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 (ctl_t *ctl, clim_t *clim)
 Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data. More...
 
double clim_photo (double rate[CP][CSZA][CO3], clim_photo_t *photo, double p, double sza, 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 (char *varname, float *array, size_t nxy, size_t nz, 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, 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, double t, met_t **met0, met_t **met1)
 Retrieves meteorological data for the specified time. More...
 
void get_met_help (ctl_t *ctl, double t, int direct, char *metbase, double dt_met, char *filename)
 Helper function to generate the filename for meteorological data. More...
 
void get_met_replace (char *orig, char *search, char *repl)
 Replaces occurrences of a substring in a string with another substring. More...
 
void get_tropo (int met_tropo, ctl_t *ctl, clim_t *clim, met_t *met, double *lons, int nx, double *lats, 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 (met_t *met0, float heights0[EX][EY][EP], float array0[EX][EY][EP], met_t *met1, float heights1[EX][EY][EP], float array1[EX][EY][EP], double ts, double height, double lon, double lat, double *var, int *ci, double *cw, int init)
 Interpolates meteorological variables to a given position and time. More...
 
void intpol_met_space_3d (met_t *met, float array[EX][EY][EP], double p, double lon, double lat, double *var, int *ci, double *cw, int init)
 Interpolates meteorological variables in 3D space. More...
 
void intpol_met_space_3d_ml (met_t *met, float array[EX][EY][EP], double p, double lon, double lat, double *var)
 Interpolates a meteorological variable in 3D space (longitude, latitude, pressure). More...
 
void intpol_met_space_2d (met_t *met, float array[EX][EY], double lon, double lat, double *var, int *ci, double *cw, int init)
 Interpolates meteorological variables in 2D space. More...
 
void intpol_met_time_3d (met_t *met0, float array0[EX][EY][EP], met_t *met1, float array1[EX][EY][EP], double ts, double p, double lon, double lat, double *var, int *ci, double *cw, int init)
 Interpolates meteorological data in 3D space and time. More...
 
void intpol_met_time_3d_ml (met_t *met0, float array0[EX][EY][EP], met_t *met1, float array1[EX][EY][EP], double ts, double p, double lon, double lat, double *var)
 Interpolates a meteorological variable in time and 3D space (longitude, latitude, pressure). More...
 
void intpol_met_time_2d (met_t *met0, float array0[EX][EY], met_t *met1, float array1[EX][EY], double ts, double lon, double lat, double *var, int *ci, double *cw, int init)
 Interpolates meteorological data in 2D space and time. More...
 
void intpol_tropo_3d (double time0, float array0[EX][EY], double time1, float array1[EX][EY], double lons[EX], double lats[EY], int nlon, int nlat, double time, double lon, double lat, 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_irr_3d (float profiles[EX][EY][EP], int np, int ind_lon, int ind_lat, double x)
 Locate the index of the interval containing a given value in a 3D irregular grid. 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], int np, int lon_ap_ind, int lat_ap_ind, double height_ap, int *ind)
 Locate the four vertical indizes of a box for a given height value. More...
 
void module_advect (ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double *dt)
 Performs the advection of atmospheric particles using meteorological data. More...
 
void module_advect_init (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 (ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, double *dt)
 Apply boundary conditions to particles based on meteorological and climatological data. More...
 
void module_chemgrid (ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double tt)
 Calculate grid data for chemistry modules. More...
 
void module_chem_init (ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
 Initializes the chemistry modules by setting atmospheric composition. More...
 
void module_convection (ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double *dt, double *rs)
 Simulate convective processes for atmospheric particles. More...
 
void module_decay (ctl_t *ctl, clim_t *clim, atm_t *atm, double *dt)
 Simulate exponential decay processes for atmospheric particles. More...
 
void module_diffusion_meso (ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, cache_t *cache, double *dt, double *rs)
 Simulate mesoscale diffusion for atmospheric particles. More...
 
void module_diffusion_turb (ctl_t *ctl, clim_t *clim, atm_t *atm, double *dt, double *rs)
 Simulate turbulent diffusion for atmospheric particles. More...
 
void module_dry_deposition (ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double *dt)
 Simulate dry deposition of atmospheric particles. More...
 
void module_h2o2_chem (ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, double *dt)
 Perform chemical reactions involving H2O2 within cloud particles. More...
 
void module_isosurf_init (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 (ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, cache_t *cache, double *dt)
 Apply the isosurface module to adjust atmospheric properties. More...
 
void module_meteo (ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, double *dt)
 Update atmospheric properties using meteorological data. More...
 
void module_mixing (ctl_t *ctl, clim_t *clim, atm_t *atm, double t)
 Update atmospheric properties through interparcel mixing. More...
 
void module_mixing_help (ctl_t *ctl, clim_t *clim, atm_t *atm, const int *ixs, const int *iys, const int *izs, int qnt_idx)
 Perform interparcel mixing for a specific quantity. More...
 
void module_oh_chem (ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, double *dt)
 Perform hydroxyl chemistry calculations for atmospheric particles. More...
 
void module_position (ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double *dt)
 Update the positions and pressure levels of atmospheric particles. More...
 
void module_rng_init (int ntask)
 Initialize random number generators for parallel tasks. More...
 
void module_rng (ctl_t *ctl, double *rs, size_t n, int method)
 Generate random numbers using various methods and distributions. More...
 
void module_sedi (ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double *dt)
 Simulate sedimentation of particles in the atmosphere. More...
 
void module_sort (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 (ctl_t *ctl, met_t *met0, atm_t *atm, double *dt, double t)
 Calculate time steps for air parcels based on specified conditions. More...
 
void module_timesteps_init (ctl_t *ctl, atm_t *atm)
 Initialize start time and time interval for time-stepping. More...
 
void module_tracer_chem (ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, double *dt)
 Simulate chemical reactions involving long-lived atmospheric tracers. More...
 
void module_wet_deposition (ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, 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, 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, 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, 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, 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, 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 (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...
 
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, 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 and populates the provided structures. More...
 
void read_met_bin_2d (FILE *in, met_t *met, float var[EX][EY], 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, ctl_t *ctl, met_t *met, float var[EX][EY][EP], char *varname, float bound_min, float bound_max)
 Reads 3D meteorological data from a binary file, potentially using different compression methods. More...
 
void read_met_cape (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 (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 (ctl_t *ctl, met_t *met)
 Calculates geopotential heights from meteorological data. More...
 
void read_met_grid (const char *filename, int ncid, ctl_t *ctl, met_t *met)
 Reads meteorological grid information from a NetCDF file. More...
 
void read_met_levels (int ncid, ctl_t *ctl, met_t *met)
 Reads meteorological variables at different vertical levels from a NetCDF file. More...
 
void read_met_ml2pl (ctl_t *ctl, met_t *met, float var[EX][EY][EP], 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_2d (int ncid, char *varname, char *varname2, char *varname3, char *varname4, ctl_t *ctl, met_t *met, float dest[EX][EY], float scl, int init)
 Reads a 2-dimensional meteorological variable from a NetCDF file. More...
 
int read_met_nc_3d (int ncid, char *varname, char *varname2, char *varname3, char *varname4, ctl_t *ctl, met_t *met, float dest[EX][EY][EP], float scl)
 Reads a 3-dimensional meteorological variable from a NetCDF file. More...
 
void read_met_pbl (met_t *met)
 Calculates the planetary boundary layer (PBL) height for each grid point. 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 (ctl_t *ctl, met_t *met)
 Downsamples meteorological data based on specified parameters. More...
 
void read_met_surface (int ncid, met_t *met, ctl_t *ctl)
 Reads surface meteorological data from a netCDF file and stores it in the meteorological data structure. More...
 
void read_met_tropo (ctl_t *ctl, 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, 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, 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, int output)
 Measures and reports elapsed time for named and grouped timers. More...
 
double time_from_filename (const char *filename, 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, ctl_t *ctl, atm_t *atm, double t)
 Writes air parcel data to a file in various formats. More...
 
void write_atm_asc (const char *filename, ctl_t *ctl, atm_t *atm, double t)
 Writes air parcel data to an ASCII file or gnuplot. More...
 
void write_atm_bin (const char *filename, ctl_t *ctl, atm_t *atm)
 Writes air parcel data to a binary file. More...
 
void write_atm_clams (const char *filename, ctl_t *ctl, atm_t *atm)
 Writes air parcel data to a NetCDF file in the CLaMS format. More...
 
void write_atm_clams_traj (const char *dirname, ctl_t *ctl, atm_t *atm, double t)
 Writes CLaMS trajectory data to a NetCDF file. More...
 
void write_atm_nc (const char *filename, ctl_t *ctl, atm_t *atm)
 Writes air parcel data to a NetCDF file. More...
 
void write_csi (const char *filename, ctl_t *ctl, atm_t *atm, double t)
 Writes Critical Success Index (CSI) data to a file. More...
 
void write_ens (const char *filename, ctl_t *ctl, atm_t *atm, double t)
 Writes ensemble data to a file. More...
 
void write_grid (const char *filename, ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double t)
 Writes grid data to a file in ASCII or netCDF format. More...
 
void write_grid_asc (const char *filename, ctl_t *ctl, double *cd, double *mean[NQ], double *sigma[NQ], double *vmr_impl, double t, double *z, double *lon, double *lat, double *area, double dz, int *np)
 Writes grid data to an ASCII file. More...
 
void write_grid_nc (const char *filename, ctl_t *ctl, double *cd, double *mean[NQ], double *sigma[NQ], double *vmr_impl, double t, double *z, double *lon, double *lat, double *area, double dz, int *np)
 Writes grid data to a NetCDF file. More...
 
int write_met (const char *filename, ctl_t *ctl, met_t *met)
 Writes meteorological data to a binary file. More...
 
void write_met_bin_2d (FILE *out, met_t *met, float var[EX][EY], char *varname)
 Writes a 2-dimensional meteorological variable to a binary file. More...
 
void write_met_bin_3d (FILE *out, ctl_t *ctl, met_t *met, float var[EX][EY][EP], char *varname, int precision, double tolerance)
 Writes a 3-dimensional meteorological variable to a binary file. More...
 
void write_output (const char *dirname, ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double t)
 Writes various types of output data to files in a specified directory. More...
 
void write_prof (const char *filename, ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double t)
 Writes profile data to a specified file. More...
 
void write_sample (const char *filename, ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double t)
 Writes sample data to a specified file. More...
 
void write_station (const char *filename, ctl_t *ctl, atm_t *atm, double t)
 Writes station data to a specified file. More...
 
void write_vtk (const char *filename, ctl_t *ctl, atm_t *atm, 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 double radius = NORM(x);
81 *lat = asin(x[2] / radius) * 180. / M_PI;
82 *lon = atan2(x[1], x[0]) * 180. / M_PI;
83 *z = radius - RE;
84}
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:217
#define NORM(a)
Compute the norm (magnitude) of a vector.
Definition: mptrac.h:1198

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

94 {
95
96 /* Get OH data from climatology... */
97 double oh = clim_zm(&clim->oh, t, lat, p);
98
99 /* Apply diurnal correction... */
100 if (ctl->oh_chem_beta > 0) {
101 double sza = sza_calc(t, lon, lat);
102 if (sza <= M_PI / 2. * 85. / 90.)
103 return oh * exp(-ctl->oh_chem_beta / cos(sza));
104 else
105 return oh * exp(-ctl->oh_chem_beta / cos(M_PI / 2. * 85. / 90.));
106 } else
107 return oh;
108}
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:394
double sza_calc(const double sec, const double lon, const double lat)
Calculates the solar zenith angle.
Definition: mptrac.c:8118
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3254
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2790
Here is the call graph for this function:

◆ clim_oh_diurnal_correction()

void clim_oh_diurnal_correction ( 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 112 of file mptrac.c.

114 {
115
116 /* Loop over climatology data points... */
117 for (int it = 0; it < clim->oh.ntime; it++)
118 for (int iz = 0; iz < clim->oh.np; iz++)
119 for (int iy = 0; iy < clim->oh.nlat; iy++) {
120
121 /* Init... */
122 int n = 0;
123 double sum = 0;
124
125 /* Integrate day/night correction factor over longitude... */
126 for (double lon = -180; lon < 180; lon += 1.0) {
127 double sza = sza_calc(clim->oh.time[it], lon, clim->oh.lat[iy]);
128 if (sza <= M_PI / 2. * 85. / 90.)
129 sum += exp(-ctl->oh_chem_beta / cos(sza));
130 else
131 sum += exp(-ctl->oh_chem_beta / cos(M_PI / 2. * 85. / 90.));
132 n++;
133 }
134
135 /* Apply scaling factor to OH data... */
136 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
137 }
138}
double time[CT]
Time [s].
Definition: mptrac.h:3210
int np
Number of pressure levels.
Definition: mptrac.h:3207
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3219
int ntime
Number of timesteps.
Definition: mptrac.h:3201
int nlat
Number of latitudes.
Definition: mptrac.h:3204
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3213
Here is the call graph for this function:

◆ clim_photo()

double clim_photo ( double  rate[CP][CSZA][CO3],
clim_photo_t photo,
double  p,
double  sza,
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 142 of file mptrac.c.

147 {
148
149 /* Check pressure range... */
150 double p_help = p;
151 if (p < photo->p[photo->np - 1])
152 p_help = photo->p[photo->np - 1];
153 else if (p > photo->p[0])
154 p_help = photo->p[0];
155
156 /* Check sza range... */
157 double sza_help = sza;
158 if (sza < photo->sza[0])
159 sza_help = photo->sza[0];
160 else if (sza > photo->sza[photo->nsza - 1])
161 sza_help = photo->sza[photo->nsza - 1];
162
163 /* Check ozone column range... */
164 double o3c_help = o3c;
165 if (o3c < photo->o3c[0])
166 o3c_help = photo->o3c[0];
167 else if (o3c > photo->o3c[photo->no3c - 1])
168 o3c_help = photo->o3c[photo->no3c - 1];
169
170 /* Get indices... */
171 int ip = locate_irr(photo->p, photo->np, p_help);
172 int isza = locate_reg(photo->sza, photo->nsza, sza_help);
173 int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
174
175 /* Interpolate photolysis rate... */
176 double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
177 photo->p[ip + 1], rate[ip + 1][isza][io3c], p_help);
178 double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
179 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1], p_help);
180 double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
181 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c], p_help);
182 double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
183 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
184 p_help);
185 aux00 = LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
186 aux11 = LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
187 aux00 = LIN(photo->sza[isza], aux00, photo->sza[isza + 1], aux11, sza_help);
188 return MAX(aux00, 0.0);
189}
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:2153
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:2055
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:827
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:854
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3128
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3137
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3134
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3140
int np
Number of pressure levels.
Definition: mptrac.h:3125
int no3c
Number of total ozone columns.
Definition: mptrac.h:3131
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 193 of file mptrac.c.

196 {
197
198 /* Get seconds since begin of year... */
199 double sec = FMOD(t, 365.25 * 86400.);
200 while (sec < 0)
201 sec += 365.25 * 86400.;
202
203 /* Get indices... */
204 int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
205 int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
206
207 /* Interpolate tropopause pressure... */
208 double p0 = LIN(clim->tropo_lat[ilat],
209 clim->tropo[isec][ilat],
210 clim->tropo_lat[ilat + 1],
211 clim->tropo[isec][ilat + 1], lat);
212 double p1 = LIN(clim->tropo_lat[ilat],
213 clim->tropo[isec + 1][ilat],
214 clim->tropo_lat[ilat + 1],
215 clim->tropo[isec + 1][ilat + 1], lat);
216 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
217}
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:603
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3233
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3242
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3236
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3245
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3239
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 221 of file mptrac.c.

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

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

378 {
379
380 /* Interpolate... */
381 if (t <= ts->time[0])
382 return ts->vmr[0];
383 else if (t >= ts->time[ts->ntime - 1])
384 return ts->vmr[ts->ntime - 1];
385 else {
386 int idx = locate_irr(ts->time, ts->ntime, t);
387 return LIN(ts->time[idx], ts->vmr[idx],
388 ts->time[idx + 1], ts->vmr[idx + 1], t);
389 }
390}
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3187
double time[CTS]
Time [s].
Definition: mptrac.h:3184
int ntime
Number of timesteps.
Definition: mptrac.h:3181
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 394 of file mptrac.c.

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

◆ compress_pck()

void compress_pck ( char *  varname,
float *  array,
size_t  nxy,
size_t  nz,
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 611 of file mptrac.c.

617 {
618
619 double min[EP], max[EP], off[EP], scl[EP];
620
621 unsigned short *sarray;
622
623 /* Allocate... */
624 ALLOC(sarray, unsigned short,
625 nxy * nz);
626
627 /* Read compressed stream and decompress array... */
628 if (decompress) {
629
630 /* Write info... */
631 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
632 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
633
634 /* Read data... */
635 FREAD(&scl, double,
636 nz,
637 inout);
638 FREAD(&off, double,
639 nz,
640 inout);
641 FREAD(sarray, unsigned short,
642 nxy * nz,
643 inout);
644
645 /* Convert to float... */
646#pragma omp parallel for default(shared)
647 for (size_t ixy = 0; ixy < nxy; ixy++)
648 for (size_t iz = 0; iz < nz; iz++)
649 array[ixy * nz + iz]
650 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
651 }
652
653 /* Compress array and output compressed stream... */
654 else {
655
656 /* Write info... */
657 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
658 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
659
660 /* Get range... */
661 for (size_t iz = 0; iz < nz; iz++) {
662 min[iz] = array[iz];
663 max[iz] = array[iz];
664 }
665 for (size_t ixy = 1; ixy < nxy; ixy++)
666 for (size_t iz = 0; iz < nz; iz++) {
667 if (array[ixy * nz + iz] < min[iz])
668 min[iz] = array[ixy * nz + iz];
669 if (array[ixy * nz + iz] > max[iz])
670 max[iz] = array[ixy * nz + iz];
671 }
672
673 /* Get offset and scaling factor... */
674 for (size_t iz = 0; iz < nz; iz++) {
675 scl[iz] = (max[iz] - min[iz]) / 65533.;
676 off[iz] = min[iz];
677 }
678
679 /* Convert to short... */
680#pragma omp parallel for default(shared)
681 for (size_t ixy = 0; ixy < nxy; ixy++)
682 for (size_t iz = 0; iz < nz; iz++)
683 if (scl[iz] != 0)
684 sarray[ixy * nz + iz] = (unsigned short)
685 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
686 else
687 sarray[ixy * nz + iz] = 0;
688
689 /* Write data... */
690 FWRITE(&scl, double,
691 nz,
692 inout);
693 FWRITE(&off, double,
694 nz,
695 inout);
696 FWRITE(sarray, unsigned short,
697 nxy * nz,
698 inout);
699 }
700
701 /* Free... */
702 free(sarray);
703}
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:641
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:621
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:344
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:256

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

856 {
857
858 const int
859 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
860 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
861
862 /* Get day of year... */
863 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
864 *doy = d0l[mon - 1] + day - 1;
865 else
866 *doy = d0[mon - 1] + day - 1;
867}

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

875 {
876
877 const int
878 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
879 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
880
881 int i;
882
883 /* Get month and day... */
884 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
885 for (i = 11; i > 0; i--)
886 if (d0l[i] <= doy)
887 break;
888 *mon = i + 1;
889 *day = doy - d0l[i] + 1;
890 } else {
891 for (i = 11; i > 0; i--)
892 if (d0[i] <= doy)
893 break;
894 *mon = i + 1;
895 *day = doy - d0[i] + 1;
896 }
897}

◆ fft_help()

void fft_help ( double *  fcReal,
double *  fcImag,
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 901 of file mptrac.c.

904 {
905
906 gsl_fft_complex_wavetable *wavetable;
907 gsl_fft_complex_workspace *workspace;
908
909 double data[2 * EX];
910
911 /* Check size... */
912 if (n > EX)
913 ERRMSG("Too many data points!");
914
915 /* Allocate... */
916 wavetable = gsl_fft_complex_wavetable_alloc((size_t) n);
917 workspace = gsl_fft_complex_workspace_alloc((size_t) n);
918
919 /* Set data (real, complex)... */
920 for (int i = 0; i < n; i++) {
921 data[2 * i] = fcReal[i];
922 data[2 * i + 1] = fcImag[i];
923 }
924
925 /* Calculate FFT... */
926 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
927
928 /* Copy data... */
929 for (int i = 0; i < n; i++) {
930 fcReal[i] = data[2 * i];
931 fcImag[i] = data[2 * i + 1];
932 }
933
934 /* Free... */
935 gsl_fft_complex_wavetable_free(wavetable);
936 gsl_fft_complex_workspace_free(workspace);
937}
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:1881
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:261

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

945 {
946
947 double radius = z + RE;
948 x[0] = radius * cos(lat / 180. * M_PI) * cos(lon / 180. * M_PI);
949 x[1] = radius * cos(lat / 180. * M_PI) * sin(lon / 180. * M_PI);
950 x[2] = radius * sin(lat / 180. * M_PI);
951}

◆ get_met()

void get_met ( ctl_t ctl,
clim_t clim,
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 955 of file mptrac.c.

960 {
961
962 static int init;
963
964 met_t *mets;
965
966 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
967
968 /* Set timer... */
969 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
970
971 /* Init... */
972 if (t == ctl->t_start || !init) {
973 init = 1;
974
975 /* Read meteo data... */
976 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
977 ctl->metbase, ctl->dt_met, filename);
978 if (!read_met(filename, ctl, clim, *met0))
979 ERRMSG("Cannot open file!");
980
981 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
982 ctl->metbase, ctl->dt_met, filename);
983 if (!read_met(filename, ctl, clim, *met1))
984 ERRMSG("Cannot open file!");
985
986 /* Update GPU... */
987#ifdef _OPENACC
988 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
989 met_t *met0up = *met0;
990 met_t *met1up = *met1;
991#ifdef ASYNCIO
992#pragma acc update device(met0up[:1],met1up[:1]) async(5)
993#else
994#pragma acc update device(met0up[:1],met1up[:1])
995#endif
996 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
997#endif
998
999 /* Caching... */
1000 if (ctl->met_cache && t != ctl->t_stop) {
1001 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
1002 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
1003 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1004 LOG(1, "Caching: %s", cachefile);
1005 if (system(cmd) != 0)
1006 WARN("Caching command failed!");
1007 }
1008 }
1009
1010 /* Read new data for forward trajectories... */
1011 if (t > (*met1)->time) {
1012
1013 /* Pointer swap... */
1014 mets = *met1;
1015 *met1 = *met0;
1016 *met0 = mets;
1017
1018 /* Read new meteo data... */
1019 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
1020 if (!read_met(filename, ctl, clim, *met1))
1021 ERRMSG("Cannot open file!");
1022
1023 /* Update GPU... */
1024#ifdef _OPENACC
1025 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
1026 met_t *met1up = *met1;
1027#ifdef ASYNCIO
1028#pragma acc update device(met1up[:1]) async(5)
1029#else
1030#pragma acc update device(met1up[:1])
1031#endif
1032 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1033#endif
1034
1035 /* Caching... */
1036 if (ctl->met_cache && t != ctl->t_stop) {
1037 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
1038 cachefile);
1039 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1040 LOG(1, "Caching: %s", cachefile);
1041 if (system(cmd) != 0)
1042 WARN("Caching command failed!");
1043 }
1044 }
1045
1046 /* Read new data for backward trajectories... */
1047 if (t < (*met0)->time) {
1048
1049 /* Pointer swap... */
1050 mets = *met1;
1051 *met1 = *met0;
1052 *met0 = mets;
1053
1054 /* Read new meteo data... */
1055 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
1056 if (!read_met(filename, ctl, clim, *met0))
1057 ERRMSG("Cannot open file!");
1058
1059 /* Update GPU... */
1060#ifdef _OPENACC
1061 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
1062 met_t *met0up = *met0;
1063#ifdef ASYNCIO
1064#pragma acc update device(met0up[:1]) async(5)
1065#else
1066#pragma acc update device(met0up[:1])
1067#endif
1068 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1069#endif
1070
1071 /* Caching... */
1072 if (ctl->met_cache && t != ctl->t_stop) {
1073 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
1074 cachefile);
1075 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1076 LOG(1, "Caching: %s", cachefile);
1077 if (system(cmd) != 0)
1078 WARN("Caching command failed!");
1079 }
1080 }
1081
1082 /* Check that grids are consistent... */
1083 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
1084 if ((*met0)->nx != (*met1)->nx
1085 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
1086 ERRMSG("Meteo grid dimensions do not match!");
1087 for (int ix = 0; ix < (*met0)->nx; ix++)
1088 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
1089 ERRMSG("Meteo grid longitudes do not match!");
1090 for (int iy = 0; iy < (*met0)->ny; iy++)
1091 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
1092 ERRMSG("Meteo grid latitudes do not match!");
1093 for (int ip = 0; ip < (*met0)->np; ip++)
1094 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
1095 ERRMSG("Meteo grid pressure levels do not match!");
1096 }
1097}
int read_met(const char *filename, ctl_t *ctl, clim_t *clim, met_t *met)
Reads meteorological data from a file and populates the provided structures.
Definition: mptrac.c:5611
void get_met_help(ctl_t *ctl, double t, int direct, char *metbase, double dt_met, char *filename)
Helper function to generate the filename for meteorological data.
Definition: mptrac.c:1101
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:236
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:1848
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:1961
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2439
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2458
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2445
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2575
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2455
double t_start
Start time of simulation [s].
Definition: mptrac.h:2442
Meteo data structure.
Definition: mptrac.h:3289
Here is the call graph for this function:

◆ get_met_help()

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

Helper function to generate the filename for meteorological data.

This function generates the appropriate filename for the meteorological data file based on the provided time t, direction direct, and the base filename metbase. The filename is formatted according to the specified meteorological data type.

Parameters
ctlPointer to the control structure containing configuration settings.
tThe time for which the meteorological data filename is to be generated.
directThe direction of time integration (-1 for backward, 1 for forward).
metbaseThe base string for the meteorological data filenames.
dt_metThe time interval between meteorological data files.
filenameThe generated filename for the meteorological data file.

The function performs the following steps:

  • Rounds the time to fixed intervals dt_met based on the direction.
  • Decodes the time into year, month, day, hour, minute, and second.
  • Constructs the filename based on the meteorological data type specified in ctl.
  • Replaces placeholders (YYYY, MM, DD, HH) in the base filename with actual date and time values.
Note
Ensure that ctl and filename are properly initialized before calling this function.
See also
jsec2time
get_met_replace
Author
Lars Hoffmann

Definition at line 1101 of file mptrac.c.

1107 {
1108
1109 char repl[LEN];
1110
1111 double t6, r;
1112
1113 int year, mon, day, hour, min, sec;
1114
1115 /* Round time to fixed intervals... */
1116 if (direct == -1)
1117 t6 = floor(t / dt_met) * dt_met;
1118 else
1119 t6 = ceil(t / dt_met) * dt_met;
1120
1121 /* Decode time... */
1122 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1123
1124 /* Set filename of MPTRAC meteo files... */
1125 if (ctl->met_clams == 0) {
1126 if (ctl->met_type == 0)
1127 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1128 else if (ctl->met_type == 1)
1129 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1130 else if (ctl->met_type == 2)
1131 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1132 else if (ctl->met_type == 3)
1133 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1134 else if (ctl->met_type == 4)
1135 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1136 else if (ctl->met_type == 5)
1137 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1138 sprintf(repl, "%d", year);
1139 get_met_replace(filename, "YYYY", repl);
1140 sprintf(repl, "%02d", mon);
1141 get_met_replace(filename, "MM", repl);
1142 sprintf(repl, "%02d", day);
1143 get_met_replace(filename, "DD", repl);
1144 sprintf(repl, "%02d", hour);
1145 get_met_replace(filename, "HH", repl);
1146 }
1147
1148 /* Set filename of CLaMS meteo files... */
1149 else {
1150 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1151 sprintf(repl, "%d", year);
1152 get_met_replace(filename, "YYYY", repl);
1153 sprintf(repl, "%02d", year % 100);
1154 get_met_replace(filename, "YY", repl);
1155 sprintf(repl, "%02d", mon);
1156 get_met_replace(filename, "MM", repl);
1157 sprintf(repl, "%02d", day);
1158 get_met_replace(filename, "DD", repl);
1159 sprintf(repl, "%02d", hour);
1160 get_met_replace(filename, "HH", repl);
1161 }
1162}
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:1166
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:1771
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2153
int met_type
Type of meteo data files (0=netCDF, 1=binary, 2=pck, 3=zfp, 4=zstd, 5=cms).
Definition: mptrac.h:2465
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 1166 of file mptrac.c.

1169 {
1170
1171 char buffer[LEN];
1172
1173 /* Iterate... */
1174 for (int i = 0; i < 3; i++) {
1175
1176 /* Replace sub-string... */
1177 char *ch;
1178 if (!(ch = strstr(orig, search)))
1179 return;
1180 strncpy(buffer, orig, (size_t) (ch - orig));
1181 buffer[ch - orig] = 0;
1182 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1183 orig[0] = 0;
1184 strcpy(orig, buffer);
1185 }
1186}

◆ get_tropo()

void get_tropo ( int  met_tropo,
ctl_t ctl,
clim_t clim,
met_t met,
double *  lons,
int  nx,
double *  lats,
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 1190 of file mptrac.c.

1205 {
1206
1208
1209 ctl->met_tropo = met_tropo;
1210 read_met_tropo(ctl, clim, met);
1211#pragma omp parallel for default(shared) private(ci,cw)
1212 for (int ix = 0; ix < nx; ix++)
1213 for (int iy = 0; iy < ny; iy++) {
1214 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1215 &pt[iy * nx + ix], ci, cw, 1);
1216 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1217 &ps[iy * nx + ix], ci, cw, 0);
1218 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1219 &zs[iy * nx + ix], ci, cw, 0);
1220 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1221 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1222 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1223 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1224 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1225 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1226 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1227 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1228 }
1229}
void read_met_tropo(ctl_t *ctl, clim_t *clim, met_t *met)
Calculates the tropopause and related meteorological variables based on various methods and stores th...
Definition: mptrac.c:7670
void intpol_met_space_3d(met_t *met, float array[EX][EY][EP], double p, double lon, double lat, double *var, int *ci, double *cw, int init)
Interpolates meteorological variables in 3D space.
Definition: mptrac.c:1409
void intpol_met_space_2d(met_t *met, float array[EX][EY], double lon, double lat, double *var, int *ci, double *cw, int init)
Interpolates meteorological variables in 2D space.
Definition: mptrac.c:1536
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:656
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2560
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3400
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3319
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3325
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3403
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3385
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3343
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3382
Here is the call graph for this function:

◆ intpol_met_4d_coord()

void intpol_met_4d_coord ( met_t met0,
float  height0[EX][EY][EP],
float  array0[EX][EY][EP],
met_t met1,
float  height1[EX][EY][EP],
float  array1[EX][EY][EP],
double  ts,
double  height,
double  lon,
double  lat,
double *  var,
int *  ci,
double *  cw,
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 1233 of file mptrac.c.

1247 {
1248
1249 if (init) {
1250
1251 /* Restrict positions to coordinate range... */
1252 lon = FMOD(lon, 360.);
1253 if (met0->lon[met0->nx - 1] > 180 && lon < 0)
1254 lon += 360;
1255
1256 /* Get horizontal indizes... */
1257 ci[0] = locate_irr(met0->lon, met0->nx, lon);
1258 ci[1] = locate_irr(met0->lat, met0->ny, lat);
1259
1260 /* Locate the vertical indizes for each edge of the column... */
1261 int ind[2][4];
1262 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1263 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1264
1265 /* Find minimum and maximum indizes... */
1266 ci[2] = ind[0][0];
1267 int k_max = ind[0][0];
1268 for (int i = 0; i < 2; i++)
1269 for (int j = 0; j < 4; j++) {
1270 if (ci[2] > ind[i][j])
1271 ci[2] = ind[i][j];
1272 if (k_max < ind[i][j])
1273 k_max = ind[i][j];
1274 }
1275
1276 /* Get weighting factors for time, longitude and latitude... */
1277 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1278 cw[0] = (lon - met0->lon[ci[0]]) /
1279 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1280 cw[1] = (lat - met0->lat[ci[1]]) /
1281 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1282
1283 /* Start determiniation of the altitude weighting factor... */
1284 double height_top, height_bot;
1285 double height00, height01, height10, height11, height0, height1;
1286
1287 /* Interpolate in time at the lowest level... */
1288 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1289 - heights0[ci[0]][ci[1]][ci[2]])
1290 + heights0[ci[0]][ci[1]][ci[2]];
1291 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1292 - heights0[ci[0]][ci[1] + 1][ci[2]])
1293 + heights0[ci[0]][ci[1] + 1][ci[2]];
1294 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1295 - heights0[ci[0] + 1][ci[1]][ci[2]])
1296 + heights0[ci[0] + 1][ci[1]][ci[2]];
1297 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1298 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1299 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1300
1301 /* Interpolate in latitude direction... */
1302 height0 = cw[1] * (height01 - height00) + height00;
1303 height1 = cw[1] * (height11 - height10) + height10;
1304
1305 /* Interpolate in longitude direction... */
1306 height_bot = cw[0] * (height1 - height0) + height0;
1307
1308 /* Interpolate in time at the upper level... */
1309 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1310 - heights0[ci[0]][ci[1]][ci[2] + 1])
1311 + heights0[ci[0]][ci[1]][ci[2] + 1];
1312 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1313 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1314 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1315 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1316 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1317 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1318 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1319 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1320 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1321
1322 /* Interpolate in latitude direction... */
1323 height0 = cw[1] * (height01 - height00) + height00;
1324 height1 = cw[1] * (height11 - height10) + height10;
1325
1326 /* Interpolate in longitude direction... */
1327 height_top = cw[0] * (height1 - height0) + height0;
1328
1329 /* Search at higher levels if height is not in box... */
1330 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1331 ((height_bot <= height) || (height_top > height))
1332 && (height_bot >= height) && (ci[2] < k_max))
1333 ||
1334 ((heights0[0][0][0] < heights0[0][0][1]) &&
1335 ((height_bot >= height) || (height_top < height))
1336 && (height_bot <= height) && (ci[2] < k_max))
1337 ) {
1338
1339 ci[2]++;
1340 height_bot = height_top;
1341
1342 /* Interpolate in time at the next level... */
1343 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1344 - heights0[ci[0]][ci[1]][ci[2] + 1])
1345 + heights0[ci[0]][ci[1]][ci[2] + 1];
1346 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1347 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1348 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1349 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1350 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1351 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1352 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1353 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1354 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1355
1356 /* Interpolate in latitude direction... */
1357 height0 = cw[1] * (height01 - height00) + height00;
1358 height1 = cw[1] * (height11 - height10) + height10;
1359
1360 /* Interpolate in longitude direction... */
1361 height_top = cw[0] * (height1 - height0) + height0;
1362 }
1363
1364 /* Get vertical weighting factors... */
1365 cw[2] = (height - height_bot)
1366 / (height_top - height_bot);
1367 }
1368
1369 /* Calculate the needed array values... */
1370 double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1371 - array0[ci[0]][ci[1]][ci[2]])
1372 + array0[ci[0]][ci[1]][ci[2]];
1373 double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1374 - array0[ci[0] + 1][ci[1]][ci[2]])
1375 + array0[ci[0] + 1][ci[1]][ci[2]];
1376 double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1377 - array0[ci[0]][ci[1] + 1][ci[2]])
1378 + array0[ci[0]][ci[1] + 1][ci[2]];
1379 double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1380 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1381 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1382 double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1383 - array0[ci[0]][ci[1]][ci[2] + 1])
1384 + array0[ci[0]][ci[1]][ci[2] + 1];
1385 double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
1386 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
1387 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
1388 double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
1389 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
1390 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
1391 double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1392 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1393 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1394
1395 double array00 = cw[0] * (array100 - array000) + array000;
1396 double array10 = cw[0] * (array110 - array010) + array010;
1397 double array01 = cw[0] * (array101 - array001) + array001;
1398 double array11 = cw[0] * (array111 - array011) + array011;
1399
1400 double aux0 = cw[1] * (array10 - array00) + array00;
1401 double aux1 = cw[1] * (array11 - array01) + array01;
1402
1403 /* Interpolate vertically... */
1404 *var = cw[2] * (aux1 - aux0) + aux0;
1405}
void locate_vert(float profiles[EX][EY][EP], int np, int lon_ap_ind, int lat_ap_ind, double height_ap, int *ind)
Locate the four vertical indizes of a box for a given height value.
Definition: mptrac.c:2172
int nx
Number of longitudes.
Definition: mptrac.h:3295
int ny
Number of latitudes.
Definition: mptrac.h:3298
double lon[EX]
Longitude [deg].
Definition: mptrac.h:3307
int npl
Number of model levels.
Definition: mptrac.h:3304
double time
Time [s].
Definition: mptrac.h:3292
double lat[EY]
Latitude [deg].
Definition: mptrac.h:3310
Here is the call graph for this function:

◆ intpol_met_space_3d()

void intpol_met_space_3d ( met_t met,
float  array[EX][EY][EP],
double  p,
double  lon,
double  lat,
double *  var,
int *  ci,
double *  cw,
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 1409 of file mptrac.c.

1418 {
1419
1420 /* Initialize interpolation... */
1421 if (init) {
1422
1423 /* Check longitude... */
1424 if (met->lon[met->nx - 1] > 180 && lon < 0)
1425 lon += 360;
1426
1427 /* Get interpolation indices... */
1428 ci[0] = locate_irr(met->p, met->np, p);
1429 ci[1] = locate_reg(met->lon, met->nx, lon);
1430 ci[2] = locate_reg(met->lat, met->ny, lat);
1431
1432 /* Get interpolation weights... */
1433 cw[0] = (met->p[ci[0] + 1] - p)
1434 / (met->p[ci[0] + 1] - met->p[ci[0]]);
1435 cw[1] = (met->lon[ci[1] + 1] - lon)
1436 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1437 cw[2] = (met->lat[ci[2] + 1] - lat)
1438 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1439 }
1440
1441 /* Interpolate vertically... */
1442 double aux00 =
1443 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
1444 + array[ci[1]][ci[2]][ci[0] + 1];
1445 double aux01 =
1446 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
1447 array[ci[1]][ci[2] + 1][ci[0] + 1])
1448 + array[ci[1]][ci[2] + 1][ci[0] + 1];
1449 double aux10 =
1450 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
1451 array[ci[1] + 1][ci[2]][ci[0] + 1])
1452 + array[ci[1] + 1][ci[2]][ci[0] + 1];
1453 double aux11 =
1454 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
1455 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
1456 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
1457
1458 /* Interpolate horizontally... */
1459 aux00 = cw[2] * (aux00 - aux01) + aux01;
1460 aux11 = cw[2] * (aux10 - aux11) + aux11;
1461 *var = cw[1] * (aux00 - aux11) + aux11;
1462}
int np
Number of pressure levels.
Definition: mptrac.h:3301
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3313
Here is the call graph for this function:

◆ intpol_met_space_3d_ml()

void intpol_met_space_3d_ml ( met_t met,
float  array[EX][EY][EP],
double  p,
double  lon,
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 1466 of file mptrac.c.

1472 {
1473
1474 /* Check longitude... */
1475 if (met->lon[met->nx - 1] > 180 && lon < 0)
1476 lon += 360;
1477
1478 /* Get horizontal indices... */
1479 int ix = locate_reg(met->lon, met->nx, lon);
1480 int iy = locate_reg(met->lat, met->ny, lat);
1481
1482 /* Interpolate vertically... */
1483 int iz = locate_irr_float(met->pl[ix][iy], met->npl, p, 0);
1484 double aux00;
1485 if (p >= met->pl[ix][iy][iz + 1])
1486 aux00 = array[ix][iy][iz + 1];
1487 else if (p <= met->pl[ix][iy][iz])
1488 aux00 = array[ix][iy][iz];
1489 else
1490 aux00 = LIN(met->pl[ix][iy][iz],
1491 array[ix][iy][iz],
1492 met->pl[ix][iy][iz + 1], array[ix][iy][iz + 1], p);
1493
1494 iz = locate_irr_float(met->pl[ix][iy + 1], met->npl, p, iz);
1495 double aux01;
1496 if (p >= met->pl[ix][iy + 1][iz + 1])
1497 aux01 = array[ix][iy + 1][iz + 1];
1498 else if (p <= met->pl[ix][iy + 1][iz])
1499 aux01 = array[ix][iy + 1][iz];
1500 else
1501 aux01 = LIN(met->pl[ix][iy + 1][iz],
1502 array[ix][iy + 1][iz],
1503 met->pl[ix][iy + 1][iz + 1], array[ix][iy + 1][iz + 1], p);
1504
1505 iz = locate_irr_float(met->pl[ix + 1][iy], met->npl, p, iz);
1506 double aux10;
1507 if (p >= met->pl[ix + 1][iy][iz + 1])
1508 aux10 = array[ix + 1][iy][iz + 1];
1509 else if (p <= met->pl[ix + 1][iy][iz])
1510 aux10 = array[ix + 1][iy][iz];
1511 else
1512 aux10 = LIN(met->pl[ix + 1][iy][iz],
1513 array[ix + 1][iy][iz],
1514 met->pl[ix + 1][iy][iz + 1], array[ix + 1][iy][iz + 1], p);
1515
1516 iz = locate_irr_float(met->pl[ix + 1][iy + 1], met->npl, p, iz);
1517 double aux11;
1518 if (p >= met->pl[ix + 1][iy + 1][iz + 1])
1519 aux11 = array[ix + 1][iy + 1][iz + 1];
1520 else if (p <= met->pl[ix + 1][iy + 1][iz])
1521 aux11 = array[ix + 1][iy + 1][iz];
1522 else
1523 aux11 = LIN(met->pl[ix + 1][iy + 1][iz],
1524 array[ix + 1][iy + 1][iz],
1525 met->pl[ix + 1][iy + 1][iz + 1],
1526 array[ix + 1][iy + 1][iz + 1], p);
1527
1528 /* Interpolate horizontally... */
1529 double aux0 = LIN(met->lat[iy], aux00, met->lat[iy + 1], aux01, lat);
1530 double aux1 = LIN(met->lat[iy], aux10, met->lat[iy + 1], aux11, lat);
1531 *var = LIN(met->lon[ix], aux0, met->lon[ix + 1], aux1, lon);
1532}
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:2085
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3421
Here is the call graph for this function:

◆ intpol_met_space_2d()

void intpol_met_space_2d ( met_t met,
float  array[EX][EY],
double  lon,
double  lat,
double *  var,
int *  ci,
double *  cw,
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 1536 of file mptrac.c.

1544 {
1545
1546 /* Initialize interpolation... */
1547 if (init) {
1548
1549 /* Check longitude... */
1550 if (met->lon[met->nx - 1] > 180 && lon < 0)
1551 lon += 360;
1552
1553 /* Get interpolation indices... */
1554 ci[1] = locate_reg(met->lon, met->nx, lon);
1555 ci[2] = locate_reg(met->lat, met->ny, lat);
1556
1557 /* Get interpolation weights... */
1558 cw[1] = (met->lon[ci[1] + 1] - lon)
1559 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1560 cw[2] = (met->lat[ci[2] + 1] - lat)
1561 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1562 }
1563
1564 /* Set variables... */
1565 double aux00 = array[ci[1]][ci[2]];
1566 double aux01 = array[ci[1]][ci[2] + 1];
1567 double aux10 = array[ci[1] + 1][ci[2]];
1568 double aux11 = array[ci[1] + 1][ci[2] + 1];
1569
1570 /* Interpolate horizontally... */
1571 if (isfinite(aux00) && isfinite(aux01)
1572 && isfinite(aux10) && isfinite(aux11)) {
1573 aux00 = cw[2] * (aux00 - aux01) + aux01;
1574 aux11 = cw[2] * (aux10 - aux11) + aux11;
1575 *var = cw[1] * (aux00 - aux11) + aux11;
1576 } else {
1577 if (cw[2] < 0.5) {
1578 if (cw[1] < 0.5)
1579 *var = aux11;
1580 else
1581 *var = aux01;
1582 } else {
1583 if (cw[1] < 0.5)
1584 *var = aux10;
1585 else
1586 *var = aux00;
1587 }
1588 }
1589}
Here is the call graph for this function:

◆ intpol_met_time_3d()

void intpol_met_time_3d ( met_t met0,
float  array0[EX][EY][EP],
met_t met1,
float  array1[EX][EY][EP],
double  ts,
double  p,
double  lon,
double  lat,
double *  var,
int *  ci,
double *  cw,
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 1593 of file mptrac.c.

1605 {
1606
1607 double var0, var1, wt;
1608
1609 /* Spatial interpolation... */
1610 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
1611 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
1612
1613 /* Get weighting factor... */
1614 wt = (met1->time - ts) / (met1->time - met0->time);
1615
1616 /* Interpolate... */
1617 *var = wt * (var0 - var1) + var1;
1618}
Here is the call graph for this function:

◆ intpol_met_time_3d_ml()

void intpol_met_time_3d_ml ( met_t met0,
float  array0[EX][EY][EP],
met_t met1,
float  array1[EX][EY][EP],
double  ts,
double  p,
double  lon,
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 1622 of file mptrac.c.

1631 {
1632
1633 double var0, var1;
1634
1635 /* Spatial interpolation... */
1636 intpol_met_space_3d_ml(met0, array0, p, lon, lat, &var0);
1637 intpol_met_space_3d_ml(met1, array1, p, lon, lat, &var1);
1638
1639 /* Interpolate... */
1640 *var = LIN(met0->time, var0, met1->time, var1, ts);
1641}
void intpol_met_space_3d_ml(met_t *met, float array[EX][EY][EP], double p, double lon, double lat, double *var)
Interpolates a meteorological variable in 3D space (longitude, latitude, pressure).
Definition: mptrac.c:1466
Here is the call graph for this function:

◆ intpol_met_time_2d()

void intpol_met_time_2d ( met_t met0,
float  array0[EX][EY],
met_t met1,
float  array1[EX][EY],
double  ts,
double  lon,
double  lat,
double *  var,
int *  ci,
double *  cw,
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 1645 of file mptrac.c.

1656 {
1657
1658 double var0, var1, wt;
1659
1660 /* Spatial interpolation... */
1661 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
1662 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
1663
1664 /* Get weighting factor... */
1665 wt = (met1->time - ts) / (met1->time - met0->time);
1666
1667 /* Interpolate... */
1668 if (isfinite(var0) && isfinite(var1))
1669 *var = wt * (var0 - var1) + var1;
1670 else if (wt < 0.5)
1671 *var = var1;
1672 else
1673 *var = var0;
1674}
Here is the call graph for this function:

◆ intpol_tropo_3d()

void intpol_tropo_3d ( double  time0,
float  array0[EX][EY],
double  time1,
float  array1[EX][EY],
double  lons[EX],
double  lats[EY],
int  nlon,
int  nlat,
double  time,
double  lon,
double  lat,
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 1678 of file mptrac.c.

1692 {
1693
1694 double aux0, aux1, aux00, aux01, aux10, aux11, mean = 0;
1695
1696 int n = 0;
1697
1698 /* Adjust longitude... */
1699 if (lon < lons[0])
1700 lon += 360;
1701 else if (lon > lons[nlon - 1])
1702 lon -= 360;
1703
1704 /* Get indices... */
1705 int ix = locate_reg(lons, (int) nlon, lon);
1706 int iy = locate_reg(lats, (int) nlat, lat);
1707
1708 /* Calculate standard deviation... */
1709 *sigma = 0;
1710 for (int dx = 0; dx < 2; dx++)
1711 for (int dy = 0; dy < 2; dy++) {
1712 if (isfinite(array0[ix + dx][iy + dy])) {
1713 mean += array0[ix + dx][iy + dy];
1714 *sigma += SQR(array0[ix + dx][iy + dy]);
1715 n++;
1716 }
1717 if (isfinite(array1[ix + dx][iy + dy])) {
1718 mean += array1[ix + dx][iy + dy];
1719 *sigma += SQR(array1[ix + dx][iy + dy]);
1720 n++;
1721 }
1722 }
1723 if (n > 0)
1724 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
1725
1726 /* Linear interpolation... */
1727 if (method == 1 && isfinite(array0[ix][iy])
1728 && isfinite(array0[ix][iy + 1])
1729 && isfinite(array0[ix + 1][iy])
1730 && isfinite(array0[ix + 1][iy + 1])
1731 && isfinite(array1[ix][iy])
1732 && isfinite(array1[ix][iy + 1])
1733 && isfinite(array1[ix + 1][iy])
1734 && isfinite(array1[ix + 1][iy + 1])) {
1735
1736 aux00 = LIN(lons[ix], array0[ix][iy],
1737 lons[ix + 1], array0[ix + 1][iy], lon);
1738 aux01 = LIN(lons[ix], array0[ix][iy + 1],
1739 lons[ix + 1], array0[ix + 1][iy + 1], lon);
1740 aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat);
1741
1742 aux10 = LIN(lons[ix], array1[ix][iy],
1743 lons[ix + 1], array1[ix + 1][iy], lon);
1744 aux11 = LIN(lons[ix], array1[ix][iy + 1],
1745 lons[ix + 1], array1[ix + 1][iy + 1], lon);
1746 aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat);
1747
1748 *var = LIN(time0, aux0, time1, aux1, time);
1749 }
1750
1751 /* Nearest neighbor interpolation... */
1752 else {
1753 aux00 = NN(lons[ix], array0[ix][iy],
1754 lons[ix + 1], array0[ix + 1][iy], lon);
1755 aux01 = NN(lons[ix], array0[ix][iy + 1],
1756 lons[ix + 1], array0[ix + 1][iy + 1], lon);
1757 aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat);
1758
1759 aux10 = NN(lons[ix], array1[ix][iy],
1760 lons[ix + 1], array1[ix + 1][iy], lon);
1761 aux11 = NN(lons[ix], array1[ix][iy + 1],
1762 lons[ix + 1], array1[ix + 1][iy + 1], lon);
1763 aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat);
1764
1765 *var = NN(time0, aux0, time1, aux1, time);
1766 }
1767}
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1183
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1522
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 1771 of file mptrac.c.

1779 {
1780
1781 struct tm t0, *t1;
1782
1783 t0.tm_year = 100;
1784 t0.tm_mon = 0;
1785 t0.tm_mday = 1;
1786 t0.tm_hour = 0;
1787 t0.tm_min = 0;
1788 t0.tm_sec = 0;
1789
1790 time_t jsec0 = (time_t) jsec + timegm(&t0);
1791 t1 = gmtime(&jsec0);
1792
1793 *year = t1->tm_year + 1900;
1794 *mon = t1->tm_mon + 1;
1795 *day = t1->tm_mday;
1796 *hour = t1->tm_hour;
1797 *min = t1->tm_min;
1798 *sec = t1->tm_sec;
1799 *remain = jsec - floor(jsec);
1800}

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

1808 {
1809
1810 /* Check number of data points... */
1811 if (nk < 2)
1812 return 1.0;
1813
1814 /* Get altitude... */
1815 double z = Z(p);
1816
1817 /* Get weighting factor... */
1818 if (z < kz[0])
1819 return kw[0];
1820 else if (z > kz[nk - 1])
1821 return kw[nk - 1];
1822 else {
1823 int idx = locate_irr(kz, nk, z);
1824 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
1825 }
1826}
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 1830 of file mptrac.c.

1832 {
1833
1834 /*
1835 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
1836 and water vapor volume mixing ratio [1].
1837
1838 Reference: https://en.wikipedia.org/wiki/Lapse_rate
1839 */
1840
1841 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
1842
1843 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
1844}
#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:1509
#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 1848 of file mptrac.c.

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

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

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

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

2089 {
2090
2091 int ilo = 0;
2092 int ihi = n - 1;
2093 int i = (ihi + ilo) >> 1;
2094
2095 if (x >= xx[ig] && x < xx[ig + 1])
2096 return ig;
2097
2098 if (xx[i] < xx[i + 1])
2099 while (ihi > ilo + 1) {
2100 i = (ihi + ilo) >> 1;
2101 if (xx[i] > x)
2102 ihi = i;
2103 else
2104 ilo = i;
2105 } else
2106 while (ihi > ilo + 1) {
2107 i = (ihi + ilo) >> 1;
2108 if (xx[i] <= x)
2109 ihi = i;
2110 else
2111 ilo = i;
2112 }
2113
2114 return ilo;
2115}

◆ locate_irr_3d()

int locate_irr_3d ( float  profiles[EX][EY][EP],
int  np,
int  ind_lon,
int  ind_lat,
double  x 
)

Locate the index of the interval containing a given value in a 3D irregular grid.

This function locates the index of the interval containing a given value in a 3D irregular grid. It searches for the interval in the specified longitude and latitude indices of the grid.

Parameters
profiles3D array representing the irregular grid.
npSize of the profile (number of data points).
ind_lonIndex of the longitude.
ind_latIndex of the latitude.
xValue to be located.
Returns
Index of the interval containing the value x.

The function assumes that the array profiles represents a 3D irregular grid. It calculates the index of the interval where the value x is located based on the data in the specified longitude and latitude indices. If the value x is outside the range of the profile, the function returns the index of the closest interval.

Author
Jan Clemens

Definition at line 2119 of file mptrac.c.

2124 {
2125
2126 int ilo = 0;
2127 int ihi = np - 1;
2128 int i = (ihi + ilo) >> 1;
2129
2130 if (profiles[ind_lon][ind_lat][i] < profiles[ind_lon][ind_lat][i + 1])
2131 while (ihi > ilo + 1) {
2132 i = (ihi + ilo) >> 1;
2133 if (profiles[ind_lon][ind_lat][i] > x) {
2134 ihi = i;
2135 } else {
2136 ilo = i;
2137 }
2138 } else
2139 while (ihi > ilo + 1) {
2140 i = (ihi + ilo) >> 1;
2141 if (profiles[ind_lon][ind_lat][i] <= x) {
2142 ihi = i;
2143 } else {
2144 ilo = i;
2145 }
2146 }
2147
2148 return ilo;
2149}

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

2156 {
2157
2158 /* Calculate index... */
2159 int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2160
2161 /* Check range... */
2162 if (i < 0)
2163 return 0;
2164 else if (i > n - 2)
2165 return n - 2;
2166 else
2167 return i;
2168}

◆ locate_vert()

void locate_vert ( float  profiles[EX][EY][EP],
int  np,
int  lon_ap_ind,
int  lat_ap_ind,
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 2172 of file mptrac.c.

2178 {
2179
2180 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2181 np, height_ap, 0);
2182 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2183 np, height_ap, ind[0]);
2184 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2185 np, height_ap, ind[1]);
2186 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2187 np, height_ap, ind[2]);
2188}
Here is the call graph for this function:

◆ module_advect()

void module_advect ( ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
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 2192 of file mptrac.c.

2197 {
2198
2199 /* Set timer... */
2200 SELECT_TIMER("MODULE_ADVECTION", "PHYSICS", NVTX_GPU);
2201
2202 /* Pressure coordinate... */
2203 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2204
2205 /* Loop over particles... */
2206 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
2207
2208 /* Init... */
2210 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2211 x[3] = { 0, 0, 0 };
2212
2213 /* Loop over integration nodes... */
2214 for (int i = 0; i < ctl->advect; i++) {
2215
2216 /* Set position... */
2217 if (i == 0) {
2218 dts = 0.0;
2219 x[0] = atm->lon[ip];
2220 x[1] = atm->lat[ip];
2221 x[2] = atm->p[ip];
2222 } else {
2223 dts = (i == 3 ? 1.0 : 0.5) * dt[ip];
2224 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2225 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2226 x[2] = atm->p[ip] + dts * w[i - 1];
2227 }
2228 double tm = atm->time[ip] + dts;
2229
2230 /* Interpolate meteo data on pressure levels... */
2231 if (ctl->advect_vert_coord == 0) {
2232 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2233 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2234 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2235 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2236 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2237 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2238 }
2239
2240 /* Interpolate meteo data on model levels... */
2241 else {
2242 intpol_met_time_3d_ml(met0, met0->ul, met1, met1->ul, tm, x[2],
2243 x[0], x[1], &u[i]);
2244 intpol_met_time_3d_ml(met0, met0->vl, met1, met1->vl, tm, x[2],
2245 x[0], x[1], &v[i]);
2246 intpol_met_time_3d_ml(met0, met0->wl, met1, met1->wl, tm, x[2],
2247 x[0], x[1], &w[i]);
2248 }
2249
2250 /* Get mean wind... */
2251 double k = 1.0;
2252 if (ctl->advect == 2)
2253 k = (i == 0 ? 0.0 : 1.0);
2254 else if (ctl->advect == 4)
2255 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2256 um += k * u[i];
2257 vm += k * v[i];
2258 wm += k * w[i];
2259 }
2260
2261 /* Set new position... */
2262 atm->time[ip] += dt[ip];
2263 atm->lon[ip] += DX2DEG(dt[ip] * um / 1000.,
2264 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2265 atm->lat[ip] += DY2DEG(dt[ip] * vm / 1000.);
2266 atm->p[ip] += dt[ip] * wm;
2267 }
2268 }
2269
2270 /* Zeta coordinate... */
2271 else if (ctl->advect_vert_coord == 1) {
2272
2273 /* Loop over particles... */
2274 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
2275
2276 /* If other modules have changed p translate it into a zeta... */
2277 if (ctl->advect_cpl_zeta_and_press_modules > 0) {
2279 intpol_met_4d_coord(met0, met0->pl, met0->zetal, met1,
2280 met1->pl, met1->zetal, atm->time[ip], atm->p[ip],
2281 atm->lon[ip], atm->lat[ip],
2282 &atm->q[ctl->qnt_zeta][ip], ci, cw, 1);
2283 }
2284
2285 /* Init... */
2286 double dts, u[4], um = 0, v[4], vm = 0, zeta_dot[4], zeta_dotm = 0,
2287 x[3] = { 0, 0, 0 };
2288
2289 /* Loop over integration nodes... */
2290 for (int i = 0; i < ctl->advect; i++) {
2291
2292 /* Set position... */
2293 if (i == 0) {
2294 dts = 0.0;
2295 x[0] = atm->lon[ip];
2296 x[1] = atm->lat[ip];
2297 x[2] = atm->q[ctl->qnt_zeta][ip];
2298 } else {
2299 dts = (i == 3 ? 1.0 : 0.5) * dt[ip];
2300 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2301 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2302 x[2] = atm->q[ctl->qnt_zeta][ip] + dts * zeta_dot[i - 1];
2303 }
2304 double tm = atm->time[ip] + dts;
2305
2306 /* Interpolate meteo data... */
2308 intpol_met_4d_coord(met0, met0->zetal, met0->ul, met1, met1->zetal,
2309 met1->ul, tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2310 intpol_met_4d_coord(met0, met0->zetal, met0->vl, met1, met0->zetal,
2311 met1->vl, tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2312 intpol_met_4d_coord(met0, met0->zetal, met0->zeta_dotl, met1,
2313 met1->zetal, met1->zeta_dotl, tm, x[2], x[0],
2314 x[1], &zeta_dot[i], ci, cw, 0);
2315
2316 /* Get mean wind... */
2317 double k = 1.0;
2318 if (ctl->advect == 2)
2319 k = (i == 0 ? 0.0 : 1.0);
2320 else if (ctl->advect == 4)
2321 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2322 um += k * u[i];
2323 vm += k * v[i];
2324 zeta_dotm += k * zeta_dot[i];
2325 }
2326
2327 /* Set new position... */
2328 atm->time[ip] += dt[ip];
2329 atm->lon[ip] += DX2DEG(dt[ip] * um / 1000.,
2330 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2331 atm->lat[ip] += DY2DEG(dt[ip] * vm / 1000.);
2332 atm->q[ctl->qnt_zeta][ip] += dt[ip] * zeta_dotm;
2333
2334 /* Check if zeta is below zero... */
2335 if (atm->q[ctl->qnt_zeta][ip] < 0) {
2336 atm->q[ctl->qnt_zeta][ip] = 0;
2337 }
2338
2339 /* Set new position also in pressure coordinates... */
2341 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2342 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2343 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2344 }
2345 }
2346}
void intpol_met_time_3d(met_t *met0, float array0[EX][EY][EP], met_t *met1, float array1[EX][EY][EP], double ts, double p, double lon, double lat, double *var, int *ci, double *cw, int init)
Interpolates meteorological data in 3D space and time.
Definition: mptrac.c:1593
void intpol_met_4d_coord(met_t *met0, float heights0[EX][EY][EP], float array0[EX][EY][EP], met_t *met1, float heights1[EX][EY][EP], float array1[EX][EY][EP], double ts, double height, double lon, double lat, double *var, int *ci, double *cw, int init)
Interpolates meteorological variables to a given position and time.
Definition: mptrac.c:1233
void intpol_met_time_3d_ml(met_t *met0, float array0[EX][EY][EP], met_t *met1, float array1[EX][EY][EP], double ts, double p, double lon, double lat, double *var)
Interpolates a meteorological variable in time and 3D space (longitude, latitude, pressure).
Definition: mptrac.c:1622
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1225
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:501
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:519
double time[NP]
Time [s].
Definition: mptrac.h:3074
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3083
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3080
int np
Number of air parcels.
Definition: mptrac.h:3071
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3086
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3077
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2595
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2358
int advect_cpl_zeta_and_press_modules
Coupled use of pressure based modules and diabatic advection.
Definition: mptrac.h:2141
int advect_vert_coord
Vertical coordinate of air parcels (0=pressure, 1=zeta, 2=eta).
Definition: mptrac.h:2147
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3436
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3394
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3430
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3427
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3388
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3424
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3391
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3433
Here is the call graph for this function:

◆ module_advect_init()

void module_advect_init ( 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 2350 of file mptrac.c.

2354 {
2355
2356 /* Initialize pressure consistent with zeta... */
2357 if (ctl->advect_vert_coord == 1) {
2358#pragma omp parallel for default(shared)
2359 for (int ip = 0; ip < atm->np; ip++) {
2361 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2362 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2363 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2364 }
2365 }
2366}
Here is the call graph for this function:

◆ module_bound_cond()

void module_bound_cond ( ctl_t ctl,
clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
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 2370 of file mptrac.c.

2376 {
2377
2378 /* Set timer... */
2379 SELECT_TIMER("MODULE_BOUNDCOND", "PHYSICS", NVTX_GPU);
2380
2381 /* Check quantity flags... */
2382 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2383 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2384 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2385 return;
2386
2387 /* Loop over particles... */
2388 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,met0,met1,atm,dt)") {
2389
2390 /* Check latitude and pressure range... */
2391 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2392 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2393 continue;
2394
2395 /* Check surface layer... */
2396 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2397 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2398
2399 /* Get surface pressure... */
2400 double ps;
2402 INTPOL_2D(ps, 1);
2403
2404 /* Check pressure... */
2405 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2406 continue;
2407
2408 /* Check height... */
2409 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2410 continue;
2411
2412 /* Check zeta range... */
2413 if (ctl->bound_zetas > 0) {
2414 double t;
2415 INTPOL_3D(t, 1);
2416 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2417 continue;
2418 }
2419
2420 /* Check planetary boundary layer... */
2421 if (ctl->bound_pbl) {
2422 double pbl;
2423 INTPOL_2D(pbl, 0);
2424 if (atm->p[ip] < pbl)
2425 continue;
2426 }
2427 }
2428
2429 /* Set mass and volume mixing ratio... */
2430 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2431 atm->q[ctl->qnt_m][ip] =
2432 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2433 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2434 atm->q[ctl->qnt_vmr][ip] =
2435 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2436
2437 /* Set CFC-10 volume mixing ratio... */
2438 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2439 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2440
2441 /* Set CFC-11 volume mixing ratio... */
2442 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2443 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2444
2445 /* Set CFC-12 volume mixing ratio... */
2446 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2447 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2448
2449 /* Set N2O volume mixing ratio... */
2450 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2451 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2452
2453 /* Set SF6 volume mixing ratio... */
2454 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2455 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2456
2457 /* Set age of air... */
2458 if (ctl->qnt_aoa >= 0)
2459 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2460 }
2461}
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:376
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:687
#define ZETA(ps, p, t)
Calculate potential vorticity using the Zeta approximation.
Definition: mptrac.h:1768
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:670
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3272
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3278
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3266
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3269
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3275
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2427
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2184
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2436
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2715
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2664
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2421
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2637
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2187
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2652
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2670
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2658
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2643
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2649
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2646
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2430
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2424
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2433
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2661
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2640
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2655
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2706
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2718
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2709
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2712
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2667
Here is the call graph for this function:

◆ module_chemgrid()

void module_chemgrid ( ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
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 2465 of file mptrac.c.

2470 {
2471
2472 /* Check quantities... */
2473 if (ctl->molmass <= 0)
2474 ERRMSG("Molar mass is not defined!");
2475 if (ctl->qnt_m < 0)
2476 ERRMSG("Module needs quantity mass!");
2477 if (ctl->qnt_Cx < 0)
2478 ERRMSG("Module needs quantity Cx!");
2479
2480 /* Set timer... */
2481 SELECT_TIMER("MODULE_CHEMGRID", "PHYSICS", NVTX_GPU);
2482
2483 /* Allocate... */
2484 const int np = atm->np;
2485 const int nz = ctl->chemgrid_nz;
2486 const int nx = ctl->chemgrid_nx;
2487 const int ny = ctl->chemgrid_ny;
2488 const int ngrid = nx * ny * nz;
2489
2490 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2491 double *restrict const press =
2492 (double *) malloc((size_t) nz * sizeof(double));
2493 double *restrict const mass =
2494 (double *) calloc((size_t) ngrid, sizeof(double));
2495 double *restrict const area =
2496 (double *) malloc((size_t) ny * sizeof(double));
2497 double *restrict const lon =
2498 (double *) malloc((size_t) nx * sizeof(double));
2499 double *restrict const lat =
2500 (double *) malloc((size_t) ny * sizeof(double));
2501
2502 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2503 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2504 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2505
2506 /* Set grid box size... */
2507 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2508 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2509 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2510
2511 /* Set vertical coordinates... */
2512#ifdef _OPENACC
2513#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])
2514#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2515#pragma acc parallel loop independent gang vector
2516#else
2517#pragma omp parallel for default(shared)
2518#endif
2519 for (int iz = 0; iz < nz; iz++) {
2520 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2521 press[iz] = P(z[iz]);
2522 }
2523
2524 /* Set time interval for output... */
2525 const double t0 = tt - 0.5 * ctl->dt_mod;
2526 const double t1 = tt + 0.5 * ctl->dt_mod;
2527
2528 /* Get indices... */
2529#ifdef _OPENACC
2530#pragma acc parallel loop independent gang vector
2531#else
2532#pragma omp parallel for default(shared)
2533#endif
2534 for (int ip = 0; ip < np; ip++) {
2535 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2536 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2537 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2538 if (atm->time[ip] < t0 || atm->time[ip] > t1
2539 || ixs[ip] < 0 || ixs[ip] >= nx
2540 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2541 izs[ip] = -1;
2542 }
2543
2544 /* Set horizontal coordinates... */
2545#ifdef _OPENACC
2546#pragma acc parallel loop independent gang vector
2547#else
2548#pragma omp parallel for default(shared)
2549#endif
2550 for (int ix = 0; ix < nx; ix++)
2551 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
2552#ifdef _OPENACC
2553#pragma acc parallel loop independent gang vector
2554#else
2555#pragma omp parallel for default(shared)
2556#endif
2557 for (int iy = 0; iy < ny; iy++) {
2558 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
2559 area[iy] =
2560 dlat * dlon * SQR(RE * M_PI / 180.) * cos(lat[iy] * M_PI / 180.);
2561 }
2562
2563 /* Get mass per grid box... */
2564#ifdef _OPENACC
2565#pragma acc parallel loop independent gang vector
2566#endif
2567 for (int ip = 0; ip < np; ip++)
2568 if (izs[ip] >= 0)
2569#ifdef _OPENACC
2570#pragma acc atomic update
2571#endif
2572 mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)]
2573 += atm->q[ctl->qnt_m][ip];
2574
2575 /* Assign grid data to air parcels ... */
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 ip = 0; ip < np; ip++)
2582 if (izs[ip] >= 0) {
2583
2584 /* Interpolate temperature... */
2585 double temp;
2587 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt, press[izs[ip]],
2588 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
2589
2590 /* Set mass... */
2591 double m = mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)];
2592
2593 /* Calculate volume mixing ratio... */
2594 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
2595 / (1e9 * RHO(press[izs[ip]], temp) * area[iys[ip]] * dz);
2596 }
2597#ifdef _OPENACC
2598#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
2599#endif
2600
2601 /* Free... */
2602 free(mass);
2603 free(lon);
2604 free(lat);
2605 free(area);
2606 free(z);
2607 free(press);
2608 free(ixs);
2609 free(iys);
2610 free(izs);
2611}
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:386
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:192
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1255
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1415
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2676
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2763
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2760
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2778
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2781
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2769
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2772
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2448
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2757
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2766
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2775
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2391
Here is the call graph for this function:

◆ module_chem_init()

void module_chem_init ( ctl_t ctl,
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 2615 of file mptrac.c.

2620 {
2621
2622#pragma omp parallel for default(shared)
2623 for (int ip = 0; ip < atm->np; ip++) {
2624
2625 /* Set H2O and O3 using meteo data... */
2627 if (ctl->qnt_Ch2o >= 0) {
2628 double h2o;
2629 INTPOL_3D(h2o, 1);
2630 SET_ATM(qnt_Ch2o, h2o);
2631 }
2632 if (ctl->qnt_Co3 >= 0) {
2633 double o3;
2634 INTPOL_3D(o3, 1);
2635 SET_ATM(qnt_Co3, o3);
2636 }
2637
2638 /* Set radical species... */
2639 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
2640 atm->lon[ip], atm->lat[ip], atm->p[ip]));
2641 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
2642 atm->lat[ip], atm->p[ip]));
2643 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
2644 atm->lat[ip], atm->p[ip]));
2645 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
2646 atm->lat[ip], atm->p[ip]));
2647 }
2648}
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:88
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1465
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3260
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3263
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3257
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2394
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2397
Here is the call graph for this function:

◆ module_convection()

void module_convection ( ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
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 2652 of file mptrac.c.

2658 {
2659
2660 /* Set timer... */
2661 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
2662
2663 /* Create random numbers... */
2664 module_rng(ctl, rs, (size_t) atm->np, 0);
2665
2666 /* Loop over particles... */
2667 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt,rs)") {
2668
2669 /* Interpolate CAPE... */
2670 double cape;
2672 INTPOL_2D(cape, 1);
2673
2674 /* Check threshold... */
2675 if (isfinite(cape) && cape >= ctl->conv_cape) {
2676
2677 /* Check CIN... */
2678 if (ctl->conv_cin > 0) {
2679 double cin;
2680 INTPOL_2D(cin, 0);
2681 if (isfinite(cin) && cin >= ctl->conv_cin)
2682 continue;
2683 }
2684
2685 /* Interpolate equilibrium level... */
2686 double pel;
2687 INTPOL_2D(pel, 0);
2688
2689 /* Check whether particle is above cloud top... */
2690 if (!isfinite(pel) || atm->p[ip] < pel)
2691 continue;
2692
2693 /* Set pressure range for vertical mixing... */
2694 double pbot = atm->p[ip];
2695 double ptop = atm->p[ip];
2696 if (ctl->conv_mix_bot == 1) {
2697 double ps;
2698 INTPOL_2D(ps, 0);
2699 pbot = ps;
2700 }
2701 if (ctl->conv_mix_top == 1)
2702 ptop = pel;
2703
2704 /* Get density range... */
2705 double tbot, ttop;
2706 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2707 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
2708 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2709 ptop, atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
2710 double rhobot = pbot / tbot;
2711 double rhotop = ptop / ttop;
2712
2713 /* Get new density... */
2714 double rho = rhobot + (rhotop - rhobot) * rs[ip];
2715
2716 /* Get pressure... */
2717 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
2718 }
2719 }
2720}
void module_rng(ctl_t *ctl, double *rs, size_t n, int method)
Generate random numbers using various methods and distributions.
Definition: mptrac.c:3659
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2622
int conv_mix_bot
Lower level for mixing (0=particle pressure, 1=surface).
Definition: mptrac.h:2631
int conv_mix_top
Upper level for mixing (0=particle pressure, 1=EL).
Definition: mptrac.h:2634
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2625
Here is the call graph for this function:

◆ module_decay()

void module_decay ( ctl_t ctl,
clim_t clim,
atm_t atm,
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 2724 of file mptrac.c.

2728 {
2729
2730 /* Set timer... */
2731 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
2732
2733 /* Check quantity flags... */
2734 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2735 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2736
2737 /* Loop over particles... */
2738 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,atm,dt)") {
2739
2740 /* Get weighting factor... */
2741 double w = tropo_weight(clim, atm->time[ip], atm->lat[ip], atm->p[ip]);
2742
2743 /* Set lifetime... */
2744 double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
2745
2746 /* Calculate exponential decay... */
2747 double aux = exp(-dt[ip] / tdec);
2748 if (ctl->qnt_m >= 0) {
2749 if (ctl->qnt_mloss_decay >= 0)
2750 atm->q[ctl->qnt_mloss_decay][ip]
2751 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2752 atm->q[ctl->qnt_m][ip] *= aux;
2753 if (ctl->qnt_loss_rate >= 0)
2754 atm->q[ctl->qnt_loss_rate][ip] += 1 / tdec;
2755 }
2756 if (ctl->qnt_vmr >= 0)
2757 atm->q[ctl->qnt_vmr][ip] *= aux;
2758 }
2759}
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:8293
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2334
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2331
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2682
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2679
Here is the call graph for this function:

◆ module_diffusion_meso()

void module_diffusion_meso ( ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
cache_t cache,
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 2763 of file mptrac.c.

2770 {
2771
2772 /* Set timer... */
2773 SELECT_TIMER("MODULE_TURBMESO", "PHYSICS", NVTX_GPU);
2774
2775 /* Create random numbers... */
2776 module_rng(ctl, rs, 3 * (size_t) atm->np, 1);
2777
2778 /* Loop over particles... */
2779 PARTICLE_LOOP(0, atm->np, 1,
2780 "acc data present(ctl,met0,met1,atm,cache,dt,rs)") {
2781
2782 /* Get indices... */
2783 int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
2784 int iy = locate_reg(met0->lat, met0->ny, atm->lat[ip]);
2785 int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
2786
2787 /* Get standard deviations of local wind data... */
2788 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
2789 for (int i = 0; i < 2; i++)
2790 for (int j = 0; j < 2; j++)
2791 for (int k = 0; k < 2; k++) {
2792 umean += met0->u[ix + i][iy + j][iz + k];
2793 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
2794 vmean += met0->v[ix + i][iy + j][iz + k];
2795 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
2796 wmean += met0->w[ix + i][iy + j][iz + k];
2797 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
2798
2799 umean += met1->u[ix + i][iy + j][iz + k];
2800 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
2801 vmean += met1->v[ix + i][iy + j][iz + k];
2802 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
2803 wmean += met1->w[ix + i][iy + j][iz + k];
2804 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
2805 }
2806 usig = usig / 16.f - SQR(umean / 16.f);
2807 usig = (usig > 0 ? sqrtf(usig) : 0);
2808 vsig = vsig / 16.f - SQR(vmean / 16.f);
2809 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
2810 wsig = wsig / 16.f - SQR(wmean / 16.f);
2811 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
2812
2813 /* Set temporal correlations for mesoscale fluctuations... */
2814 double r = 1 - 2 * fabs(dt[ip]) / ctl->dt_met;
2815 double r2 = sqrt(1 - r * r);
2816
2817 /* Calculate horizontal mesoscale wind fluctuations... */
2818 if (ctl->turb_mesox > 0) {
2819 cache->uvwp[ip][0] =
2820 (float) (r * cache->uvwp[ip][0] +
2821 r2 * rs[3 * ip] * ctl->turb_mesox * usig);
2822 atm->lon[ip] +=
2823 DX2DEG(cache->uvwp[ip][0] * dt[ip] / 1000., atm->lat[ip]);
2824
2825 cache->uvwp[ip][1] =
2826 (float) (r * cache->uvwp[ip][1] +
2827 r2 * rs[3 * ip + 1] * ctl->turb_mesox * vsig);
2828 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * dt[ip] / 1000.);
2829 }
2830
2831 /* Calculate vertical mesoscale wind fluctuations... */
2832 if (ctl->turb_mesoz > 0) {
2833 cache->uvwp[ip][2] =
2834 (float) (r * cache->uvwp[ip][2] +
2835 r2 * rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
2836 atm->p[ip] += cache->uvwp[ip][2] * dt[ip];
2837 }
2838 }
2839}
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3111
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2619
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2616
Here is the call graph for this function:

◆ module_diffusion_turb()

void module_diffusion_turb ( ctl_t ctl,
clim_t clim,
atm_t atm,
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 2843 of file mptrac.c.

2848 {
2849
2850 /* Set timer... */
2851 SELECT_TIMER("MODULE_TURBDIFF", "PHYSICS", NVTX_GPU);
2852
2853 /* Create random numbers... */
2854 module_rng(ctl, rs, 3 * (size_t) atm->np, 1);
2855
2856 /* Loop over particles... */
2857 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,atm,dt,rs)") {
2858
2859 /* Get weighting factor... */
2860 double w = tropo_weight(clim, atm->time[ip], atm->lat[ip], atm->p[ip]);
2861
2862 /* Set diffusivity... */
2863 double dx = w * ctl->turb_dx_trop + (1 - w) * ctl->turb_dx_strat;
2864 double dz = w * ctl->turb_dz_trop + (1 - w) * ctl->turb_dz_strat;
2865
2866 /* Horizontal turbulent diffusion... */
2867 if (dx > 0) {
2868 double sigma = sqrt(2.0 * dx * fabs(dt[ip]));
2869 atm->lon[ip] += DX2DEG(rs[3 * ip] * sigma / 1000., atm->lat[ip]);
2870 atm->lat[ip] += DY2DEG(rs[3 * ip + 1] * sigma / 1000.);
2871 }
2872
2873 /* Vertical turbulent diffusion... */
2874 if (dz > 0) {
2875 double sigma = sqrt(2.0 * dz * fabs(dt[ip]));
2876 atm->p[ip] += DZ2DP(rs[3 * ip + 2] * sigma / 1000., atm->p[ip]);
2877 }
2878 }
2879}
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:536
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2610
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2607
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2604
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2613
Here is the call graph for this function:

◆ module_dry_deposition()

void module_dry_deposition ( ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
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 2883 of file mptrac.c.

2888 {
2889
2890 /* Set timer... */
2891 SELECT_TIMER("MODULE_DRYDEPO", "PHYSICS", NVTX_GPU);
2892
2893 /* Check quantity flags... */
2894 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2895 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2896
2897 /* Loop over particles... */
2898 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
2899
2900 /* Get surface pressure... */
2901 double ps;
2903 INTPOL_2D(ps, 1);
2904
2905 /* Check whether particle is above the surface layer... */
2906 if (atm->p[ip] < ps - ctl->dry_depo_dp)
2907 continue;
2908
2909 /* Set depth of surface layer... */
2910 double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
2911
2912 /* Calculate sedimentation velocity for particles... */
2913 double v_dep;
2914 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
2915
2916 /* Get temperature... */
2917 double t;
2918 INTPOL_3D(t, 1);
2919
2920 /* Set deposition velocity... */
2921 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
2922 atm->q[ctl->qnt_rhop][ip]);
2923 }
2924
2925 /* Use explicit sedimentation velocity for gases... */
2926 else
2927 v_dep = ctl->dry_depo_vdep;
2928
2929 /* Calculate loss of mass based on deposition velocity... */
2930 double aux = exp(-dt[ip] * v_dep / dz);
2931 if (ctl->qnt_m >= 0) {
2932 if (ctl->qnt_mloss_dry >= 0)
2933 atm->q[ctl->qnt_mloss_dry][ip]
2934 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2935 atm->q[ctl->qnt_m][ip] *= aux;
2936 if (ctl->qnt_loss_rate >= 0)
2937 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
2938 }
2939 if (ctl->qnt_vmr >= 0)
2940 atm->q[ctl->qnt_vmr][ip] *= aux;
2941 }
2942}
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:8015
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2193
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2190
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2832
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2328
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2835
Here is the call graph for this function:

◆ module_h2o2_chem()

void module_h2o2_chem ( ctl_t ctl,
clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
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 2946 of file mptrac.c.

2952 {
2953
2954 /* Set timer... */
2955 SELECT_TIMER("MODULE_H2O2CHEM", "PHYSICS", NVTX_GPU);
2956
2957 /* Check quantity flags... */
2958 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2959 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2960
2961 /* Parameter of SO2 correction... */
2962 const double a = 3.12541941e-06;
2963 const double b = -5.72532259e-01;
2964 const double low = pow(1 / a, 1 / b);
2965
2966 /* Loop over particles... */
2967 PARTICLE_LOOP(0, atm->np, 1, "acc data present(clim,ctl,met0,met1,atm,dt)") {
2968
2969 /* Check whether particle is inside cloud... */
2970 double lwc, rwc;
2972 INTPOL_3D(lwc, 1);
2973 INTPOL_3D(rwc, 0);
2974 if (!(lwc > 0 || rwc > 0))
2975 continue;
2976
2977 /* Get temperature... */
2978 double t;
2979 INTPOL_3D(t, 0);
2980
2981 /* Get molecular density... */
2982 double M = MOLEC_DENS(atm->p[ip], t);
2983
2984 /* Reaction rate (Berglen et al., 2004)... */
2985 double k = 9.1e7 * exp(-29700 / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
2986
2987 /* Henry constant of SO2... */
2988 double H_SO2 = 1.3e-2 * exp(2900 * (1. / t - 1. / 298.15)) * RI * t;
2989 double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
2990
2991 /* Henry constant of H2O2... */
2992 double H_h2o2 = 8.3e2 * exp(7600 * (1 / t - 1 / 298.15)) * RI * t;
2993
2994 /* Correction factor for high SO2 concentration
2995 (if qnt_Cx is defined, the correction is switched on)... */
2996 double cor = 1;
2997 if (ctl->qnt_Cx >= 0)
2998 cor = atm->q[ctl->qnt_Cx][ip] >
2999 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3000
3001 double h2o2 = H_h2o2
3002 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3003 * M * cor * 1000 / AVO; /* unit: mol/L */
3004
3005 /* Volume water content in cloud [m^3 m^(-3)]... */
3006 double rho_air = 100 * atm->p[ip] / (RI * t) * MA / 1000;
3007 double CWC = (lwc + rwc) * rho_air / 1000;
3008
3009 /* Calculate exponential decay (Rolph et al., 1992)... */
3010 double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3011 double aux = exp(-dt[ip] * rate_coef);
3012 if (ctl->qnt_m >= 0) {
3013 if (ctl->qnt_mloss_h2o2 >= 0)
3014 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3015 atm->q[ctl->qnt_m][ip] *= aux;
3016 if (ctl->qnt_loss_rate >= 0)
3017 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3018 }
3019 if (ctl->qnt_vmr >= 0)
3020 atm->q[ctl->qnt_vmr][ip] *= aux;
3021 }
3022}
#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:967
#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:2319
Here is the call graph for this function:

◆ module_isosurf_init()

void module_isosurf_init ( 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 3026 of file mptrac.c.

3031 {
3032
3033 double t;
3034
3035 /* Set timer... */
3036 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3037
3038 /* Init... */
3040
3041 /* Save pressure... */
3042 if (ctl->isosurf == 1)
3043 for (int ip = 0; ip < atm->np; ip++)
3044 cache->iso_var[ip] = atm->p[ip];
3045
3046 /* Save density... */
3047 else if (ctl->isosurf == 2)
3048 for (int ip = 0; ip < atm->np; ip++) {
3049 INTPOL_3D(t, 1);
3050 cache->iso_var[ip] = atm->p[ip] / t;
3051 }
3052
3053 /* Save potential temperature... */
3054 else if (ctl->isosurf == 3)
3055 for (int ip = 0; ip < atm->np; ip++) {
3056 INTPOL_3D(t, 1);
3057 cache->iso_var[ip] = THETA(atm->p[ip], t);
3058 }
3059
3060 /* Read balloon pressure data... */
3061 else if (ctl->isosurf == 4) {
3062
3063 /* Write info... */
3064 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3065
3066 /* Open file... */
3067 FILE *in;
3068 if (!(in = fopen(ctl->balloon, "r")))
3069 ERRMSG("Cannot open file!");
3070
3071 /* Read pressure time series... */
3072 char line[LEN];
3073 while (fgets(line, LEN, in))
3074 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3075 &(cache->iso_ps[cache->iso_n])) == 2)
3076 if ((++cache->iso_n) > NP)
3077 ERRMSG("Too many data points!");
3078
3079 /* Check number of points... */
3080 if (cache->iso_n < 1)
3081 ERRMSG("Could not read any data!");
3082
3083 /* Close file... */
3084 fclose(in);
3085 }
3086}
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1609
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:241
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3105
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3108
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3102
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3099
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2592
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2589

◆ module_isosurf()

void module_isosurf ( ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
cache_t cache,
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 3090 of file mptrac.c.

3096 {
3097
3098 /* Set timer... */
3099 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3100
3101 /* Loop over particles... */
3102 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm,cache,dt)") {
3103
3104 /* Init... */
3105 double t;
3107
3108 /* Restore pressure... */
3109 if (ctl->isosurf == 1)
3110 atm->p[ip] = cache->iso_var[ip];
3111
3112 /* Restore density... */
3113 else if (ctl->isosurf == 2) {
3114 INTPOL_3D(t, 1);
3115 atm->p[ip] = cache->iso_var[ip] * t;
3116 }
3117
3118 /* Restore potential temperature... */
3119 else if (ctl->isosurf == 3) {
3120 INTPOL_3D(t, 1);
3121 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3122 }
3123
3124 /* Interpolate pressure... */
3125 else if (ctl->isosurf == 4) {
3126 if (atm->time[ip] <= cache->iso_ts[0])
3127 atm->p[ip] = cache->iso_ps[0];
3128 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3129 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3130 else {
3131 int idx = locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3132 atm->p[ip] = LIN(cache->iso_ts[idx], cache->iso_ps[idx],
3133 cache->iso_ts[idx + 1], cache->iso_ps[idx + 1],
3134 atm->time[ip]);
3135 }
3136 }
3137 }
3138}
Here is the call graph for this function:

◆ module_meteo()

void module_meteo ( ctl_t ctl,
clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
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 3202 of file mptrac.c.

3208 {
3209
3210 /* Set timer... */
3211 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
3212
3213 /* Check quantity flags... */
3214 if (ctl->qnt_tsts >= 0)
3215 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3216 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3217
3218 /* Loop over particles... */
3219 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,clim,met0,met1,atm,dt)") {
3220
3221 double ps, ts, zs, us, vs, lsm, sst, pbl, pt, pct, pcb, cl, plcl, plfc,
3222 pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot, o3,
3223 lwc, rwc, iwc, swc, cc, z, zt;
3224
3225 /* Interpolate meteo data... */
3227 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3228
3229 /* Set quantities... */
3230 SET_ATM(qnt_ps, ps);
3231 SET_ATM(qnt_ts, ts);
3232 SET_ATM(qnt_zs, zs);
3233 SET_ATM(qnt_us, us);
3234 SET_ATM(qnt_vs, vs);
3235 SET_ATM(qnt_lsm, lsm);
3236 SET_ATM(qnt_sst, sst);
3237 SET_ATM(qnt_pbl, pbl);
3238 SET_ATM(qnt_pt, pt);
3239 SET_ATM(qnt_tt, tt);
3240 SET_ATM(qnt_zt, zt);
3241 SET_ATM(qnt_h2ot, h2ot);
3242 SET_ATM(qnt_zg, z);
3243 SET_ATM(qnt_p, atm->p[ip]);
3244 SET_ATM(qnt_t, t);
3245 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3246 SET_ATM(qnt_u, u);
3247 SET_ATM(qnt_v, v);
3248 SET_ATM(qnt_w, w);
3249 SET_ATM(qnt_h2o, h2o);
3250 SET_ATM(qnt_o3, o3);
3251 SET_ATM(qnt_lwc, lwc);
3252 SET_ATM(qnt_rwc, rwc);
3253 SET_ATM(qnt_iwc, iwc);
3254 SET_ATM(qnt_swc, swc);
3255 SET_ATM(qnt_cc, cc);
3256 SET_ATM(qnt_pct, pct);
3257 SET_ATM(qnt_pcb, pcb);
3258 SET_ATM(qnt_cl, cl);
3259 SET_ATM(qnt_plcl, plcl);
3260 SET_ATM(qnt_plfc, plfc);
3261 SET_ATM(qnt_pel, pel);
3262 SET_ATM(qnt_cape, cape);
3263 SET_ATM(qnt_cin, cin);
3264 SET_ATM(qnt_o3c, o3c);
3265 SET_ATM(qnt_hno3,
3266 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3267 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3268 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3269 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3270 atm->lat[ip], atm->p[ip]));
3271 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3272 atm->lat[ip], atm->p[ip]));
3273 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3274 atm->lat[ip], atm->p[ip]));
3275 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3276 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3277 SET_ATM(qnt_psat, PSAT(t));
3278 SET_ATM(qnt_psice, PSICE(t));
3279 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3280 SET_ATM(qnt_sh, SH(h2o));
3281 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3282 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3283 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3284 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3285 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3286 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3287 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3288 SET_ATM(qnt_pv, pv);
3289 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3290 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3291 SET_ATM(qnt_tnat,
3292 nat_temperature(atm->p[ip], h2o,
3293 clim_zm(&clim->hno3, atm->time[ip],
3294 atm->lat[ip], atm->p[ip])));
3295 SET_ATM(qnt_tsts,
3296 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3297 }
3298}
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:4159
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:1830
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1684
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1330
#define H0
Scale height [km].
Definition: mptrac.h:177
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1303
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1585
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1390
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:757
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1360
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1560
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1279
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3251
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2388
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2382
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2385
Here is the call graph for this function:

◆ module_mixing()

void module_mixing ( ctl_t ctl,
clim_t clim,
atm_t atm,
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 3302 of file mptrac.c.

3306 {
3307
3308 /* Set timer... */
3309 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
3310
3311 /* Allocate... */
3312 const int np = atm->np;
3313 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3314 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3315 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3316
3317 /* Set grid box size... */
3318 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3319 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3320 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3321
3322 /* Set time interval... */
3323 const double t0 = t - 0.5 * ctl->dt_mod;
3324 const double t1 = t + 0.5 * ctl->dt_mod;
3325
3326 /* Get indices... */
3327#ifdef _OPENACC
3328#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3329#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3330#pragma acc parallel loop independent gang vector
3331#else
3332#pragma omp parallel for default(shared)
3333#endif
3334 for (int ip = 0; ip < np; ip++) {
3335 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3336 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3337 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3338 if (atm->time[ip] < t0 || atm->time[ip] > t1
3339 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3340 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3341 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3342 izs[ip] = -1;
3343 }
3344
3345 /* Calculate interparcel mixing... */
3346 if (ctl->qnt_m >= 0)
3347 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_m);
3348 if (ctl->qnt_vmr >= 0)
3349 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_vmr);
3350 if (ctl->qnt_Ch2o >= 0)
3351 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o);
3352 if (ctl->qnt_Co3 >= 0)
3353 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3);
3354 if (ctl->qnt_Cco >= 0)
3355 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cco);
3356 if (ctl->qnt_Coh >= 0)
3357 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Coh);
3358 if (ctl->qnt_Ch >= 0)
3359 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch);
3360 if (ctl->qnt_Cho2 >= 0)
3361 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cho2);
3362 if (ctl->qnt_Ch2o2 >= 0)
3363 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o2);
3364 if (ctl->qnt_Co1d >= 0)
3365 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co1d);
3366 if (ctl->qnt_Co3p >= 0)
3367 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3p);
3368 if (ctl->qnt_Cccl4 >= 0)
3369 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl4);
3370 if (ctl->qnt_Cccl3f >= 0)
3371 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl3f);
3372 if (ctl->qnt_Cccl2f2 >= 0)
3373 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl2f2);
3374 if (ctl->qnt_Cn2o >= 0)
3375 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cn2o);
3376 if (ctl->qnt_Csf6 >= 0)
3377 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Csf6);
3378 if (ctl->qnt_aoa >= 0)
3379 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_aoa);
3380
3381 /* Free... */
3382#ifdef _OPENACC
3383#pragma acc exit data delete(ixs,iys,izs)
3384#endif
3385 free(ixs);
3386 free(iys);
3387 free(izs);
3388}
void module_mixing_help(ctl_t *ctl, clim_t *clim, atm_t *atm, const int *ixs, const int *iys, const int *izs, int qnt_idx)
Perform interparcel mixing for a specific quantity.
Definition: mptrac.c:3392
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2403
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2739
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2736
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2415
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2733
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2400
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2748
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2406
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2751
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2409
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2730
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2742
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2754
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2418
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2412
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2745
Here is the call graph for this function:

◆ module_mixing_help()

void module_mixing_help ( ctl_t ctl,
clim_t clim,
atm_t atm,
const int *  ixs,
const int *  iys,
const int *  izs,
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 3392 of file mptrac.c.

3399 {
3400
3401 /* Allocate... */
3402 const int np = atm->np;
3403 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
3404 double *restrict const cmean =
3405 (double *) malloc((size_t) ngrid * sizeof(double));
3406 int *restrict const count = (int *) malloc((size_t) ngrid * sizeof(int));
3407
3408 /* Init... */
3409#ifdef _OPENACC
3410#pragma acc enter data create(cmean[0:ngrid],count[0:ngrid])
3411#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
3412#pragma acc parallel loop independent gang vector
3413#else
3414#ifdef __NVCOMPILER
3415#pragma novector
3416#endif
3417#pragma omp parallel for
3418#endif
3419 for (int i = 0; i < ngrid; i++) {
3420 count[i] = 0;
3421 cmean[i] = 0;
3422 }
3423
3424 /* Loop over particles... */
3425#ifdef _OPENACC
3426#pragma acc parallel loop independent gang vector
3427#endif
3428 for (int ip = 0; ip < np; ip++)
3429 if (izs[ip] >= 0) {
3430 int idx = ARRAY_3D
3431 (ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz);
3432#ifdef _OPENACC
3433#pragma acc atomic update
3434#endif
3435 cmean[idx] += atm->q[qnt_idx][ip];
3436#ifdef _OPENACC
3437#pragma acc atomic update
3438#endif
3439 count[idx]++;
3440 }
3441#ifdef _OPENACC
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 if (count[i] > 0)
3451 cmean[i] /= count[i];
3452
3453 /* Calculate interparcel mixing... */
3454#ifdef _OPENACC
3455#pragma acc parallel loop independent gang vector
3456#else
3457#pragma omp parallel for
3458#endif
3459 for (int ip = 0; ip < np; ip++)
3460 if (izs[ip] >= 0) {
3461
3462 /* Set mixing parameter... */
3463 double mixparam = 1.0;
3464 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
3465 double w =
3466 tropo_weight(clim, atm->time[ip], atm->lat[ip], atm->p[ip]);
3467 mixparam = w * ctl->mixing_trop + (1 - w) * ctl->mixing_strat;
3468 }
3469
3470 /* Adjust quantity... */
3471 atm->q[qnt_idx][ip] +=
3472 (cmean
3473 [ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz)]
3474 - atm->q[qnt_idx][ip]) * mixparam;
3475 }
3476
3477 /* Free... */
3478#ifdef _OPENACC
3479#pragma acc exit data delete(cmean,count)
3480#endif
3481 free(cmean);
3482 free(count);
3483}
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2724
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2727
Here is the call graph for this function:

◆ module_oh_chem()

void module_oh_chem ( ctl_t ctl,
clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
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 3487 of file mptrac.c.

3493 {
3494
3495 /* Set timer... */
3496 SELECT_TIMER("MODULE_OHCHEM", "PHYSICS", NVTX_GPU);
3497
3498 /* Check quantity flags... */
3499 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3500 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3501
3502 /* Parameter of SO2 correction... */
3503 const double a = 4.71572206e-08;
3504 const double b = -8.28782867e-01;
3505 const double low = pow(1 / a, 1 / b);
3506
3507 /* Loop over particles... */
3508 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,met0,met1,atm,dt)") {
3509
3510 /* Get temperature... */
3511 double t;
3513 INTPOL_3D(t, 1);
3514
3515 /* Calculate molecular density... */
3516 double M = MOLEC_DENS(atm->p[ip], t);
3517
3518 /* Use constant reaction rate... */
3519 double k = NAN;
3520 if (ctl->oh_chem_reaction == 1)
3521 k = ctl->oh_chem[0];
3522
3523 /* Calculate bimolecular reaction rate... */
3524 else if (ctl->oh_chem_reaction == 2)
3525 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
3526
3527 /* Calculate termolecular reaction rate... */
3528 if (ctl->oh_chem_reaction == 3) {
3529
3530 /* Calculate rate coefficient for X + OH + M -> XOH + M
3531 (JPL Publication 19-05) ... */
3532 double k0 =
3533 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
3534 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
3535 double ki =
3536 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
3537 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
3538 double c = log10(k0 * M / ki);
3539 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
3540 }
3541
3542 /* Correction factor for high SO2 concentration
3543 (if qnt_Cx is defined, the correction is switched on)... */
3544 double cor = 1;
3545 if (ctl->qnt_Cx >= 0)
3546 cor =
3547 atm->q[ctl->qnt_Cx][ip] >
3548 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3549
3550 /* Calculate exponential decay... */
3551 double rate_coef = k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
3552 atm->lat[ip], atm->p[ip]) * M * cor;
3553 double aux = exp(-dt[ip] * rate_coef);
3554 if (ctl->qnt_m >= 0) {
3555 if (ctl->qnt_mloss_oh >= 0)
3556 atm->q[ctl->qnt_mloss_oh][ip]
3557 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3558 atm->q[ctl->qnt_m][ip] *= aux;
3559 if (ctl->qnt_loss_rate >= 0)
3560 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3561 }
3562 if (ctl->qnt_vmr >= 0)
3563 atm->q[ctl->qnt_vmr][ip] *= aux;
3564 }
3565}
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2787
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2784
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2316
Here is the call graph for this function:

◆ module_position()

void module_position ( ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
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 3569 of file mptrac.c.

3574 {
3575
3576 /* Set timer... */
3577 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
3578
3579 /* Loop over particles... */
3580 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
3581
3582 /* Init... */
3583 double ps;
3585
3586 /* Calculate modulo... */
3587 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
3588 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
3589
3590 /* Check latitude... */
3591 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
3592 if (atm->lat[ip] > 90) {
3593 atm->lat[ip] = 180 - atm->lat[ip];
3594 atm->lon[ip] += 180;
3595 }
3596 if (atm->lat[ip] < -90) {
3597 atm->lat[ip] = -180 - atm->lat[ip];
3598 atm->lon[ip] += 180;
3599 }
3600 }
3601
3602 /* Check longitude... */
3603 while (atm->lon[ip] < -180)
3604 atm->lon[ip] += 360;
3605 while (atm->lon[ip] >= 180)
3606 atm->lon[ip] -= 360;
3607
3608 /* Check pressure... */
3609 if (atm->p[ip] < met0->p[met0->np - 1]) {
3610 if (ctl->reflect)
3611 atm->p[ip] = 2. * met0->p[met0->np - 1] - atm->p[ip];
3612 else
3613 atm->p[ip] = met0->p[met0->np - 1];
3614 } else if (atm->p[ip] > 300.) {
3615 INTPOL_2D(ps, 1);
3616 if (atm->p[ip] > ps) {
3617 if (ctl->reflect)
3618 atm->p[ip] = 2. * ps - atm->p[ip];
3619 else
3620 atm->p[ip] = ps;
3621 }
3622 }
3623 }
3624}
int reflect
Reflection of particles at top and bottom boundary (0=no, 1=yes).
Definition: mptrac.h:2598

◆ module_rng_init()

void module_rng_init ( 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 3628 of file mptrac.c.

3629 {
3630
3631 /* Initialize GSL random number generators... */
3632 gsl_rng_env_setup();
3633 if (omp_get_max_threads() > NTHREADS)
3634 ERRMSG("Too many threads!");
3635 for (int i = 0; i < NTHREADS; i++) {
3636 rng[i] = gsl_rng_alloc(gsl_rng_default);
3637 gsl_rng_set(rng[i], gsl_rng_default_seed
3638 + (long unsigned) (ntask * NTHREADS + i));
3639 }
3640
3641 /* Initialize cuRAND random number generators... */
3642#ifdef CURAND
3643 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
3644 CURAND_STATUS_SUCCESS)
3645 ERRMSG("Cannot create random number generator!");
3646 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
3647 CURAND_STATUS_SUCCESS)
3648 ERRMSG("Cannot set seed for random number generator!");
3649 if (curandSetStream
3650 (rng_curand,
3651 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
3652 CURAND_STATUS_SUCCESS)
3653 ERRMSG("Cannot set stream for random number generator!");
3654#endif
3655}
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:281

◆ module_rng()

void module_rng ( ctl_t ctl,
double *  rs,
size_t  n,
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 3659 of file mptrac.c.

3663 {
3664
3665 /* Use GSL random number generators... */
3666 if (ctl->rng_type == 0) {
3667
3668 /* Uniform distribution... */
3669 if (method == 0) {
3670#pragma omp parallel for default(shared)
3671 for (size_t i = 0; i < n; ++i)
3672 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
3673 }
3674
3675 /* Normal distribution... */
3676 else if (method == 1) {
3677#pragma omp parallel for default(shared)
3678 for (size_t i = 0; i < n; ++i)
3679 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
3680 }
3681
3682 /* Update of random numbers on device... */
3683#ifdef _OPENACC
3684#pragma acc update device(rs[:n])
3685#endif
3686 }
3687
3688 /* Use Squares random number generator (Widynski, 2022)... */
3689 else if (ctl->rng_type == 1) {
3690
3691 /* Set key (don't change this!)... */
3692 const uint64_t key = 0xc8e4fd154ce32f6d;
3693
3694 /* Uniform distribution... */
3695#ifdef _OPENACC
3696#pragma acc data present(rs)
3697#pragma acc parallel loop independent gang vector
3698#else
3699#pragma omp parallel for default(shared)
3700#endif
3701 for (size_t i = 0; i < n + 1; ++i) {
3702 uint64_t r, t, x, y, z;
3703 y = x = (rng_ctr + i) * key;
3704 z = y + key;
3705 x = x * x + y;
3706 x = (x >> 32) | (x << 32);
3707 x = x * x + z;
3708 x = (x >> 32) | (x << 32);
3709 x = x * x + y;
3710 x = (x >> 32) | (x << 32);
3711 t = x = x * x + z;
3712 x = (x >> 32) | (x << 32);
3713 r = t ^ ((x * x + y) >> 32);
3714 rs[i] = (double) r / (double) UINT64_MAX;
3715 }
3716 rng_ctr += n + 1;
3717
3718 /* Normal distribution... */
3719 if (method == 1) {
3720#ifdef _OPENACC
3721#pragma acc parallel loop independent gang vector
3722#else
3723#pragma omp parallel for default(shared)
3724#endif
3725 for (size_t i = 0; i < n; i += 2) {
3726 double r = sqrt(-2.0 * log(rs[i]));
3727 double phi = 2.0 * M_PI * rs[i + 1];
3728 rs[i] = r * cosf((float) phi);
3729 rs[i + 1] = r * sinf((float) phi);
3730 }
3731 }
3732 }
3733
3734 /* Use cuRAND random number generators... */
3735 else if (ctl->rng_type == 2) {
3736#ifdef CURAND
3737#pragma acc host_data use_device(rs)
3738 {
3739
3740 /* Uniform distribution... */
3741 if (method == 0) {
3742 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
3743 CURAND_STATUS_SUCCESS)
3744 ERRMSG("Cannot create random numbers!");
3745 }
3746
3747 /* Normal distribution... */
3748 else if (method == 1) {
3749 if (curandGenerateNormalDouble
3750 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
3751 1.0) != CURAND_STATUS_SUCCESS)
3752 ERRMSG("Cannot create random numbers!");
3753 }
3754 }
3755#else
3756 ERRMSG("MPTRAC was compiled without cuRAND!");
3757#endif
3758 }
3759}
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2601

◆ module_sedi()

void module_sedi ( ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
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 3763 of file mptrac.c.

3768 {
3769
3770 /* Set timer... */
3771 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
3772
3773 /* Loop over particles... */
3774 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
3775
3776 /* Get temperature... */
3777 double t;
3779 INTPOL_3D(t, 1);
3780
3781 /* Sedimentation velocity... */
3782 double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3783 atm->q[ctl->qnt_rhop][ip]);
3784
3785 /* Calculate pressure change... */
3786 atm->p[ip] += DZ2DP(v_s * dt[ip] / 1000., atm->p[ip]);
3787 }
3788}
Here is the call graph for this function:

◆ module_sort()

void module_sort ( 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 3792 of file mptrac.c.

3795 {
3796
3797 /* Set timer... */
3798 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
3799
3800 /* Allocate... */
3801 const int np = atm->np;
3802 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
3803 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
3804
3805#ifdef _OPENACC
3806#pragma acc enter data create(a[0:np],p[0:np])
3807#pragma acc data present(ctl,met0,atm,a,p)
3808#endif
3809
3810 /* Get box index... */
3811#ifdef _OPENACC
3812#pragma acc parallel loop independent gang vector
3813#else
3814#pragma omp parallel for default(shared)
3815#endif
3816 for (int ip = 0; ip < np; ip++) {
3817 a[ip] =
3818 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
3819 locate_reg(met0->lat, met0->ny, atm->lat[ip]))
3820 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
3821 p[ip] = ip;
3822 }
3823
3824 /* Sorting... */
3825#ifdef _OPENACC
3826#pragma acc host_data use_device(a, p)
3827#endif
3828#ifdef THRUST
3829 thrustSortWrapper(a, np, p);
3830#else
3831 ERRMSG("MPTRAC was compiled without Thrust library!");
3832#endif
3833
3834 /* Sort data... */
3835 module_sort_help(atm->time, p, np);
3836 module_sort_help(atm->p, p, np);
3837 module_sort_help(atm->lon, p, np);
3838 module_sort_help(atm->lat, p, np);
3839 for (int iq = 0; iq < ctl->nq; iq++)
3840 module_sort_help(atm->q[iq], p, np);
3841
3842 /* Free... */
3843#ifdef _OPENACC
3844#pragma acc exit data delete(a,p)
3845#endif
3846 free(a);
3847 free(p);
3848}
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:3852
void thrustSortWrapper(double *__restrict__ c, int n, int *__restrict__ index)
Wrapper to Thrust sorting function.
int nq
Number of quantities.
Definition: mptrac.h:2160
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 3852 of file mptrac.c.

3855 {
3856
3857 /* Allocate... */
3858 double *restrict const help =
3859 (double *) malloc((size_t) np * sizeof(double));
3860
3861 /* Reordering of array... */
3862#ifdef _OPENACC
3863#pragma acc enter data create(help[0:np])
3864#pragma acc data present(a,p,help)
3865#pragma acc parallel loop independent gang vector
3866#else
3867#pragma omp parallel for default(shared)
3868#endif
3869 for (int ip = 0; ip < np; ip++)
3870 help[ip] = a[p[ip]];
3871#ifdef _OPENACC
3872#pragma acc parallel loop independent gang vector
3873#else
3874#pragma omp parallel for default(shared)
3875#endif
3876 for (int ip = 0; ip < np; ip++)
3877 a[ip] = help[ip];
3878
3879 /* Free... */
3880#ifdef _OPENACC
3881#pragma acc exit data delete(help)
3882#endif
3883 free(help);
3884}

◆ module_timesteps()

void module_timesteps ( ctl_t ctl,
met_t met0,
atm_t atm,
double *  dt,
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 3888 of file mptrac.c.

3893 {
3894
3895 /* Set timer... */
3896 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
3897
3898 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
3899 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
3900
3901 const int local =
3902 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
3903
3904 /* Loop over particles... */
3905 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,atm,met0,dt)") {
3906
3907 /* Set time step for each air parcel... */
3908 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
3909 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
3910 && ctl->direction * (atm->time[ip] - t) < 0))
3911 dt[ip] = t - atm->time[ip];
3912 else
3913 dt[ip] = 0.0;
3914
3915 /* Check horizontal boundaries of local meteo data... */
3916 if (local && (atm->lon[ip] <= met0->lon[0]
3917 || atm->lon[ip] >= met0->lon[met0->nx - 1]
3918 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
3919 dt[ip] = 0.0;
3920 }
3921}

◆ module_timesteps_init()

void module_timesteps_init ( ctl_t ctl,
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 3925 of file mptrac.c.

3927 {
3928
3929 /* Set timer... */
3930 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
3931
3932 /* Set start time... */
3933 if (ctl->direction == 1) {
3934 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3935 if (ctl->t_stop > 1e99)
3936 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3937 } else {
3938 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3939 if (ctl->t_stop > 1e99)
3940 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3941 }
3942
3943 /* Check time interval... */
3944 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
3945 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
3946
3947 /* Round start time... */
3948 if (ctl->direction == 1)
3949 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
3950 else
3951 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
3952}

◆ module_tracer_chem()

void module_tracer_chem ( ctl_t ctl,
clim_t clim,
met_t met0,
met_t met1,
atm_t atm,
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 3956 of file mptrac.c.

3962 {
3963
3964 /* Set timer... */
3965 SELECT_TIMER("MODULE_TRACERCHEM", "PHYSICS", NVTX_GPU);
3966
3967 /* Loop over particles... */
3968 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,met0,atm,met1,dt)") {
3969
3970 /* Get temperature... */
3971 double t;
3973 INTPOL_3D(t, 1);
3974
3975 /* Get molecular density... */
3976 double M = MOLEC_DENS(atm->p[ip], t);
3977
3978 /* Get total column ozone... */
3979 double o3c;
3980 INTPOL_2D(o3c, 1);
3981
3982 /* Get solar zenith angle... */
3983 double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
3984
3985 /* Get O(1D) volume mixing ratio... */
3986 double o1d = clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
3987
3988 /* Reactions for CFC-10... */
3989 if (ctl->qnt_Cccl4 >= 0) {
3990 double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
3991 double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
3992 atm->p[ip], sza, o3c);
3993 atm->q[ctl->qnt_Cccl4][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
3994 }
3995
3996 /* Reactions for CFC-11... */
3997 if (ctl->qnt_Cccl3f >= 0) {
3998 double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
3999 double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4000 atm->p[ip], sza, o3c);
4001 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
4002 }
4003
4004 /* Reactions for CFC-12... */
4005 if (ctl->qnt_Cccl2f2 >= 0) {
4006 double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4007 double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4008 atm->p[ip], sza, o3c);
4009 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
4010 }
4011
4012 /* Reactions for N2O... */
4013 if (ctl->qnt_Cn2o >= 0) {
4014 double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4015 double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4016 atm->p[ip], sza, o3c);
4017 atm->q[ctl->qnt_Cn2o][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
4018 }
4019 }
4020}
double clim_photo(double rate[CP][CSZA][CO3], clim_photo_t *photo, double p, double sza, double o3c)
Calculates the photolysis rate for a given set of atmospheric conditions.
Definition: mptrac.c:142
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:411
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3152
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3149
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3143
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3146
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3248
Here is the call graph for this function:

◆ module_wet_deposition()

void module_wet_deposition ( ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
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 4024 of file mptrac.c.

4029 {
4030
4031 /* Set timer... */
4032 SELECT_TIMER("MODULE_WETDEPO", "PHYSICS", NVTX_GPU);
4033
4034 /* Check quantity flags... */
4035 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4036 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4037
4038 /* Loop over particles... */
4039 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
4040
4041 /* Check whether particle is below cloud top... */
4042 double pct;
4044 INTPOL_2D(pct, 1);
4045 if (!isfinite(pct) || atm->p[ip] <= pct)
4046 continue;
4047
4048 /* Get cloud bottom pressure... */
4049 double pcb;
4050 INTPOL_2D(pcb, 0);
4051
4052 /* Estimate precipitation rate (Pisso et al., 2019)... */
4053 double cl;
4054 INTPOL_2D(cl, 0);
4055 double Is =
4056 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4057 if (Is < 0.01)
4058 continue;
4059
4060 /* Check whether particle is inside or below cloud... */
4061 double lwc, rwc, iwc, swc;
4062 INTPOL_3D(lwc, 1);
4063 INTPOL_3D(rwc, 0);
4064 INTPOL_3D(iwc, 0);
4065 INTPOL_3D(swc, 0);
4066 int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4067
4068 /* Get temperature... */
4069 double t;
4070 INTPOL_3D(t, 0);
4071
4072 /* Calculate in-cloud scavenging coefficient... */
4073 double lambda = 0;
4074 if (inside) {
4075
4076 /* Calculate retention factor... */
4077 double eta;
4078 if (t > 273.15)
4079 eta = 1;
4080 else if (t <= 238.15)
4081 eta = ctl->wet_depo_ic_ret_ratio;
4082 else
4083 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4084
4085 /* Use exponential dependency for particles ... */
4086 if (ctl->wet_depo_ic_a > 0)
4087 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4088
4089 /* Use Henry's law for gases... */
4090 else if (ctl->wet_depo_ic_h[0] > 0) {
4091
4092 /* Get Henry's constant (Sander, 2015)... */
4093 double h = ctl->wet_depo_ic_h[0]
4094 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4095
4096 /* Use effective Henry's constant for SO2
4097 (Berglen, 2004; Simpson, 2012)... */
4098 if (ctl->wet_depo_ic_h[2] > 0) {
4099 double H_ion = pow(10, ctl->wet_depo_ic_h[2] * (-1));
4100 double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4101 double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4102 h *= (1 + K_1 / H_ion + K_1 * K_2 / pow(H_ion, 2));
4103 }
4104
4105 /* Estimate depth of cloud layer... */
4106 double dz = 1e3 * (Z(pct) - Z(pcb));
4107
4108 /* Calculate scavenging coefficient (Draxler and Hess, 1997)... */
4109 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4110 }
4111 }
4112
4113 /* Calculate below-cloud scavenging coefficient... */
4114 else {
4115
4116 /* Calculate retention factor... */
4117 double eta;
4118 if (t > 270)
4119 eta = 1;
4120 else
4121 eta = ctl->wet_depo_bc_ret_ratio;
4122
4123 /* Use exponential dependency for particles... */
4124 if (ctl->wet_depo_bc_a > 0)
4125 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4126
4127 /* Use Henry's law for gases... */
4128 else if (ctl->wet_depo_bc_h[0] > 0) {
4129
4130 /* Get Henry's constant (Sander, 2015)... */
4131 double h = ctl->wet_depo_bc_h[0]
4132 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4133
4134 /* Estimate depth of cloud layer... */
4135 double dz = 1e3 * (Z(pct) - Z(pcb));
4136
4137 /* Calculate scavenging coefficient (Draxler and Hess, 1997)... */
4138 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4139 }
4140 }
4141
4142 /* Calculate exponential decay of mass... */
4143 double aux = exp(-dt[ip] * lambda);
4144 if (ctl->qnt_m >= 0) {
4145 if (ctl->qnt_mloss_wet >= 0)
4146 atm->q[ctl->qnt_mloss_wet][ip]
4147 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4148 atm->q[ctl->qnt_m][ip] *= aux;
4149 if (ctl->qnt_loss_rate >= 0)
4150 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4151 }
4152 if (ctl->qnt_vmr >= 0)
4153 atm->q[ctl->qnt_vmr][ip] *= aux;
4154 }
4155}
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2814
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2808
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2325
double wet_depo_ic_h[3]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb, pH).
Definition: mptrac.h:2820
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2805
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2823
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2829
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2826
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2817
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2811

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

4162 {
4163
4164 /* Check water vapor volume mixing ratio... */
4165 double h2o_help = MAX(h2o, 0.1e-6);
4166
4167 /* Calculate T_NAT... */
4168 double p_hno3 = hno3 * p / 1.333224;
4169 double p_h2o = h2o_help * p / 1.333224;
4170 double a = 0.009179 - 0.00088 * log10(p_h2o);
4171 double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
4172 double c = -11397.0 / a;
4173 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
4174 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
4175 if (x2 > 0)
4176 tnat = x2;
4177
4178 return tnat;
4179}

◆ read_atm()

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

4186 {
4187
4188 int result;
4189
4190 /* Set timer... */
4191 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
4192
4193 /* Init... */
4194 atm->np = 0;
4195
4196 /* Write info... */
4197 LOG(1, "Read atmospheric data: %s", filename);
4198
4199 /* Read ASCII data... */
4200 if (ctl->atm_type == 0)
4201 result = read_atm_asc(filename, ctl, atm);
4202
4203 /* Read binary data... */
4204 else if (ctl->atm_type == 1)
4205 result = read_atm_bin(filename, ctl, atm);
4206
4207 /* Read netCDF data... */
4208 else if (ctl->atm_type == 2)
4209 result = read_atm_nc(filename, ctl, atm);
4210
4211 /* Read CLaMS data... */
4212 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
4213 result = read_atm_clams(filename, ctl, atm);
4214
4215 /* Error... */
4216 else
4217 ERRMSG("Atmospheric data type not supported!");
4218
4219 /* Check result... */
4220 if (result != 1)
4221 return 0;
4222
4223 /* Check number of air parcels... */
4224 if (atm->np < 1)
4225 ERRMSG("Can not read any data!");
4226
4227 /* Write info... */
4228 double mini, maxi;
4229 LOG(2, "Number of particles: %d", atm->np);
4230 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
4231 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
4232 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
4233 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
4234 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
4235 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
4236 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
4237 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
4238 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
4239 for (int iq = 0; iq < ctl->nq; iq++) {
4240 char msg[5 * LEN];
4241 sprintf(msg, "Quantity %s range: %s ... %s %s",
4242 ctl->qnt_name[iq], ctl->qnt_format[iq],
4243 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
4244 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
4245 LOG(2, msg, mini, maxi);
4246 }
4247
4248 /* Return success... */
4249 return 1;
4250}
int read_atm_nc(const char *filename, ctl_t *ctl, atm_t *atm)
Reads air parcel data from a generic netCDF file and populates the given atmospheric structure.
Definition: mptrac.c:4408
int read_atm_asc(const char *filename, ctl_t *ctl, atm_t *atm)
Reads air parcel data from an ASCII file and populates the given atmospheric structure.
Definition: mptrac.c:4254
int read_atm_clams(const char *filename, ctl_t *ctl, atm_t *atm)
Reads air parcel data from a CLaMS netCDF file and populates the given atmospheric structure.
Definition: mptrac.c:4352
int read_atm_bin(const char *filename, ctl_t *ctl, atm_t *atm)
Reads air parcel data from a binary file and populates the given atmospheric structure.
Definition: mptrac.c:4296
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2172
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:2864
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2169
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2163
Here is the call graph for this function:

◆ read_atm_asc()

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

4257 {
4258
4259 /* Open file... */
4260 FILE *in;
4261 if (!(in = fopen(filename, "r"))) {
4262 WARN("Cannot open file!");
4263 return 0;
4264 }
4265
4266 /* Read line... */
4267 char line[LEN];
4268 while (fgets(line, LEN, in)) {
4269
4270 /* Read data... */
4271 char *tok;
4272 TOK(line, tok, "%lg", atm->time[atm->np]);
4273 TOK(NULL, tok, "%lg", atm->p[atm->np]);
4274 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
4275 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
4276 for (int iq = 0; iq < ctl->nq; iq++)
4277 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
4278
4279 /* Convert altitude to pressure... */
4280 atm->p[atm->np] = P(atm->p[atm->np]);
4281
4282 /* Increment data point counter... */
4283 if ((++atm->np) > NP)
4284 ERRMSG("Too many data points!");
4285 }
4286
4287 /* Close file... */
4288 fclose(in);
4289
4290 /* Return success... */
4291 return 1;
4292}
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1659

◆ read_atm_bin()

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

4299 {
4300
4301 /* Open file... */
4302 FILE *in;
4303 if (!(in = fopen(filename, "r")))
4304 return 0;
4305
4306 /* Check version of binary data... */
4307 int version;
4308 FREAD(&version, int,
4309 1,
4310 in);
4311 if (version != 100)
4312 ERRMSG("Wrong version of binary data!");
4313
4314 /* Read data... */
4315 FREAD(&atm->np, int,
4316 1,
4317 in);
4318 FREAD(atm->time, double,
4319 (size_t) atm->np,
4320 in);
4321 FREAD(atm->p, double,
4322 (size_t) atm->np,
4323 in);
4324 FREAD(atm->lon, double,
4325 (size_t) atm->np,
4326 in);
4327 FREAD(atm->lat, double,
4328 (size_t) atm->np,
4329 in);
4330 for (int iq = 0; iq < ctl->nq; iq++)
4331 FREAD(atm->q[iq], double,
4332 (size_t) atm->np,
4333 in);
4334
4335 /* Read final flag... */
4336 int final;
4337 FREAD(&final, int,
4338 1,
4339 in);
4340 if (final != 999)
4341 ERRMSG("Error while reading binary data!");
4342
4343 /* Close file... */
4344 fclose(in);
4345
4346 /* Return success... */
4347 return 1;
4348}

◆ read_atm_clams()

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

4355 {
4356
4357 int ncid, varid;
4358
4359 /* Open file... */
4360 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
4361 return 0;
4362
4363 /* Get dimensions... */
4364 NC_INQ_DIM("NPARTS", &atm->np, 1, NP);
4365
4366 /* Get time... */
4367 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
4368 NC(nc_get_var_double(ncid, varid, atm->time));
4369 } else {
4370 WARN("TIME_INIT not found use time instead!");
4371 double time_init;
4372 NC_GET_DOUBLE("time", &time_init, 1);
4373 for (int ip = 0; ip < atm->np; ip++) {
4374 atm->time[ip] = time_init;
4375 }
4376 }
4377
4378 /* Read zeta coordinate, pressure is optional... */
4379 if (ctl->advect_vert_coord == 1) {
4380 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
4381 NC_GET_DOUBLE("PRESS", atm->p, 0);
4382 }
4383
4384 /* Read pressure, zeta coordinate is optional... */
4385 else {
4386 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
4387 NC(nc_get_var_double(ncid, varid, atm->p));
4388 } else {
4389 WARN("PRESS_INIT not found use PRESS instead!");
4390 nc_inq_varid(ncid, "PRESS", &varid);
4391 NC(nc_get_var_double(ncid, varid, atm->p));
4392 }
4393 }
4394
4395 /* Read longitude and latitude... */
4396 NC_GET_DOUBLE("LON", atm->lon, 1);
4397 NC_GET_DOUBLE("LAT", atm->lat, 1);
4398
4399 /* Close file... */
4400 NC(nc_close(ncid));
4401
4402 /* Return success... */
4403 return 1;
4404}
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:981
#define NC_INQ_DIM(dimname, ptr, min, max)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1054
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1026

◆ read_atm_nc()

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

4411 {
4412
4413 int ncid, varid;
4414
4415 /* Open file... */
4416 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
4417 return 0;
4418
4419 /* Get dimensions... */
4420 NC_INQ_DIM("obs", &atm->np, 1, NP);
4421
4422 /* Read geolocations... */
4423 NC_GET_DOUBLE("time", atm->time, 1);
4424 NC_GET_DOUBLE("press", atm->p, 1);
4425 NC_GET_DOUBLE("lon", atm->lon, 1);
4426 NC_GET_DOUBLE("lat", atm->lat, 1);
4427
4428 /* Read variables... */
4429 for (int iq = 0; iq < ctl->nq; iq++)
4430 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
4431
4432 /* Close file... */
4433 NC(nc_close(ncid));
4434
4435 /* Return success... */
4436 return 1;
4437}

◆ read_clim()

void read_clim ( 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 4441 of file mptrac.c.

4443 {
4444
4445 /* Set timer... */
4446 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
4447
4448 /* Init tropopause climatology... */
4449 clim_tropo_init(clim);
4450
4451 /* Read photolysis rates... */
4452 if (ctl->clim_photo[0] != '-')
4453 read_clim_photo(ctl->clim_photo, &clim->photo);
4454
4455 /* Read HNO3 climatology... */
4456 if (ctl->clim_hno3_filename[0] != '-')
4457 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
4458
4459 /* Read OH climatology... */
4460 if (ctl->clim_oh_filename[0] != '-') {
4461 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
4462 if (ctl->oh_chem_beta > 0)
4463 clim_oh_diurnal_correction(ctl, clim);
4464 }
4465
4466 /* Read H2O2 climatology... */
4467 if (ctl->clim_h2o2_filename[0] != '-')
4468 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
4469
4470 /* Read HO2 climatology... */
4471 if (ctl->clim_ho2_filename[0] != '-')
4472 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
4473
4474 /* Read O(1D) climatology... */
4475 if (ctl->clim_o1d_filename[0] != '-')
4476 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
4477
4478 /* Read CFC-10 time series... */
4479 if (ctl->clim_ccl4_timeseries[0] != '-')
4481
4482 /* Read CFC-11 time series... */
4483 if (ctl->clim_ccl3f_timeseries[0] != '-')
4485
4486 /* Read CFC-12 time series... */
4487 if (ctl->clim_ccl2f2_timeseries[0] != '-')
4489
4490 /* Read N2O time series... */
4491 if (ctl->clim_n2o_timeseries[0] != '-')
4492 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
4493
4494 /* Read SF6 time series... */
4495 if (ctl->clim_sf6_timeseries[0] != '-')
4496 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
4497}
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:4501
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:4636
void clim_oh_diurnal_correction(ctl_t *ctl, clim_t *clim)
Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data.
Definition: mptrac.c:112
void read_clim_zm(const char *filename, char *varname, clim_zm_t *zm)
Reads zonally averaged climatological data from a netCDF file and populates the given structure.
Definition: mptrac.c:4690
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:221
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2697
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2700
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2685
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2694
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2691
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2688
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 4501 of file mptrac.c.

4503 {
4504
4505 int ncid, varid, ip, is, io;
4506
4507 double *help1, *help2, *help3, *help4;
4508
4509 /* Write info... */
4510 LOG(1, "Read photolysis rates: %s", filename);
4511
4512 /* Open netCDF file... */
4513 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
4514 WARN("Photolysis rate data are missing!");
4515 return;
4516 }
4517
4518 /* Read pressure data... */
4519 NC_INQ_DIM("press", &photo->np, 2, CP);
4520 NC_GET_DOUBLE("press", photo->p, 1);
4521 if (photo->p[0] < photo->p[1])
4522 ERRMSG("Pressure data are not descending!");
4523
4524 /* Read total column ozone data... */
4525 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3);
4526 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
4527 if (photo->o3c[0] > photo->o3c[1])
4528 ERRMSG("Total column ozone data are not ascending!");
4529
4530 /* Read solar zenith angle data... */
4531 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA);
4532 NC_GET_DOUBLE("sza", photo->sza, 1);
4533 if (photo->sza[0] > photo->sza[1])
4534 ERRMSG("Solar zenith angle data are not ascending!");
4535
4536 /* Read data... */
4537 ALLOC(help1, double,
4538 photo->np * photo->nsza * photo->no3c);
4539 ALLOC(help2, double,
4540 photo->np * photo->nsza * photo->no3c);
4541 ALLOC(help3, double,
4542 photo->np * photo->nsza * photo->no3c);
4543 ALLOC(help4, double,
4544 photo->np * photo->nsza * photo->no3c);
4545 NC_GET_DOUBLE("J_N2O", help1, 1);
4546 NC_GET_DOUBLE("J_CCl4", help2, 1);
4547 NC_GET_DOUBLE("J_CFC-11", help3, 1);
4548 NC_GET_DOUBLE("J_CFC-12", help4, 1);
4549 for (ip = 0; ip < photo->np; ip++)
4550 for (is = 0; is < photo->nsza; is++)
4551 for (io = 0; io < photo->no3c; io++) {
4552 photo->n2o[ip][is][io] =
4553 help1[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4554 photo->ccl4[ip][is][io] =
4555 help2[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4556 photo->ccl3f[ip][is][io] =
4557 help3[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4558 photo->ccl2f2[ip][is][io] =
4559 help4[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4560 }
4561
4562 NC_GET_DOUBLE("J_O2", help1, 1);
4563 NC_GET_DOUBLE("J_O3b", help2, 1);
4564 NC_GET_DOUBLE("J_O3a", help3, 1);
4565 NC_GET_DOUBLE("J_H2O2", help4, 1);
4566 for (ip = 0; ip < photo->np; ip++)
4567 for (is = 0; is < photo->nsza; is++)
4568 for (io = 0; io < photo->no3c; io++) {
4569 photo->o2[ip][is][io] =
4570 help1[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4571 photo->o3_1[ip][is][io] =
4572 help2[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4573 photo->o3_2[ip][is][io] =
4574 help3[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4575 photo->h2o2[ip][is][io] =
4576 help4[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4577 }
4578 NC_GET_DOUBLE("J_H2O", help1, 1);
4579 for (ip = 0; ip < photo->np; ip++)
4580 for (is = 0; is < photo->nsza; is++)
4581 for (io = 0; io < photo->no3c; io++)
4582 photo->h2o[ip][is][io] =
4583 help1[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4584 free(help1);
4585 free(help2);
4586 free(help3);
4587 free(help4);
4588
4589 /* Close netCDF file... */
4590 NC(nc_close(ncid));
4591
4592 /* Write info... */
4593 LOG(2, "Number of pressure levels: %d", photo->np);
4594 LOG(2, "Altitude levels: %g, %g ... %g km",
4595 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
4596 LOG(2, "Pressure levels: %g, %g ... %g hPa",
4597 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
4598 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
4599 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
4600 photo->sza[0] * 180. / M_PI, photo->sza[1] * 180. / M_PI,
4601 photo->sza[photo->nsza - 1] * 180. / M_PI);
4602 LOG(2, "Number of total column ozone values: %d", photo->no3c);
4603 LOG(2, "Total column ozone: %g, %g ... %g DU",
4604 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
4605 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
4606 photo->n2o[0][0][0], photo->n2o[1][0][0],
4607 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4608 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
4609 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
4610 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4611 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
4612 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
4613 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4614 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
4615 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
4616 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4617 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
4618 photo->o2[0][0][0], photo->o2[1][0][0],
4619 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4620 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
4621 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
4622 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4623 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
4624 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
4625 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4626 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
4627 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
4628 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4629 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
4630 photo->h2o[0][0][0], photo->h2o[1][0][0],
4631 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4632}
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:296
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:291
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:301
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3158
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3155
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3164
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3167
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3161

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

4638 {
4639
4640 /* Write info... */
4641 LOG(1, "Read climatological time series: %s", filename);
4642
4643 /* Open file... */
4644 FILE *in;
4645 if (!(in = fopen(filename, "r"))) {
4646 WARN("Cannot open file!");
4647 return 0;
4648 }
4649
4650 /* Read data... */
4651 char line[LEN];
4652 int nh = 0;
4653 while (fgets(line, LEN, in))
4654 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
4655
4656 /* Convert years to seconds... */
4657 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
4658
4659 /* Check data... */
4660 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
4661 ERRMSG("Time series must be ascending!");
4662
4663 /* Count time steps... */
4664 if ((++nh) >= CTS)
4665 ERRMSG("Too many data points!");
4666 }
4667
4668 /* Close file... */
4669 fclose(in);
4670
4671 /* Check number of data points... */
4672 ts->ntime = nh;
4673 if (nh < 2)
4674 ERRMSG("Not enough data points!");
4675
4676 /* Write info... */
4677 LOG(2, "Number of time steps: %d", ts->ntime);
4678 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
4679 ts->time[nh - 1]);
4680 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
4681 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
4682 (size_t) nh));
4683
4684 /* Exit success... */
4685 return 1;
4686}
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:311

◆ read_clim_zm()

void read_clim_zm ( const char *  filename,
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 4690 of file mptrac.c.

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

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

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

5574 {
5575
5576 /* Write info... */
5577 LOG(1, "Read kernel function: %s", filename);
5578
5579 /* Open file... */
5580 FILE *in;
5581 if (!(in = fopen(filename, "r")))
5582 ERRMSG("Cannot open file!");
5583
5584 /* Read data... */
5585 char line[LEN];
5586 int n = 0;
5587 while (fgets(line, LEN, in))
5588 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
5589 if (n > 0 && kz[n] < kz[n - 1])
5590 ERRMSG("Height levels must be ascending!");
5591 if ((++n) >= EP)
5592 ERRMSG("Too many height levels!");
5593 }
5594
5595 /* Close file... */
5596 fclose(in);
5597
5598 /* Check number of data points... */
5599 *nk = n;
5600 if (n < 2)
5601 ERRMSG("Not enough height levels!");
5602
5603 /* Normalize kernel function... */
5604 double kmax = gsl_stats_max(kw, 1, (size_t) n);
5605 for (int iz = 0; iz < n; iz++)
5606 kw[iz] /= kmax;
5607}

◆ read_met()

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

Reads meteorological data from a file and populates the provided structures.

This function reads meteorological data from a specified file, populating the provided structures ctl, clim, and met with the parsed data. The function handles both netCDF and binary data formats. For netCDF data, it performs various data processing steps such as reading coordinates, surface data, atmospheric levels, and calculating derived quantities. For binary data, it reads the data directly into the appropriate arrays and structures.

Parameters
filenameA string containing the path to the file containing meteorological data.
ctlA pointer to a structure containing control parameters.
climA pointer to a structure containing climatological data.
metA pointer to a structure to store the meteorological data.
Returns
Returns 1 on success and 0 on failure.

The function performs the following steps:

  • Logs information indicating the meteorological data file being read.
  • Determines the type of meteorological data (netCDF or binary).
  • For netCDF data:
    • Opens the netCDF file and reads various data components including grid coordinates, atmospheric levels, surface data, and derived quantities.
    • Performs data processing steps such as extrapolation, boundary condition handling, downsampling, and calculations of geopotential heights, potential vorticity, boundary layer data, tropopause data, cloud properties, convective available potential energy, total column ozone, and detrending.
    • Checks and adjusts meteorological data as necessary, including monotonicity of vertical coordinates.
    • Closes the netCDF file after reading.
  • For binary data:
    • Opens the binary file and reads metadata including the type and version of the data, time information, dimensions, and grid coordinates.
    • Reads surface data, level data, and final flag from the binary file.
    • Closes the binary file after reading.
  • Copies wind data to a cache for subsequent use.
  • Returns 1 on successful reading and processing of meteorological data.
Note
The function handles different types of meteorological data formats and performs appropriate processing and error checking for each format.
Author
Lars Hoffmann

Definition at line 5611 of file mptrac.c.

5615 {
5616
5617 /* Write info... */
5618 LOG(1, "Read meteo data: %s", filename);
5619
5620 /* Initialize rank... */
5621 int rank = 0;
5622#ifdef MPI
5623 if (ctl->met_mpi_share)
5624 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5625#endif
5626
5627 /* Read netCDF data... */
5628 if (!ctl->met_mpi_share || rank == 0) {
5629 if (ctl->met_type == 0) {
5630
5631 int ncid;
5632
5633 /* Open netCDF file... */
5634 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
5635 WARN("Cannot open file!");
5636 return 0;
5637 }
5638
5639 /* Read coordinates of meteo data... */
5640 read_met_grid(filename, ncid, ctl, met);
5641
5642 /* Read meteo data on vertical levels... */
5643 read_met_levels(ncid, ctl, met);
5644
5645 /* Extrapolate data for lower boundary... */
5647
5648 /* Read surface data... */
5649 read_met_surface(ncid, met, ctl);
5650
5651 /* Fix polar winds... */
5653
5654 /* Create periodic boundary conditions... */
5655 read_met_periodic(met);
5656
5657 /* Downsampling... */
5658 read_met_sample(ctl, met);
5659
5660 /* Calculate geopotential heights... */
5661 read_met_geopot(ctl, met);
5662
5663 /* Calculate potential vorticity... */
5664 read_met_pv(met);
5665
5666 /* Calculate boundary layer data... */
5667 read_met_pbl(met);
5668
5669 /* Calculate tropopause data... */
5670 read_met_tropo(ctl, clim, met);
5671
5672 /* Calculate cloud properties... */
5673 read_met_cloud(met);
5674
5675 /* Calculate convective available potential energy... */
5676 read_met_cape(clim, met);
5677
5678 /* Calculate total column ozone... */
5679 read_met_ozone(met);
5680
5681 /* Detrending... */
5682 read_met_detrend(ctl, met);
5683
5684 /* Check meteo data and smooth zeta profiles ... */
5685 if (ctl->advect_vert_coord == 1)
5687
5688 /* Close file... */
5689 NC(nc_close(ncid));
5690 }
5691
5692 /* Read binary data... */
5693 else if (ctl->met_type >= 1 && ctl->met_type <= 5) {
5694
5695 FILE *in;
5696
5697 double r;
5698
5699 int year, mon, day, hour, min, sec;
5700
5701 /* Set timer... */
5702 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
5703
5704 /* Open file... */
5705 if (!(in = fopen(filename, "r"))) {
5706 WARN("Cannot open file!");
5707 return 0;
5708 }
5709
5710 /* Check type of binary data... */
5711 int met_type;
5712 FREAD(&met_type, int,
5713 1,
5714 in);
5715 if (met_type != ctl->met_type)
5716 ERRMSG("Wrong MET_TYPE of binary data!");
5717
5718 /* Check version of binary data... */
5719 int version;
5720 FREAD(&version, int,
5721 1,
5722 in);
5723 if (version != 100 && version != 101 && version != 102)
5724 ERRMSG("Wrong version of binary data!");
5725
5726 /* Read time... */
5727 FREAD(&met->time, double,
5728 1,
5729 in);
5730 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
5731 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
5732 met->time, year, mon, day, hour, min);
5733 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
5734 || day < 1 || day > 31 || hour < 0 || hour > 23)
5735 ERRMSG("Error while reading time!");
5736
5737 /* Read dimensions... */
5738 FREAD(&met->nx, int,
5739 1,
5740 in);
5741 LOG(2, "Number of longitudes: %d", met->nx);
5742 if (met->nx < 2 || met->nx > EX)
5743 ERRMSG("Number of longitudes out of range!");
5744
5745 FREAD(&met->ny, int,
5746 1,
5747 in);
5748 LOG(2, "Number of latitudes: %d", met->ny);
5749 if (met->ny < 2 || met->ny > EY)
5750 ERRMSG("Number of latitudes out of range!");
5751
5752 FREAD(&met->np, int,
5753 1,
5754 in);
5755 LOG(2, "Number of levels: %d", met->np);
5756 if (met->np < 2 || met->np > EP)
5757 ERRMSG("Number of levels out of range!");
5758
5759 /* Read grid... */
5760 FREAD(met->lon, double,
5761 (size_t) met->nx,
5762 in);
5763 LOG(2, "Longitudes: %g, %g ... %g deg",
5764 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
5765
5766 FREAD(met->lat, double,
5767 (size_t) met->ny,
5768 in);
5769 LOG(2, "Latitudes: %g, %g ... %g deg",
5770 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
5771
5772 FREAD(met->p, double,
5773 (size_t) met->np,
5774 in);
5775 LOG(2, "Altitude levels: %g, %g ... %g km",
5776 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
5777 LOG(2, "Pressure levels: %g, %g ... %g hPa",
5778 met->p[0], met->p[1], met->p[met->np - 1]);
5779
5780 /* Read surface data... */
5781 read_met_bin_2d(in, met, met->ps, "PS");
5782 read_met_bin_2d(in, met, met->ts, "TS");
5783 read_met_bin_2d(in, met, met->zs, "ZS");
5784 read_met_bin_2d(in, met, met->us, "US");
5785 read_met_bin_2d(in, met, met->vs, "VS");
5786 if (version >= 101) {
5787 read_met_bin_2d(in, met, met->lsm, "LSM");
5788 read_met_bin_2d(in, met, met->sst, "SST");
5789 }
5790 read_met_bin_2d(in, met, met->pbl, "PBL");
5791 read_met_bin_2d(in, met, met->pt, "PT");
5792 read_met_bin_2d(in, met, met->tt, "TT");
5793 read_met_bin_2d(in, met, met->zt, "ZT");
5794 read_met_bin_2d(in, met, met->h2ot, "H2OT");
5795 read_met_bin_2d(in, met, met->pct, "PCT");
5796 read_met_bin_2d(in, met, met->pcb, "PCB");
5797 read_met_bin_2d(in, met, met->cl, "CL");
5798 read_met_bin_2d(in, met, met->plcl, "PLCL");
5799 read_met_bin_2d(in, met, met->plfc, "PLFC");
5800 read_met_bin_2d(in, met, met->pel, "PEL");
5801 read_met_bin_2d(in, met, met->cape, "CAPE");
5802 read_met_bin_2d(in, met, met->cin, "CIN");
5803
5804 /* Read level data... */
5805 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
5806 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
5807 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
5808 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
5809 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
5810 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
5811 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
5812 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
5813 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
5814 if (version >= 102)
5815 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
5816 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
5817 if (version >= 102)
5818 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
5819 if (version >= 101)
5820 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
5821
5822 /* Read final flag... */
5823 int final;
5824 FREAD(&final, int,
5825 1,
5826 in);
5827 if (final != 999)
5828 ERRMSG("Error while reading binary data!");
5829
5830 /* Close file... */
5831 fclose(in);
5832 }
5833
5834 /* Not implemented... */
5835 else
5836 ERRMSG("MET_TYPE not implemented!");
5837 }
5838
5839 /* Broadcast data via MPI... */
5840#ifdef MPI
5841 if (ctl->met_mpi_share) {
5842
5843 /* Set timer... */
5844 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
5845 LOG(2, "Broadcast data on rank %d...", rank);
5846
5847 /* Broadcast... */
5848 broadcast_large_data(met, sizeof(met_t));
5849 }
5850#endif
5851
5852 /* Return success... */
5853 return 1;
5854}
void read_met_bin_2d(FILE *in, met_t *met, float var[EX][EY], char *varname)
Reads a 2-dimensional meteorological variable from a binary file and stores it in the provided array.
Definition: mptrac.c:5858
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:6238
void read_met_levels(int ncid, ctl_t *ctl, met_t *met)
Reads meteorological variables at different vertical levels from a NetCDF file.
Definition: mptrac.c:6523
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:6083
void read_met_grid(const char *filename, int ncid, ctl_t *ctl, met_t *met)
Reads meteorological grid information from a NetCDF file.
Definition: mptrac.c:6405
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:7154
void read_met_pbl(met_t *met)
Calculates the planetary boundary layer (PBL) height for each grid point.
Definition: mptrac.c:7083
void read_met_sample(ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:7402
void read_met_monotonize(met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:6708
void read_met_bin_3d(FILE *in, ctl_t *ctl, met_t *met, float var[EX][EY][EP], char *varname, float bound_min, float bound_max)
Reads 3D meteorological data from a binary file, potentially using different compression methods.
Definition: mptrac.c:5887
void read_met_detrend(ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:6134
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:7374
void read_met_surface(int ncid, met_t *met, ctl_t *ctl)
Reads surface meteorological data from a netCDF file and stores it in the meteorological data structu...
Definition: mptrac.c:7550
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:7268
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:7209
void read_met_cape(clim_t *clim, met_t *met)
Calculates Convective Available Potential Energy (CAPE) for each grid point.
Definition: mptrac.c:5973
void read_met_geopot(ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:6278
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:266
void broadcast_large_data(void *data, size_t N)
Broadcasts large data across all processes in an MPI communicator.
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3349
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3337
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3409
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3373
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3355
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3406
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3328
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3418
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3322
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3358
float pel[EX][EY]
Pressure at equilibrium level [hPa].
Definition: mptrac.h:3370
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3376
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3364
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3346
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3340
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3331
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3334
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3412
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3352
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3397
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3361
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3367
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3415
Here is the call graph for this function:

◆ read_met_bin_2d()

void read_met_bin_2d ( FILE *  in,
met_t met,
float  var[EX][EY],
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 5858 of file mptrac.c.

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

◆ read_met_bin_3d()

void read_met_bin_3d ( FILE *  in,
ctl_t ctl,
met_t met,
float  var[EX][EY][EP],
char *  varname,
float  bound_min,
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 5887 of file mptrac.c.

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

◆ read_met_cape()

void read_met_cape ( 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 5973 of file mptrac.c.

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

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

◆ read_met_detrend()

void read_met_detrend ( 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 6134 of file mptrac.c.

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

6239 {
6240
6241 /* Set timer... */
6242 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
6243 LOG(2, "Extrapolate meteo data...");
6244
6245 /* Loop over columns... */
6246#pragma omp parallel for default(shared) collapse(2)
6247 for (int ix = 0; ix < met->nx; ix++)
6248 for (int iy = 0; iy < met->ny; iy++) {
6249
6250 /* Find lowest valid data point... */
6251 int ip0;
6252 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
6253 if (!isfinite(met->t[ix][iy][ip0])
6254 || !isfinite(met->u[ix][iy][ip0])
6255 || !isfinite(met->v[ix][iy][ip0])
6256 || !isfinite(met->w[ix][iy][ip0]))
6257 break;
6258
6259 /* Extrapolate... */
6260 for (int ip = ip0; ip >= 0; ip--) {
6261 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
6262 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
6263 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
6264 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
6265 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
6266 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
6267 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
6268 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
6269 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
6270 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
6271 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
6272 }
6273 }
6274}

◆ read_met_geopot()

void read_met_geopot ( 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 6278 of file mptrac.c.

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

◆ read_met_grid()

void read_met_grid ( const char *  filename,
int  ncid,
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 6405 of file mptrac.c.

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

◆ read_met_levels()

void read_met_levels ( int  ncid,
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 6523 of file mptrac.c.

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

◆ read_met_ml2pl()

void read_met_ml2pl ( ctl_t ctl,
met_t met,
float  var[EX][EY][EP],
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 6666 of file mptrac.c.

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

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

◆ read_met_nc_2d()

int read_met_nc_2d ( int  ncid,
char *  varname,
char *  varname2,
char *  varname3,
char *  varname4,
ctl_t ctl,
met_t met,
float  dest[EX][EY],
float  scl,
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 6787 of file mptrac.c.

6797 {
6798
6799 char varsel[LEN];
6800
6801 float offset, scalfac;
6802
6803 int varid;
6804
6805 /* Check if variable exists... */
6806 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
6807 sprintf(varsel, "%s", varname);
6808 else if (varname2 != NULL
6809 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
6810 sprintf(varsel, "%s", varname2);
6811 else if (varname3 != NULL
6812 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
6813 sprintf(varsel, "%s", varname3);
6814 else if (varname4 != NULL
6815 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
6816 sprintf(varsel, "%s", varname4);
6817 else
6818 return 0;
6819
6820 /* Read packed data... */
6821 if (ctl->met_nc_scale
6822 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
6823 && nc_get_att_float(ncid, varid, "scale_factor",
6824 &scalfac) == NC_NOERR) {
6825
6826 /* Allocate... */
6827 short *help;
6828 ALLOC(help, short,
6829 EX * EY * EP);
6830
6831 /* Read fill value and missing value... */
6832 short fillval, missval;
6833 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
6834 fillval = 0;
6835 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
6836 missval = 0;
6837
6838 /* Write info... */
6839 LOG(2, "Read 2-D variable: %s"
6840 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
6841 varsel, fillval, missval, scalfac, offset);
6842
6843 /* Read data... */
6844 NC(nc_get_var_short(ncid, varid, help));
6845
6846 /* Check meteo data layout... */
6847 if (ctl->met_convention != 0)
6848 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
6849
6850 /* Copy and check data... */
6851#pragma omp parallel for default(shared) num_threads(12)
6852 for (int ix = 0; ix < met->nx; ix++)
6853 for (int iy = 0; iy < met->ny; iy++) {
6854 if (init)
6855 dest[ix][iy] = 0;
6856 short aux = help[ARRAY_2D(iy, ix, met->nx)];
6857 if ((fillval == 0 || aux != fillval)
6858 && (missval == 0 || aux != missval)
6859 && fabsf(aux * scalfac + offset) < 1e14f)
6860 dest[ix][iy] += scl * (aux * scalfac + offset);
6861 else
6862 dest[ix][iy] = NAN;
6863 }
6864
6865 /* Free... */
6866 free(help);
6867 }
6868
6869 /* Unpacked data... */
6870 else {
6871
6872 /* Allocate... */
6873 float *help;
6874 ALLOC(help, float,
6875 EX * EY);
6876
6877 /* Read fill value and missing value... */
6878 float fillval, missval;
6879 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
6880 fillval = 0;
6881 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
6882 missval = 0;
6883
6884 /* Write info... */
6885 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
6886 varsel, fillval, missval);
6887
6888 /* Read data... */
6889 NC(nc_get_var_float(ncid, varid, help));
6890
6891 /* Check meteo data layout... */
6892 if (ctl->met_convention == 0) {
6893
6894 /* Copy and check data (ordering: lat, lon)... */
6895#pragma omp parallel for default(shared) num_threads(12)
6896 for (int ix = 0; ix < met->nx; ix++)
6897 for (int iy = 0; iy < met->ny; iy++) {
6898 if (init)
6899 dest[ix][iy] = 0;
6900 float aux = help[ARRAY_2D(iy, ix, met->nx)];
6901 if ((fillval == 0 || aux != fillval)
6902 && (missval == 0 || aux != missval)
6903 && fabsf(aux) < 1e14f)
6904 dest[ix][iy] += scl * aux;
6905 else
6906 dest[ix][iy] = NAN;
6907 }
6908
6909 } else {
6910
6911 /* Copy and check data (ordering: lon, lat)... */
6912#pragma omp parallel for default(shared) num_threads(12)
6913 for (int iy = 0; iy < met->ny; iy++)
6914 for (int ix = 0; ix < met->nx; ix++) {
6915 if (init)
6916 dest[ix][iy] = 0;
6917 float aux = help[ARRAY_2D(ix, iy, met->ny)];
6918 if ((fillval == 0 || aux != fillval)
6919 && (missval == 0 || aux != missval)
6920 && fabsf(aux) < 1e14f)
6921 dest[ix][iy] += scl * aux;
6922 else
6923 dest[ix][iy] = NAN;
6924 }
6925 }
6926
6927 /* Free... */
6928 free(help);
6929 }
6930
6931 /* Return... */
6932 return 1;
6933}
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2468
int met_convention
Meteo data layout (0=[lev, lat, lon], 1 = [lon, lat, lev]).
Definition: mptrac.h:2461

◆ read_met_nc_3d()

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

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

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

Parameters
ncidThe NetCDF file ID.
varnameThe name of the variable to read.
varname2An alternative name of the variable to read (in case varname is not found).
varname3An alternative name of the variable to read (in case varname2 is not found).
varname4An alternative name of the variable to read (in case varname3 is not found).
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.
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 6937 of file mptrac.c.

6946 {
6947
6948 char varsel[LEN];
6949
6950 float offset, scalfac;
6951
6952 int varid;
6953
6954 /* Check if variable exists... */
6955 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
6956 sprintf(varsel, "%s", varname);
6957 else if (varname2 != NULL
6958 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
6959 sprintf(varsel, "%s", varname2);
6960 else if (varname3 != NULL
6961 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
6962 sprintf(varsel, "%s", varname3);
6963 else if (varname4 != NULL
6964 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
6965 sprintf(varsel, "%s", varname4);
6966 else
6967 return 0;
6968
6969 /* Read packed data... */
6970 if (ctl->met_nc_scale
6971 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
6972 && nc_get_att_float(ncid, varid, "scale_factor",
6973 &scalfac) == NC_NOERR) {
6974
6975 /* Allocate... */
6976 short *help;
6977 ALLOC(help, short,
6978 EX * EY * EP);
6979
6980 /* Read fill value and missing value... */
6981 short fillval, missval;
6982 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
6983 fillval = 0;
6984 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
6985 missval = 0;
6986
6987 /* Write info... */
6988 LOG(2, "Read 3-D variable: %s "
6989 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
6990 varsel, fillval, missval, scalfac, offset);
6991
6992 /* Read data... */
6993 NC(nc_get_var_short(ncid, varid, help));
6994
6995 /* Check meteo data layout... */
6996 if (ctl->met_convention != 0)
6997 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
6998
6999 /* Copy and check data... */
7000#pragma omp parallel for default(shared) num_threads(12)
7001 for (int ix = 0; ix < met->nx; ix++)
7002 for (int iy = 0; iy < met->ny; iy++)
7003 for (int ip = 0; ip < met->np; ip++) {
7004 short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7005 if ((fillval == 0 || aux != fillval)
7006 && (missval == 0 || aux != missval)
7007 && fabsf(aux * scalfac + offset) < 1e14f)
7008 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
7009 else
7010 dest[ix][iy][ip] = NAN;
7011 }
7012
7013 /* Free... */
7014 free(help);
7015 }
7016
7017 /* Unpacked data... */
7018 else {
7019
7020 /* Allocate... */
7021 float *help;
7022 ALLOC(help, float,
7023 EX * EY * EP);
7024
7025 /* Read fill value and missing value... */
7026 float fillval, missval;
7027 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7028 fillval = 0;
7029 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7030 missval = 0;
7031
7032 /* Write info... */
7033 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
7034 varsel, fillval, missval);
7035
7036 /* Read data... */
7037 NC(nc_get_var_float(ncid, varid, help));
7038
7039 /* Check meteo data layout... */
7040 if (ctl->met_convention == 0) {
7041
7042 /* Copy and check data (ordering: lev, lat, lon)... */
7043#pragma omp parallel for default(shared) num_threads(12)
7044 for (int ix = 0; ix < met->nx; ix++)
7045 for (int iy = 0; iy < met->ny; iy++)
7046 for (int ip = 0; ip < met->np; ip++) {
7047 float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7048 if ((fillval == 0 || aux != fillval)
7049 && (missval == 0 || aux != missval)
7050 && fabsf(aux) < 1e14f)
7051 dest[ix][iy][ip] = scl * aux;
7052 else
7053 dest[ix][iy][ip] = NAN;
7054 }
7055
7056 } else {
7057
7058 /* Copy and check data (ordering: lon, lat, lev)... */
7059#pragma omp parallel for default(shared) num_threads(12)
7060 for (int ip = 0; ip < met->np; ip++)
7061 for (int iy = 0; iy < met->ny; iy++)
7062 for (int ix = 0; ix < met->nx; ix++) {
7063 float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7064 if ((fillval == 0 || aux != fillval)
7065 && (missval == 0 || aux != missval)
7066 && fabsf(aux) < 1e14f)
7067 dest[ix][iy][ip] = scl * aux;
7068 else
7069 dest[ix][iy][ip] = NAN;
7070 }
7071 }
7072
7073 /* Free... */
7074 free(help);
7075 }
7076
7077 /* Return... */
7078 return 1;
7079}

◆ read_met_pbl()

void read_met_pbl ( met_t met)

Calculates the planetary boundary layer (PBL) height for each grid point.

This function estimates the height of the planetary boundary layer (PBL) based on various meteorological parameters. The method used is based on empirical relationships, such as those proposed by Vogelezang and Holtslag (1996) or Seidel et al. (2012). It computes the PBL height by analyzing the vertical profiles of temperature, wind speed, humidity, and pressure.

Parameters
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets timer for performance monitoring.
  • Iterates over each grid point to calculate the PBL height.
  • Determines the bottom level of the PBL based on pressure and a specified thickness.
  • Finds the lowest model level near the bottom of the PBL.
  • Interpolates meteorological variables to the near-surface level.
  • Computes virtual potential temperature (theta_v) at the surface.
  • Initializes variables for Richardson number calculation.
  • Loops over vertical levels to calculate Richardson number and identify the PBL height.
  • Determines the PBL height based on the critical Richardson number criterion.
  • Stores the calculated PBL height in the meteorological data structure.
Note
This function plays a crucial role in atmospheric modeling applications for characterizing the height of the boundary layer, which influences atmospheric dynamics and pollutant dispersion.
Author
Lars Hoffmann

Definition at line 7083 of file mptrac.c.

7084 {
7085
7086 /* Set timer... */
7087 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
7088 LOG(2, "Calculate planetary boundary layer...");
7089
7090 /* Parameters used to estimate the height of the PBL
7091 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
7092 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
7093
7094 /* Loop over grid points... */
7095#pragma omp parallel for default(shared) collapse(2)
7096 for (int ix = 0; ix < met->nx; ix++)
7097 for (int iy = 0; iy < met->ny; iy++) {
7098
7099 /* Set bottom level of PBL... */
7100 double pbl_bot = met->ps[ix][iy] + DZ2DP(dz, met->ps[ix][iy]);
7101
7102 /* Find lowest level near the bottom... */
7103 int ip;
7104 for (ip = 1; ip < met->np; ip++)
7105 if (met->p[ip] < pbl_bot)
7106 break;
7107
7108 /* Get near surface data... */
7109 double zs = LIN(met->p[ip - 1], met->z[ix][iy][ip - 1],
7110 met->p[ip], met->z[ix][iy][ip], pbl_bot);
7111 double ts = LIN(met->p[ip - 1], met->t[ix][iy][ip - 1],
7112 met->p[ip], met->t[ix][iy][ip], pbl_bot);
7113 double us = LIN(met->p[ip - 1], met->u[ix][iy][ip - 1],
7114 met->p[ip], met->u[ix][iy][ip], pbl_bot);
7115 double vs = LIN(met->p[ip - 1], met->v[ix][iy][ip - 1],
7116 met->p[ip], met->v[ix][iy][ip], pbl_bot);
7117 double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
7118 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
7119 double tvs = THETAVIRT(pbl_bot, ts, h2os);
7120
7121 /* Init... */
7122 double rib_old = 0;
7123
7124 /* Loop over levels... */
7125 for (; ip < met->np; ip++) {
7126
7127 /* Get squared horizontal wind speed... */
7128 double vh2
7129 = SQR(met->u[ix][iy][ip] - us) + SQR(met->v[ix][iy][ip] - vs);
7130 vh2 = MAX(vh2, SQR(umin));
7131
7132 /* Calculate bulk Richardson number... */
7133 double rib = G0 * 1e3 * (met->z[ix][iy][ip] - zs) / tvs
7134 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
7135 met->h2o[ix][iy][ip]) - tvs) / vh2;
7136
7137 /* Check for critical value... */
7138 if (rib >= rib_crit) {
7139 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
7140 rib, met->p[ip], rib_crit));
7141 if (met->pbl[ix][iy] > pbl_bot)
7142 met->pbl[ix][iy] = (float) pbl_bot;
7143 break;
7144 }
7145
7146 /* Save Richardson number... */
7147 rib_old = rib;
7148 }
7149 }
7150}
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1638

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

7155 {
7156
7157 /* Set timer... */
7158 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
7159 LOG(2, "Apply periodic boundary conditions...");
7160
7161 /* Check longitudes... */
7162 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
7163 + met->lon[1] - met->lon[0] - 360) < 0.01))
7164 return;
7165
7166 /* Increase longitude counter... */
7167 if ((++met->nx) >= EX)
7168 ERRMSG("Cannot create periodic boundary conditions!");
7169
7170 /* Set longitude... */
7171 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
7172
7173 /* Loop over latitudes and pressure levels... */
7174#pragma omp parallel for default(shared)
7175 for (int iy = 0; iy < met->ny; iy++) {
7176 met->ps[met->nx - 1][iy] = met->ps[0][iy];
7177 met->zs[met->nx - 1][iy] = met->zs[0][iy];
7178 met->ts[met->nx - 1][iy] = met->ts[0][iy];
7179 met->us[met->nx - 1][iy] = met->us[0][iy];
7180 met->vs[met->nx - 1][iy] = met->vs[0][iy];
7181 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
7182 met->sst[met->nx - 1][iy] = met->sst[0][iy];
7183 for (int ip = 0; ip < met->np; ip++) {
7184 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
7185 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
7186 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
7187 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
7188 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
7189 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
7190 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
7191 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
7192 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
7193 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
7194 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
7195 }
7196 for (int ip = 0; ip < met->npl; ip++) {
7197 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
7198 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
7199 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
7200 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
7201 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
7202 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
7203 }
7204 }
7205}

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

7210 {
7211
7212 /* Set timer... */
7213 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
7214 LOG(2, "Apply fix for polar winds...");
7215
7216 /* Check latitudes... */
7217 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
7218 return;
7219
7220 /* Loop over hemispheres... */
7221 for (int ihem = 0; ihem < 2; ihem++) {
7222
7223 /* Set latitude indices... */
7224 int i89 = 1, i90 = 0, sign = 1;
7225 if (ihem == 1) {
7226 i89 = met->ny - 2;
7227 i90 = met->ny - 1;
7228 }
7229 if (met->lat[i90] < 0)
7230 sign = -1;
7231
7232 /* Look-up table of cosinus and sinus... */
7233 double clon[EX], slon[EX];
7234#pragma omp parallel for default(shared)
7235 for (int ix = 0; ix < met->nx; ix++) {
7236 clon[ix] = cos(sign * met->lon[ix] / 180. * M_PI);
7237 slon[ix] = sin(sign * met->lon[ix] / 180. * M_PI);
7238 }
7239
7240 /* Loop over levels... */
7241#pragma omp parallel for default(shared)
7242 for (int ip = 0; ip < met->np; ip++) {
7243
7244 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
7245 double vel89x = 0, vel89y = 0;
7246 for (int ix = 0; ix < met->nx; ix++) {
7247 vel89x +=
7248 (met->u[ix][i89][ip] * clon[ix] -
7249 met->v[ix][i89][ip] * slon[ix]) / met->nx;
7250 vel89y +=
7251 (met->u[ix][i89][ip] * slon[ix] +
7252 met->v[ix][i89][ip] * clon[ix]) / met->nx;
7253 }
7254
7255 /* Replace 90 degree winds by 89 degree mean... */
7256 for (int ix = 0; ix < met->nx; ix++) {
7257 met->u[ix][i90][ip]
7258 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
7259 met->v[ix][i90][ip]
7260 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
7261 }
7262 }
7263 }
7264}

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

7269 {
7270
7271 double pows[EP];
7272
7273 /* Set timer... */
7274 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
7275 LOG(2, "Calculate potential vorticity...");
7276
7277 /* Set powers... */
7278#pragma omp parallel for default(shared)
7279 for (int ip = 0; ip < met->np; ip++)
7280 pows[ip] = pow(1000. / met->p[ip], 0.286);
7281
7282 /* Loop over grid points... */
7283#pragma omp parallel for default(shared)
7284 for (int ix = 0; ix < met->nx; ix++) {
7285
7286 /* Set indices... */
7287 int ix0 = MAX(ix - 1, 0);
7288 int ix1 = MIN(ix + 1, met->nx - 1);
7289
7290 /* Loop over grid points... */
7291 for (int iy = 0; iy < met->ny; iy++) {
7292
7293 /* Set indices... */
7294 int iy0 = MAX(iy - 1, 0);
7295 int iy1 = MIN(iy + 1, met->ny - 1);
7296
7297 /* Set auxiliary variables... */
7298 double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
7299 double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
7300 double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
7301 double c0 = cos(met->lat[iy0] / 180. * M_PI);
7302 double c1 = cos(met->lat[iy1] / 180. * M_PI);
7303 double cr = cos(latr / 180. * M_PI);
7304 double vort = 2 * 7.2921e-5 * sin(latr * M_PI / 180.);
7305
7306 /* Loop over grid points... */
7307 for (int ip = 0; ip < met->np; ip++) {
7308
7309 /* Get gradients in longitude... */
7310 double dtdx
7311 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
7312 double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
7313
7314 /* Get gradients in latitude... */
7315 double dtdy
7316 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
7317 double dudy
7318 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
7319
7320 /* Set indices... */
7321 int ip0 = MAX(ip - 1, 0);
7322 int ip1 = MIN(ip + 1, met->np - 1);
7323
7324 /* Get gradients in pressure... */
7325 double dtdp, dudp, dvdp;
7326 double dp0 = 100. * (met->p[ip] - met->p[ip0]);
7327 double dp1 = 100. * (met->p[ip1] - met->p[ip]);
7328 if (ip != ip0 && ip != ip1) {
7329 double denom = dp0 * dp1 * (dp0 + dp1);
7330 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
7331 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
7332 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
7333 / denom;
7334 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
7335 - dp1 * dp1 * met->u[ix][iy][ip0]
7336 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
7337 / denom;
7338 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
7339 - dp1 * dp1 * met->v[ix][iy][ip0]
7340 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
7341 / denom;
7342 } else {
7343 double denom = dp0 + dp1;
7344 dtdp =
7345 (met->t[ix][iy][ip1] * pows[ip1] -
7346 met->t[ix][iy][ip0] * pows[ip0]) / denom;
7347 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
7348 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
7349 }
7350
7351 /* Calculate PV... */
7352 met->pv[ix][iy][ip] = (float)
7353 (1e6 * G0 *
7354 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
7355 }
7356 }
7357 }
7358
7359 /* Fix for polar regions... */
7360#pragma omp parallel for default(shared)
7361 for (int ix = 0; ix < met->nx; ix++)
7362 for (int ip = 0; ip < met->np; ip++) {
7363 met->pv[ix][0][ip]
7364 = met->pv[ix][1][ip]
7365 = met->pv[ix][2][ip];
7366 met->pv[ix][met->ny - 1][ip]
7367 = met->pv[ix][met->ny - 2][ip]
7368 = met->pv[ix][met->ny - 3][ip];
7369 }
7370}
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:456
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:435

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

7375 {
7376
7377 /* Set timer... */
7378 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
7379 LOG(2, "Calculate total column ozone...");
7380
7381 /* Loop over columns... */
7382#pragma omp parallel for default(shared) collapse(2)
7383 for (int ix = 0; ix < met->nx; ix++)
7384 for (int iy = 0; iy < met->ny; iy++) {
7385
7386 /* Integrate... */
7387 double cd = 0;
7388 for (int ip = 1; ip < met->np; ip++)
7389 if (met->p[ip - 1] <= met->ps[ix][iy]) {
7390 double vmr = 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
7391 double dp = met->p[ip - 1] - met->p[ip];
7392 cd += vmr * MO3 / MA * dp * 1e2 / G0;
7393 }
7394
7395 /* Convert to Dobson units... */
7396 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
7397 }
7398}
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3379

◆ read_met_sample()

void read_met_sample ( 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 7402 of file mptrac.c.

7404 {
7405
7406 met_t *help;
7407
7408 /* Check parameters... */
7409 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
7410 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
7411 return;
7412
7413 /* Set timer... */
7414 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
7415 LOG(2, "Downsampling of meteo data...");
7416
7417 /* Allocate... */
7418 ALLOC(help, met_t, 1);
7419
7420 /* Copy data... */
7421 help->nx = met->nx;
7422 help->ny = met->ny;
7423 help->np = met->np;
7424 memcpy(help->lon, met->lon, sizeof(met->lon));
7425 memcpy(help->lat, met->lat, sizeof(met->lat));
7426 memcpy(help->p, met->p, sizeof(met->p));
7427
7428 /* Smoothing... */
7429 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
7430 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
7431 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
7432 help->ps[ix][iy] = 0;
7433 help->zs[ix][iy] = 0;
7434 help->ts[ix][iy] = 0;
7435 help->us[ix][iy] = 0;
7436 help->vs[ix][iy] = 0;
7437 help->lsm[ix][iy] = 0;
7438 help->sst[ix][iy] = 0;
7439 help->t[ix][iy][ip] = 0;
7440 help->u[ix][iy][ip] = 0;
7441 help->v[ix][iy][ip] = 0;
7442 help->w[ix][iy][ip] = 0;
7443 help->h2o[ix][iy][ip] = 0;
7444 help->o3[ix][iy][ip] = 0;
7445 help->lwc[ix][iy][ip] = 0;
7446 help->rwc[ix][iy][ip] = 0;
7447 help->iwc[ix][iy][ip] = 0;
7448 help->swc[ix][iy][ip] = 0;
7449 help->cc[ix][iy][ip] = 0;
7450 float wsum = 0;
7451 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
7452 ix2++) {
7453 int ix3 = ix2;
7454 if (ix3 < 0)
7455 ix3 += met->nx;
7456 else if (ix3 >= met->nx)
7457 ix3 -= met->nx;
7458
7459 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
7460 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
7461 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
7462 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
7463 float w = (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
7464 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
7465 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
7466 help->ps[ix][iy] += w * met->ps[ix3][iy2];
7467 help->zs[ix][iy] += w * met->zs[ix3][iy2];
7468 help->ts[ix][iy] += w * met->ts[ix3][iy2];
7469 help->us[ix][iy] += w * met->us[ix3][iy2];
7470 help->vs[ix][iy] += w * met->vs[ix3][iy2];
7471 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
7472 help->sst[ix][iy] += w * met->sst[ix3][iy2];
7473 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
7474 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
7475 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
7476 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
7477 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
7478 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
7479 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
7480 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
7481 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
7482 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
7483 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
7484 wsum += w;
7485 }
7486 }
7487 help->ps[ix][iy] /= wsum;
7488 help->zs[ix][iy] /= wsum;
7489 help->ts[ix][iy] /= wsum;
7490 help->us[ix][iy] /= wsum;
7491 help->vs[ix][iy] /= wsum;
7492 help->lsm[ix][iy] /= wsum;
7493 help->sst[ix][iy] /= wsum;
7494 help->t[ix][iy][ip] /= wsum;
7495 help->u[ix][iy][ip] /= wsum;
7496 help->v[ix][iy][ip] /= wsum;
7497 help->w[ix][iy][ip] /= wsum;
7498 help->h2o[ix][iy][ip] /= wsum;
7499 help->o3[ix][iy][ip] /= wsum;
7500 help->lwc[ix][iy][ip] /= wsum;
7501 help->rwc[ix][iy][ip] /= wsum;
7502 help->iwc[ix][iy][ip] /= wsum;
7503 help->swc[ix][iy][ip] /= wsum;
7504 help->cc[ix][iy][ip] /= wsum;
7505 }
7506 }
7507 }
7508
7509 /* Downsampling... */
7510 met->nx = 0;
7511 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
7512 met->lon[met->nx] = help->lon[ix];
7513 met->ny = 0;
7514 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
7515 met->lat[met->ny] = help->lat[iy];
7516 met->ps[met->nx][met->ny] = help->ps[ix][iy];
7517 met->zs[met->nx][met->ny] = help->zs[ix][iy];
7518 met->ts[met->nx][met->ny] = help->ts[ix][iy];
7519 met->us[met->nx][met->ny] = help->us[ix][iy];
7520 met->vs[met->nx][met->ny] = help->vs[ix][iy];
7521 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
7522 met->sst[met->nx][met->ny] = help->sst[ix][iy];
7523 met->np = 0;
7524 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
7525 met->p[met->np] = help->p[ip];
7526 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
7527 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
7528 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
7529 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
7530 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
7531 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
7532 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
7533 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
7534 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
7535 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
7536 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
7537 met->np++;
7538 }
7539 met->ny++;
7540 }
7541 met->nx++;
7542 }
7543
7544 /* Free... */
7545 free(help);
7546}
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2529
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2535
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2532
int met_dx
Stride for longitudes.
Definition: mptrac.h:2523
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2538
int met_dy
Stride for latitudes.
Definition: mptrac.h:2526

◆ read_met_surface()

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

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

7553 {
7554
7555 /* Set timer... */
7556 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
7557 LOG(2, "Read surface data...");
7558
7559 /* MPTRAC meteo data... */
7560 if (ctl->met_clams == 0) {
7561
7562 /* Read surface pressure... */
7563 if (read_met_nc_2d
7564 (ncid, "lnsp", "LNSP", NULL, NULL, ctl, met, met->ps, 1.0f, 1)) {
7565 for (int ix = 0; ix < met->nx; ix++)
7566 for (int iy = 0; iy < met->ny; iy++)
7567 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
7568 } else
7569 if (!read_met_nc_2d
7570 (ncid, "ps", "PS", "sp", "SP", ctl, met, met->ps, 0.01f, 1)) {
7571 WARN("Cannot not read surface pressure data (use lowest level)!");
7572 for (int ix = 0; ix < met->nx; ix++)
7573 for (int iy = 0; iy < met->ny; iy++)
7574 met->ps[ix][iy] = (float) met->p[0];
7575 }
7576
7577 /* Read geopotential height at the surface... */
7578 if (!read_met_nc_2d
7579 (ncid, "z", "Z", NULL, NULL, ctl, met, met->zs,
7580 (float) (1. / (1000. * G0)), 1))
7581 if (!read_met_nc_2d
7582 (ncid, "zm", "ZM", NULL, NULL, ctl, met, met->zs,
7583 (float) (1. / 1000.), 1))
7584 WARN("Cannot read surface geopotential height!");
7585
7586 /* Read temperature at the surface... */
7587 if (!read_met_nc_2d
7588 (ncid, "t2m", "T2M", "2t", "2T", ctl, met, met->ts, 1.0, 1))
7589 WARN("Cannot read surface temperature!");
7590
7591 /* Read zonal wind at the surface... */
7592 if (!read_met_nc_2d
7593 (ncid, "u10m", "U10M", "10u", "10U", ctl, met, met->us, 1.0, 1))
7594 WARN("Cannot read surface zonal wind!");
7595
7596 /* Read meridional wind at the surface... */
7597 if (!read_met_nc_2d
7598 (ncid, "v10m", "V10M", "10v", "10V", ctl, met, met->vs, 1.0, 1))
7599 WARN("Cannot read surface meridional wind!");
7600
7601 /* Read land-sea mask... */
7602 if (!read_met_nc_2d
7603 (ncid, "lsm", "LSM", NULL, NULL, ctl, met, met->lsm, 1.0, 1))
7604 WARN("Cannot read land-sea mask!");
7605
7606 /* Read sea surface temperature... */
7607 if (!read_met_nc_2d
7608 (ncid, "sstk", "SSTK", "sst", "SST", ctl, met, met->sst, 1.0, 1))
7609 WARN("Cannot read sea surface temperature!");
7610 }
7611
7612 /* CLaMS meteo data... */
7613 else {
7614
7615 /* Read surface pressure... */
7616 if (!read_met_nc_2d
7617 (ncid, "ps", "PS", NULL, NULL, ctl, met, met->ps, 0.01f, 1)) {
7618 WARN("Cannot not read surface pressure data (use lowest level)!");
7619 for (int ix = 0; ix < met->nx; ix++)
7620 for (int iy = 0; iy < met->ny; iy++)
7621 met->ps[ix][iy] = (float) met->p[0];
7622 }
7623
7624 /* Read geopotential height at the surface
7625 (use lowermost level of 3-D data field)... */
7626 float *help;
7627 ALLOC(help, float,
7628 EX * EY * EP);
7629 memcpy(help, met->pl, sizeof(met->pl));
7630 if (!read_met_nc_3d
7631 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
7632 (float) (1e-3 / G0))) {
7633 ERRMSG("Cannot read geopotential height!");
7634 } else
7635 for (int ix = 0; ix < met->nx; ix++)
7636 for (int iy = 0; iy < met->ny; iy++)
7637 met->zs[ix][iy] = met->pl[ix][iy][0];
7638 memcpy(met->pl, help, sizeof(met->pl));
7639 free(help);
7640
7641 /* Read temperature at the surface... */
7642 if (!read_met_nc_2d
7643 (ncid, "t2", "T2", NULL, NULL, ctl, met, met->ts, 1.0, 1))
7644 WARN("Cannot read surface temperature!");
7645
7646 /* Read zonal wind at the surface... */
7647 if (!read_met_nc_2d
7648 (ncid, "u10", "U10", NULL, NULL, ctl, met, met->us, 1.0, 1))
7649 WARN("Cannot read surface zonal wind!");
7650
7651 /* Read meridional wind at the surface... */
7652 if (!read_met_nc_2d
7653 (ncid, "v10", "V10", NULL, NULL, ctl, met, met->vs, 1.0, 1))
7654 WARN("Cannot read surface meridional wind!");
7655
7656 /* Read land-sea mask... */
7657 if (!read_met_nc_2d
7658 (ncid, "lsm", "LSM", NULL, NULL, ctl, met, met->lsm, 1.0, 1))
7659 WARN("Cannot read land-sea mask!");
7660
7661 /* Read sea surface temperature... */
7662 if (!read_met_nc_2d
7663 (ncid, "sstk", "SSTK", NULL, NULL, ctl, met, met->sst, 1.0, 1))
7664 WARN("Cannot read sea surface temperature!");
7665 }
7666}
int read_met_nc_2d(int ncid, char *varname, char *varname2, char *varname3, char *varname4, ctl_t *ctl, met_t *met, float dest[EX][EY], float scl, int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:6787
Here is the call graph for this function:

◆ read_met_tropo()

void read_met_tropo ( ctl_t ctl,
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 7670 of file mptrac.c.

7673 {
7674
7675 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
7676 th2[200], z[EP], z2[200];
7677
7678 /* Set timer... */
7679 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
7680 LOG(2, "Calculate tropopause...");
7681
7682 /* Get altitude and pressure profiles... */
7683#pragma omp parallel for default(shared)
7684 for (int iz = 0; iz < met->np; iz++)
7685 z[iz] = Z(met->p[iz]);
7686#pragma omp parallel for default(shared)
7687 for (int iz = 0; iz <= 190; iz++) {
7688 z2[iz] = 4.5 + 0.1 * iz;
7689 p2[iz] = P(z2[iz]);
7690 }
7691
7692 /* Do not calculate tropopause... */
7693 if (ctl->met_tropo == 0)
7694#pragma omp parallel for default(shared) collapse(2)
7695 for (int ix = 0; ix < met->nx; ix++)
7696 for (int iy = 0; iy < met->ny; iy++)
7697 met->pt[ix][iy] = NAN;
7698
7699 /* Use tropopause climatology... */
7700 else if (ctl->met_tropo == 1) {
7701#pragma omp parallel for default(shared) collapse(2)
7702 for (int ix = 0; ix < met->nx; ix++)
7703 for (int iy = 0; iy < met->ny; iy++)
7704 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
7705 }
7706
7707 /* Use cold point... */
7708 else if (ctl->met_tropo == 2) {
7709
7710 /* Loop over grid points... */
7711#pragma omp parallel for default(shared) private(t,t2) collapse(2)
7712 for (int ix = 0; ix < met->nx; ix++)
7713 for (int iy = 0; iy < met->ny; iy++) {
7714
7715 /* Interpolate temperature profile... */
7716 for (int iz = 0; iz < met->np; iz++)
7717 t[iz] = met->t[ix][iy][iz];
7718 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
7719
7720 /* Find minimum... */
7721 int iz = (int) gsl_stats_min_index(t2, 1, 171);
7722 if (iz > 0 && iz < 170)
7723 met->pt[ix][iy] = (float) p2[iz];
7724 else
7725 met->pt[ix][iy] = NAN;
7726 }
7727 }
7728
7729 /* Use WMO definition... */
7730 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
7731
7732 /* Loop over grid points... */
7733#pragma omp parallel for default(shared) private(t,t2) collapse(2)
7734 for (int ix = 0; ix < met->nx; ix++)
7735 for (int iy = 0; iy < met->ny; iy++) {
7736
7737 /* Interpolate temperature profile... */
7738 int iz;
7739 for (iz = 0; iz < met->np; iz++)
7740 t[iz] = met->t[ix][iy][iz];
7741 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
7742
7743 /* Find 1st tropopause... */
7744 met->pt[ix][iy] = NAN;
7745 for (iz = 0; iz <= 170; iz++) {
7746 int found = 1;
7747 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
7748 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
7749 found = 0;
7750 break;
7751 }
7752 if (found) {
7753 if (iz > 0 && iz < 170)
7754 met->pt[ix][iy] = (float) p2[iz];
7755 break;
7756 }
7757 }
7758
7759 /* Find 2nd tropopause... */
7760 if (ctl->met_tropo == 4) {
7761 met->pt[ix][iy] = NAN;
7762 for (; iz <= 170; iz++) {
7763 int found = 1;
7764 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
7765 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
7766 found = 0;
7767 break;
7768 }
7769 if (found)
7770 break;
7771 }
7772 for (; iz <= 170; iz++) {
7773 int found = 1;
7774 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
7775 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
7776 found = 0;
7777 break;
7778 }
7779 if (found) {
7780 if (iz > 0 && iz < 170)
7781 met->pt[ix][iy] = (float) p2[iz];
7782 break;
7783 }
7784 }
7785 }
7786 }
7787 }
7788
7789 /* Use dynamical tropopause... */
7790 else if (ctl->met_tropo == 5) {
7791
7792 /* Loop over grid points... */
7793#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
7794 for (int ix = 0; ix < met->nx; ix++)
7795 for (int iy = 0; iy < met->ny; iy++) {
7796
7797 /* Interpolate potential vorticity profile... */
7798 for (int iz = 0; iz < met->np; iz++)
7799 pv[iz] = met->pv[ix][iy][iz];
7800 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
7801
7802 /* Interpolate potential temperature profile... */
7803 for (int iz = 0; iz < met->np; iz++)
7804 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
7805 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
7806
7807 /* Find dynamical tropopause... */
7808 met->pt[ix][iy] = NAN;
7809 for (int iz = 0; iz <= 170; iz++)
7810 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
7811 || th2[iz] >= ctl->met_tropo_theta) {
7812 if (iz > 0 && iz < 170)
7813 met->pt[ix][iy] = (float) p2[iz];
7814 break;
7815 }
7816 }
7817 }
7818
7819 else
7820 ERRMSG("Cannot calculate tropopause!");
7821
7822 /* Interpolate temperature, geopotential height, and water vapor... */
7823#pragma omp parallel for default(shared) collapse(2)
7824 for (int ix = 0; ix < met->nx; ix++)
7825 for (int iy = 0; iy < met->ny; iy++) {
7826 double h2ot, tt, zt;
7828 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
7829 met->lat[iy], &tt, ci, cw, 1);
7830 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
7831 met->lat[iy], &zt, ci, cw, 0);
7832 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
7833 met->lat[iy], &h2ot, ci, cw, 0);
7834 met->tt[ix][iy] = (float) tt;
7835 met->zt[ix][iy] = (float) zt;
7836 met->h2ot[ix][iy] = (float) h2ot;
7837 }
7838}
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:8048
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:808
Here is the call graph for this function:

◆ read_obs()

void read_obs ( const char *  filename,
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 7842 of file mptrac.c.

7850 {
7851
7852 /* Write info... */
7853 LOG(1, "Read observation data: %s", filename);
7854
7855 /* Read data... */
7856 if (ctl->obs_type == 0)
7857 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
7858 else if (ctl->obs_type == 1)
7859 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
7860 else
7861 ERRMSG("Set OBS_TYPE to 0 or 1!");
7862
7863 /* Check time... */
7864 for (int i = 1; i < *nobs; i++)
7865 if (rt[i] < rt[i - 1])
7866 ERRMSG("Time must be ascending!");
7867
7868 /* Write info... */
7869 int n = *nobs;
7870 double mini, maxi;
7871 LOG(2, "Number of observations: %d", *nobs);
7872 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
7873 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
7874 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
7875 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
7876 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
7877 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
7878 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
7879 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
7880 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
7881 LOG(2, "Observation range: %g ... %g", mini, maxi);
7882}
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:7886
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:7914
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 7886 of file mptrac.c.

7893 {
7894
7895 /* Open observation data file... */
7896 FILE *in;
7897 if (!(in = fopen(filename, "r")))
7898 ERRMSG("Cannot open file!");
7899
7900 /* Read observations... */
7901 char line[LEN];
7902 while (fgets(line, LEN, in))
7903 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
7904 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
7905 if ((++(*nobs)) >= NOBS)
7906 ERRMSG("Too many observations!");
7907
7908 /* Close observation data file... */
7909 fclose(in);
7910}
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:276

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

7921 {
7922
7923 int ncid, varid;
7924
7925 /* Open netCDF file... */
7926 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7927 ERRMSG("Cannot open file!");
7928
7929 /* Read the observations from the NetCDF file... */
7930 NC_INQ_DIM("nobs", nobs, 1, NOBS);
7931 NC_GET_DOUBLE("time", rt, 1);
7932 NC_GET_DOUBLE("alt", rz, 1);
7933 NC_GET_DOUBLE("lon", rlon, 1);
7934 NC_GET_DOUBLE("lat", rlat, 1);
7935 NC_GET_DOUBLE("obs", robs, 1);
7936
7937 /* Close file... */
7938 NC(nc_close(ncid));
7939}

◆ scan_ctl()

double scan_ctl ( const char *  filename,
int  argc,
char *  argv[],
const char *  varname,
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 7943 of file mptrac.c.

7950 {
7951
7952 FILE *in = NULL;
7953
7954 char fullname1[LEN], fullname2[LEN], rval[LEN];
7955
7956 int contain = 0, i;
7957
7958 /* Open file... */
7959 if (filename[strlen(filename) - 1] != '-')
7960 if (!(in = fopen(filename, "r")))
7961 ERRMSG("Cannot open file!");
7962
7963 /* Set full variable name... */
7964 if (arridx >= 0) {
7965 sprintf(fullname1, "%s[%d]", varname, arridx);
7966 sprintf(fullname2, "%s[*]", varname);
7967 } else {
7968 sprintf(fullname1, "%s", varname);
7969 sprintf(fullname2, "%s", varname);
7970 }
7971
7972 /* Read data... */
7973 if (in != NULL) {
7974 char dummy[LEN], line[LEN], rvarname[LEN];
7975 while (fgets(line, LEN, in)) {
7976 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
7977 if (strcasecmp(rvarname, fullname1) == 0 ||
7978 strcasecmp(rvarname, fullname2) == 0) {
7979 contain = 1;
7980 break;
7981 }
7982 }
7983 }
7984 for (i = 1; i < argc - 1; i++)
7985 if (strcasecmp(argv[i], fullname1) == 0 ||
7986 strcasecmp(argv[i], fullname2) == 0) {
7987 sprintf(rval, "%s", argv[i + 1]);
7988 contain = 1;
7989 break;
7990 }
7991
7992 /* Close file... */
7993 if (in != NULL)
7994 fclose(in);
7995
7996 /* Check for missing variables... */
7997 if (!contain) {
7998 if (strlen(defvalue) > 0)
7999 sprintf(rval, "%s", defvalue);
8000 else
8001 ERRMSG("Missing variable %s!\n", fullname1);
8002 }
8003
8004 /* Write info... */
8005 LOG(1, "%s = %s", fullname1, rval);
8006
8007 /* Return values... */
8008 if (value != NULL)
8009 sprintf(value, "%s", rval);
8010 return atof(rval);
8011}

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

8019 {
8020
8021 /* Convert particle radius from microns to m... */
8022 double rp_help = rp * 1e-6;
8023
8024 /* Density of dry air [kg / m^3]... */
8025 double rho = RHO(p, T);
8026
8027 /* Dynamic viscosity of air [kg / (m s)]... */
8028 double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
8029
8030 /* Thermal velocity of an air molecule [m / s]... */
8031 double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
8032
8033 /* Mean free path of an air molecule [m]... */
8034 double lambda = 2. * eta / (rho * v);
8035
8036 /* Knudsen number for air (dimensionless)... */
8037 double K = lambda / rp_help;
8038
8039 /* Cunningham slip-flow correction (dimensionless)... */
8040 double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
8041
8042 /* Sedimentation velocity [m / s]... */
8043 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
8044}
#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 8048 of file mptrac.c.

8055 {
8056
8057 /* Cubic spline interpolation... */
8058 if (method == 1) {
8059
8060 /* Allocate... */
8061 gsl_interp_accel *acc;
8062 gsl_spline *s;
8063 acc = gsl_interp_accel_alloc();
8064 s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
8065
8066 /* Interpolate profile... */
8067 gsl_spline_init(s, x, y, (size_t) n);
8068 for (int i = 0; i < n2; i++)
8069 if (x2[i] <= x[0])
8070 y2[i] = y[0];
8071 else if (x2[i] >= x[n - 1])
8072 y2[i] = y[n - 1];
8073 else
8074 y2[i] = gsl_spline_eval(s, x2[i], acc);
8075
8076 /* Free... */
8077 gsl_spline_free(s);
8078 gsl_interp_accel_free(acc);
8079 }
8080
8081 /* Linear interpolation... */
8082 else {
8083 for (int i = 0; i < n2; i++)
8084 if (x2[i] <= x[0])
8085 y2[i] = y[0];
8086 else if (x2[i] >= x[n - 1])
8087 y2[i] = y[n - 1];
8088 else {
8089 int idx = locate_irr(x, n, x2[i]);
8090 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
8091 }
8092 }
8093}
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 8097 of file mptrac.c.

8099 {
8100
8101 if (n <= 0)
8102 return 0;
8103
8104 float mean = 0, var = 0;
8105
8106 for (int i = 0; i < n; ++i) {
8107 mean += data[i];
8108 var += SQR(data[i]);
8109 }
8110
8111 var = var / (float) n - SQR(mean / (float) n);
8112
8113 return (var > 0 ? sqrtf(var) : 0);
8114}

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

8121 {
8122
8123 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
8124 const double D = sec / 86400 - 0.5;
8125
8126 /* Geocentric apparent ecliptic longitude [rad]... */
8127 const double g = (357.529 + 0.98560028 * D) * M_PI / 180;
8128 const double q = 280.459 + 0.98564736 * D;
8129 const double L = (q + 1.915 * sin(g) + 0.020 * sin(2 * g)) * M_PI / 180;
8130
8131 /* Mean obliquity of the ecliptic [rad]... */
8132 const double e = (23.439 - 0.00000036 * D) * M_PI / 180;
8133
8134 /* Declination [rad]... */
8135 const double sindec = sin(e) * sin(L);
8136
8137 /* Right ascension [rad]... */
8138 const double ra = atan2(cos(e) * sin(L), cos(L));
8139
8140 /* Greenwich Mean Sidereal Time [h]... */
8141 const double GMST = 18.697374558 + 24.06570982441908 * D;
8142
8143 /* Local Sidereal Time [h]... */
8144 const double LST = GMST + lon / 15;
8145
8146 /* Hour angle [rad]... */
8147 const double h = LST / 12 * M_PI - ra;
8148
8149 /* Convert latitude... */
8150 const double lat_help = lat * M_PI / 180;
8151
8152 /* Return solar zenith angle [rad]... */
8153 return acos(sin(lat_help) * sindec +
8154 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
8155}

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

8167 {
8168
8169 struct tm t0, t1;
8170
8171 t0.tm_year = 100;
8172 t0.tm_mon = 0;
8173 t0.tm_mday = 1;
8174 t0.tm_hour = 0;
8175 t0.tm_min = 0;
8176 t0.tm_sec = 0;
8177
8178 t1.tm_year = year - 1900;
8179 t1.tm_mon = mon - 1;
8180 t1.tm_mday = day;
8181 t1.tm_hour = hour;
8182 t1.tm_min = min;
8183 t1.tm_sec = sec;
8184
8185 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
8186}

◆ timer()

void timer ( const char *  name,
const char *  group,
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 8190 of file mptrac.c.

8193 {
8194
8195 static char names[NTIMER][100], groups[NTIMER][100];
8196
8197 static double rt_name[NTIMER], rt_group[NTIMER],
8198 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
8199
8200 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
8201
8202 /* Get time... */
8203 t1 = omp_get_wtime();
8204 dt = t1 - t0;
8205
8206 /* Add elapsed time to current timers... */
8207 if (iname >= 0) {
8208 rt_name[iname] += dt;
8209 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
8210 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
8211 ct_name[iname]++;
8212 }
8213 if (igroup >= 0)
8214 rt_group[igroup] += t1 - t0;
8215
8216 /* Report timers... */
8217 if (output) {
8218 for (int i = 0; i < nname; i++)
8219 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
8220 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
8221 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
8222 for (int i = 0; i < ngroup; i++)
8223 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
8224 double total = 0.0;
8225 for (int i = 0; i < nname; i++)
8226 total += rt_name[i];
8227 LOG(1, "TIMER_TOTAL = %.3f s", total);
8228 }
8229
8230 /* Identify IDs of next timer... */
8231 for (iname = 0; iname < nname; iname++)
8232 if (strcasecmp(name, names[iname]) == 0)
8233 break;
8234 for (igroup = 0; igroup < ngroup; igroup++)
8235 if (strcasecmp(group, groups[igroup]) == 0)
8236 break;
8237
8238 /* Check whether this is a new timer... */
8239 if (iname >= nname) {
8240 sprintf(names[iname], "%s", name);
8241 if ((++nname) >= NTIMER)
8242 ERRMSG("Too many timers!");
8243 }
8244
8245 /* Check whether this is a new group... */
8246 if (igroup >= ngroup) {
8247 sprintf(groups[igroup], "%s", group);
8248 if ((++ngroup) >= NTIMER)
8249 ERRMSG("Too many groups!");
8250 }
8251
8252 /* Save starting time... */
8253 t0 = t1;
8254}
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:1925

◆ time_from_filename()

double time_from_filename ( const char *  filename,
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 8258 of file mptrac.c.

8260 {
8261
8262 char tstr[10];
8263
8264 double t;
8265
8266 /* Get time from filename... */
8267 int len = (int) strlen(filename);
8268 sprintf(tstr, "%.4s", &filename[len - offset]);
8269 int year = atoi(tstr);
8270 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
8271 int mon = atoi(tstr);
8272 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
8273 int day = atoi(tstr);
8274 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
8275 int hour = atoi(tstr);
8276 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
8277 int min = atoi(tstr);
8278
8279 /* Check time... */
8280 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
8281 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
8282 ERRMSG("Cannot read time from filename!");
8283
8284 /* Convert time to Julian seconds... */
8285 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
8286
8287 /* Return time... */
8288 return t;
8289}
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 8293 of file mptrac.c.

8297 {
8298
8299 /* Get tropopause pressure... */
8300 double pt = clim_tropo(clim, t, lat);
8301
8302 /* Get pressure range... */
8303 double p1 = pt * 0.866877899;
8304 double p0 = pt / 0.866877899;
8305
8306 /* Get weighting factor... */
8307 if (p > p0)
8308 return 1;
8309 else if (p < p1)
8310 return 0;
8311 else
8312 return LIN(p0, 1.0, p1, 0.0, p);
8313}
Here is the call graph for this function:

◆ write_atm()

void write_atm ( const char *  filename,
ctl_t ctl,
atm_t atm,
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 8317 of file mptrac.c.

8321 {
8322
8323 /* Set timer... */
8324 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
8325
8326 /* Write info... */
8327 LOG(1, "Write atmospheric data: %s", filename);
8328
8329 /* Write ASCII data... */
8330 if (ctl->atm_type_out == 0)
8331 write_atm_asc(filename, ctl, atm, t);
8332
8333 /* Write binary data... */
8334 else if (ctl->atm_type_out == 1)
8335 write_atm_bin(filename, ctl, atm);
8336
8337 /* Write netCDF data... */
8338 else if (ctl->atm_type_out == 2)
8339 write_atm_nc(filename, ctl, atm);
8340
8341 /* Write CLaMS trajectory data... */
8342 else if (ctl->atm_type_out == 3)
8343 write_atm_clams_traj(filename, ctl, atm, t);
8344
8345 /* Write CLaMS pos data... */
8346 else if (ctl->atm_type_out == 4)
8347 write_atm_clams(filename, ctl, atm);
8348
8349 /* Error... */
8350 else
8351 ERRMSG("Atmospheric data type not supported!");
8352
8353 /* Write info... */
8354 double mini, maxi;
8355 LOG(2, "Number of particles: %d", atm->np);
8356 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
8357 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8358 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
8359 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
8360 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
8361 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
8362 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
8363 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
8364 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
8365 for (int iq = 0; iq < ctl->nq; iq++) {
8366 char msg[5 * LEN];
8367 sprintf(msg, "Quantity %s range: %s ... %s %s",
8368 ctl->qnt_name[iq], ctl->qnt_format[iq],
8369 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
8370 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
8371 LOG(2, msg, mini, maxi);
8372 }
8373}
void write_atm_asc(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes air parcel data to an ASCII file or gnuplot.
Definition: mptrac.c:8377
void write_atm_clams_traj(const char *dirname, ctl_t *ctl, atm_t *atm, double t)
Writes CLaMS trajectory data to a NetCDF file.
Definition: mptrac.c:8558
void write_atm_clams(const char *filename, ctl_t *ctl, atm_t *atm)
Writes air parcel data to a NetCDF file in the CLaMS format.
Definition: mptrac.c:8509
void write_atm_bin(const char *filename, ctl_t *ctl, atm_t *atm)
Writes air parcel data to a binary file.
Definition: mptrac.c:8459
void write_atm_nc(const char *filename, ctl_t *ctl, atm_t *atm)
Writes air parcel data to a NetCDF file.
Definition: mptrac.c:8707
Here is the call graph for this function:

◆ write_atm_asc()

void write_atm_asc ( const char *  filename,
ctl_t ctl,
atm_t atm,
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 8377 of file mptrac.c.

8381 {
8382
8383 FILE *out;
8384
8385 /* Set time interval for output... */
8386 double t0 = t - 0.5 * ctl->dt_mod;
8387 double t1 = t + 0.5 * ctl->dt_mod;
8388
8389 /* Check if gnuplot output is requested... */
8390 if (ctl->atm_gpfile[0] != '-') {
8391
8392 /* Create gnuplot pipe... */
8393 if (!(out = popen("gnuplot", "w")))
8394 ERRMSG("Cannot create pipe to gnuplot!");
8395
8396 /* Set plot filename... */
8397 fprintf(out, "set out \"%s.png\"\n", filename);
8398
8399 /* Set time string... */
8400 double r;
8401 int year, mon, day, hour, min, sec;
8402 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
8403 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
8404 year, mon, day, hour, min);
8405
8406 /* Dump gnuplot file to pipe... */
8407 FILE *in;
8408 if (!(in = fopen(ctl->atm_gpfile, "r")))
8409 ERRMSG("Cannot open file!");
8410 char line[LEN];
8411 while (fgets(line, LEN, in))
8412 fprintf(out, "%s", line);
8413 fclose(in);
8414 }
8415
8416 else {
8417
8418 /* Create file... */
8419 if (!(out = fopen(filename, "w")))
8420 ERRMSG("Cannot create file!");
8421 }
8422
8423 /* Write header... */
8424 fprintf(out,
8425 "# $1 = time [s]\n"
8426 "# $2 = altitude [km]\n"
8427 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
8428 for (int iq = 0; iq < ctl->nq; iq++)
8429 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
8430 ctl->qnt_unit[iq]);
8431 fprintf(out, "\n");
8432
8433 /* Write data... */
8434 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
8435
8436 /* Check time... */
8437 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
8438 continue;
8439
8440 /* Write output... */
8441 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
8442 atm->lon[ip], atm->lat[ip]);
8443 for (int iq = 0; iq < ctl->nq; iq++) {
8444 fprintf(out, " ");
8445 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
8446 fprintf(out, ctl->qnt_format[iq], NAN);
8447 else
8448 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
8449 }
8450 fprintf(out, "\n");
8451 }
8452
8453 /* Close file... */
8454 fclose(out);
8455}
Here is the call graph for this function:

◆ write_atm_bin()

void write_atm_bin ( const char *  filename,
ctl_t ctl,
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 8459 of file mptrac.c.

8462 {
8463
8464 FILE *out;
8465
8466 /* Create file... */
8467 if (!(out = fopen(filename, "w")))
8468 ERRMSG("Cannot create file!");
8469
8470 /* Write version of binary data... */
8471 int version = 100;
8472 FWRITE(&version, int,
8473 1,
8474 out);
8475
8476 /* Write data... */
8477 FWRITE(&atm->np, int,
8478 1,
8479 out);
8480 FWRITE(atm->time, double,
8481 (size_t) atm->np,
8482 out);
8483 FWRITE(atm->p, double,
8484 (size_t) atm->np,
8485 out);
8486 FWRITE(atm->lon, double,
8487 (size_t) atm->np,
8488 out);
8489 FWRITE(atm->lat, double,
8490 (size_t) atm->np,
8491 out);
8492 for (int iq = 0; iq < ctl->nq; iq++)
8493 FWRITE(atm->q[iq], double,
8494 (size_t) atm->np,
8495 out);
8496
8497 /* Write final flag... */
8498 int final = 999;
8499 FWRITE(&final, int,
8500 1,
8501 out);
8502
8503 /* Close file... */
8504 fclose(out);
8505}

◆ write_atm_clams()

void write_atm_clams ( const char *  filename,
ctl_t ctl,
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 8509 of file mptrac.c.

8512 {
8513
8514 int tid, pid, ncid, varid;
8515 size_t start[2], count[2];
8516
8517 /* Create file... */
8518 nc_create(filename, NC_CLOBBER, &ncid);
8519
8520 /* Define dimensions... */
8521 NC(nc_def_dim(ncid, "time", 1, &tid));
8522 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
8523
8524 /* Define variables and their attributes... */
8525 int dim_ids[2] = { tid, pid };
8526 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
8527 "seconds since 2000-01-01 00:00:00 UTC");
8528 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg");
8529 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg");
8530 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa");
8531 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K");
8532 for (int iq = 0; iq < ctl->nq; iq++)
8533 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
8534 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
8535
8536 /* Define global attributes... */
8537 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
8538 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
8539
8540 /* End definitions... */
8541 NC(nc_enddef(ncid));
8542
8543 /* Write data... */
8544 NC_PUT_DOUBLE("time", atm->time, 0);
8545 NC_PUT_DOUBLE("LAT", atm->lat, 0);
8546 NC_PUT_DOUBLE("LON", atm->lon, 0);
8547 NC_PUT_DOUBLE("PRESS", atm->p, 0);
8548 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
8549 for (int iq = 0; iq < ctl->nq; iq++)
8550 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8551
8552 /* Close file... */
8553 NC(nc_close(ncid));
8554}
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1163
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1077
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1003

◆ write_atm_clams_traj()

void write_atm_clams_traj ( const char *  dirname,
ctl_t ctl,
atm_t atm,
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 8558 of file mptrac.c.

8562 {
8563
8564 /* Global Counter... */
8565 static size_t out_cnt = 0;
8566
8567 double r, r_start, r_stop;
8568 int year, mon, day, hour, min, sec;
8569 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
8570 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
8571 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
8572
8573 int ncid, varid, tid, pid, cid;
8574 int dim_ids[2];
8575
8576 /* time, nparc */
8577 size_t start[2];
8578 size_t count[2];
8579
8580 /* Determine start and stop times of calculation... */
8581 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
8582 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
8583 &min_start, &sec_start, &r_start);
8584 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
8585 &min_stop, &sec_stop, &r_stop);
8586
8587 sprintf(filename_out, "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc",
8588 dirname,
8589 year_start % 100, mon_start, day_start, hour_start,
8590 year_stop % 100, mon_stop, day_stop, hour_stop);
8591 LOG(1, "Write traj file: %s", filename_out);
8592
8593 /* Define hyperslap for the traj_file... */
8594 start[0] = out_cnt;
8595 start[1] = 0;
8596 count[0] = 1;
8597 count[1] = (size_t) atm->np;
8598
8599 /* Create the file at the first timestep... */
8600 if (out_cnt == 0) {
8601
8602 /* Create file... */
8603 nc_create(filename_out, NC_CLOBBER, &ncid);
8604
8605 /* Define dimensions... */
8606 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
8607 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
8608 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
8609 dim_ids[0] = tid;
8610 dim_ids[1] = pid;
8611
8612 /* Define variables and their attributes... */
8613 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
8614 "seconds since 2000-01-01 00:00:00 UTC");
8615 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg");
8616 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg");
8617 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa");
8618 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K");
8619 for (int iq = 0; iq < ctl->nq; iq++)
8620 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
8621 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
8622
8623 /* Define global attributes... */
8624 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
8625 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
8626
8627 /* End definitions... */
8628 NC(nc_enddef(ncid));
8629 NC(nc_close(ncid));
8630 }
8631
8632 /* Increment global counter to change hyperslap... */
8633 out_cnt++;
8634
8635 /* Open file... */
8636 NC(nc_open(filename_out, NC_WRITE, &ncid));
8637
8638 /* Write data... */
8639 NC_PUT_DOUBLE("time", atm->time, 1);
8640 NC_PUT_DOUBLE("LAT", atm->lat, 1);
8641 NC_PUT_DOUBLE("LON", atm->lon, 1);
8642 NC_PUT_DOUBLE("PRESS", atm->p, 1);
8643 if (ctl->advect_vert_coord == 1) {
8644 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
8645 } else if (ctl->qnt_zeta >= 0) {
8646 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
8647 }
8648 for (int iq = 0; iq < ctl->nq; iq++)
8649 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
8650
8651 /* Close file... */
8652 NC(nc_close(ncid));
8653
8654 /* At the last time step create the init_fix_YYYYMMDDHH file... */
8655 if ((year == year_stop) && (mon == mon_stop)
8656 && (day == day_stop) && (hour == hour_stop)) {
8657
8658 /* Set filename... */
8659 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
8660 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
8661 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
8662 LOG(1, "Write init file: %s", filename_init);
8663
8664 /* Create file... */
8665 nc_create(filename_init, NC_CLOBBER, &ncid);
8666
8667 /* Define dimensions... */
8668 NC(nc_def_dim(ncid, "time", 1, &tid));
8669 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
8670 dim_ids[0] = tid;
8671 dim_ids[1] = pid;
8672
8673 /* Define variables and their attributes... */
8674 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
8675 "seconds since 2000-01-01 00:00:00 UTC");
8676 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg");
8677 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg");
8678 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa");
8679 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K");
8680 for (int iq = 0; iq < ctl->nq; iq++)
8681 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
8682 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
8683
8684 /* Define global attributes... */
8685 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
8686 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
8687
8688 /* End definitions... */
8689 NC(nc_enddef(ncid));
8690
8691 /* Write data... */
8692 NC_PUT_DOUBLE("time", atm->time, 0);
8693 NC_PUT_DOUBLE("LAT", atm->lat, 0);
8694 NC_PUT_DOUBLE("LON", atm->lon, 0);
8695 NC_PUT_DOUBLE("PRESS", atm->p, 0);
8696 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
8697 for (int iq = 0; iq < ctl->nq; iq++)
8698 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8699
8700 /* Close file... */
8701 NC(nc_close(ncid));
8702 }
8703}
Here is the call graph for this function:

◆ write_atm_nc()

void write_atm_nc ( const char *  filename,
ctl_t ctl,
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 8707 of file mptrac.c.

8710 {
8711
8712 int ncid, obsid, varid;
8713
8714 size_t start[2], count[2];
8715
8716 /* Create file... */
8717 NC(nc_create(filename, NC_CLOBBER, &ncid));
8718
8719 /* Define dimensions... */
8720 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
8721
8722 /* Define variables and their attributes... */
8723 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
8724 "seconds since 2000-01-01 00:00:00 UTC");
8725 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa");
8726 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east");
8727 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north");
8728 for (int iq = 0; iq < ctl->nq; iq++)
8729 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
8730 ctl->qnt_longname[iq], ctl->qnt_unit[iq]);
8731
8732 /* Define global attributes... */
8733 NC_PUT_ATT_GLOBAL("featureType", "point");
8734
8735 /* End definitions... */
8736 NC(nc_enddef(ncid));
8737
8738 /* Write data... */
8739 NC_PUT_DOUBLE("time", atm->time, 0);
8740 NC_PUT_DOUBLE("press", atm->p, 0);
8741 NC_PUT_DOUBLE("lon", atm->lon, 0);
8742 NC_PUT_DOUBLE("lat", atm->lat, 0);
8743 for (int iq = 0; iq < ctl->nq; iq++)
8744 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8745
8746 /* Close file... */
8747 NC(nc_close(ncid));
8748}

◆ write_csi()

void write_csi ( const char *  filename,
ctl_t ctl,
atm_t atm,
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 8752 of file mptrac.c.

8756 {
8757
8758 static FILE *out;
8759
8760 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
8761 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
8762
8763 static int *obscount, ct, cx, cy, cz, ip, ix, iy, iz, n, nobs, nk;
8764
8765 /* Set timer... */
8766 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
8767
8768 /* Init... */
8769 if (t == ctl->t_start) {
8770
8771 /* Check quantity index for mass... */
8772 if (ctl->qnt_m < 0)
8773 ERRMSG("Need quantity mass!");
8774
8775 /* Allocate... */
8776 ALLOC(area, double,
8777 ctl->csi_ny);
8778 ALLOC(rt, double,
8779 NOBS);
8780 ALLOC(rz, double,
8781 NOBS);
8782 ALLOC(rlon, double,
8783 NOBS);
8784 ALLOC(rlat, double,
8785 NOBS);
8786 ALLOC(robs, double,
8787 NOBS);
8788
8789 /* Read observation data... */
8790 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
8791
8792 /* Read kernel data... */
8793 if (ctl->csi_kernel[0] != '-')
8794 read_kernel(ctl->csi_kernel, kz, kw, &nk);
8795
8796 /* Create new file... */
8797 LOG(1, "Write CSI data: %s", filename);
8798 if (!(out = fopen(filename, "w")))
8799 ERRMSG("Cannot create file!");
8800
8801 /* Write header... */
8802 fprintf(out,
8803 "# $1 = time [s]\n"
8804 "# $2 = number of hits (cx)\n"
8805 "# $3 = number of misses (cy)\n"
8806 "# $4 = number of false alarms (cz)\n"
8807 "# $5 = number of observations (cx + cy)\n"
8808 "# $6 = number of forecasts (cx + cz)\n"
8809 "# $7 = bias (ratio of forecasts and observations) [%%]\n"
8810 "# $8 = probability of detection (POD) [%%]\n"
8811 "# $9 = false alarm rate (FAR) [%%]\n"
8812 "# $10 = critical success index (CSI) [%%]\n");
8813 fprintf(out,
8814 "# $11 = hits associated with random chance\n"
8815 "# $12 = equitable threat score (ETS) [%%]\n"
8816 "# $13 = Pearson linear correlation coefficient\n"
8817 "# $14 = Spearman rank-order correlation coefficient\n"
8818 "# $15 = column density mean error (F - O) [kg/m^2]\n"
8819 "# $16 = column density root mean square error (RMSE) [kg/m^2]\n"
8820 "# $17 = column density mean absolute error [kg/m^2]\n"
8821 "# $18 = log-likelihood function\n"
8822 "# $19 = number of data points\n\n");
8823
8824 /* Set grid box size... */
8825 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
8826 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
8827 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
8828
8829 /* Set horizontal coordinates... */
8830 for (iy = 0; iy < ctl->csi_ny; iy++) {
8831 double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
8832 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(lat * M_PI / 180.);
8833 }
8834 }
8835
8836 /* Set time interval... */
8837 double t0 = t - 0.5 * ctl->dt_mod;
8838 double t1 = t + 0.5 * ctl->dt_mod;
8839
8840 /* Allocate... */
8841 ALLOC(modmean, double,
8842 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
8843 ALLOC(obsmean, double,
8844 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
8845 ALLOC(obscount, int,
8846 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
8847 ALLOC(obsstd, double,
8848 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
8849
8850 /* Loop over observations... */
8851 for (int i = 0; i < nobs; i++) {
8852
8853 /* Check time... */
8854 if (rt[i] < t0)
8855 continue;
8856 else if (rt[i] >= t1)
8857 break;
8858
8859 /* Check observation data... */
8860 if (!isfinite(robs[i]))
8861 continue;
8862
8863 /* Calculate indices... */
8864 ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
8865 iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
8866 iz = (int) ((rz[i] - ctl->csi_z0) / dz);
8867
8868 /* Check indices... */
8869 if (ix < 0 || ix >= ctl->csi_nx ||
8870 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
8871 continue;
8872
8873 /* Get mean observation index... */
8874 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
8875 obsmean[idx] += robs[i];
8876 obsstd[idx] += SQR(robs[i]);
8877 obscount[idx]++;
8878 }
8879
8880 /* Analyze model data... */
8881 for (ip = 0; ip < atm->np; ip++) {
8882
8883 /* Check time... */
8884 if (atm->time[ip] < t0 || atm->time[ip] > t1)
8885 continue;
8886
8887 /* Get indices... */
8888 ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
8889 iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
8890 iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
8891
8892 /* Check indices... */
8893 if (ix < 0 || ix >= ctl->csi_nx ||
8894 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
8895 continue;
8896
8897 /* Get total mass in grid cell... */
8898 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
8899 modmean[idx] += kernel_weight(kz, kw, nk, atm->p[ip])
8900 * atm->q[ctl->qnt_m][ip];
8901 }
8902
8903 /* Analyze all grid cells... */
8904 for (ix = 0; ix < ctl->csi_nx; ix++)
8905 for (iy = 0; iy < ctl->csi_ny; iy++)
8906 for (iz = 0; iz < ctl->csi_nz; iz++) {
8907
8908 /* Calculate mean observation index... */
8909 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
8910 if (obscount[idx] > 0) {
8911 obsmean[idx] /= obscount[idx];
8912 obsstd[idx] -= SQR(obsmean[idx]);
8913 obsstd[idx] = sqrt(obsstd[idx]);
8914 }
8915
8916 /* Calculate column density... */
8917 if (modmean[idx] > 0)
8918 modmean[idx] /= (1e6 * area[iy]);
8919
8920 /* Calculate CSI... */
8921 if (obscount[idx] > 0) {
8922 ct++;
8923 if (obsmean[idx] >= ctl->csi_obsmin &&
8924 modmean[idx] >= ctl->csi_modmin)
8925 cx++;
8926 else if (obsmean[idx] >= ctl->csi_obsmin &&
8927 modmean[idx] < ctl->csi_modmin)
8928 cy++;
8929 else if (obsmean[idx] < ctl->csi_obsmin &&
8930 modmean[idx] >= ctl->csi_modmin)
8931 cz++;
8932 }
8933
8934 /* Save data for other verification statistics... */
8935 if (obscount[idx] > 0
8936 && (obsmean[idx] >= ctl->csi_obsmin
8937 || modmean[idx] >= ctl->csi_modmin)) {
8938 x[n] = modmean[idx];
8939 y[n] = obsmean[idx];
8940 if (modmean[idx] >= ctl->csi_modmin)
8941 obsstdn[n] = obsstd[idx];
8942 if ((++n) >= NCSI)
8943 ERRMSG("Too many data points to calculate statistics!");
8944 }
8945 }
8946
8947 /* Write output... */
8948 if (fmod(t, ctl->csi_dt_out) == 0) {
8949
8950 /* Calculate verification statistics
8951 (https://www.cawcr.gov.au/projects/verification/) ... */
8952 static double work[2 * NCSI], work2[2 * NCSI];;
8953 int n_obs = cx + cy;
8954 int n_for = cx + cz;
8955 double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
8956 double pod = (n_obs > 0) ? (100. * cx) / n_obs : NAN;
8957 double far = (n_for > 0) ? (100. * cz) / n_for : NAN;
8958 double csi = (cx + cy + cz > 0) ? (100. * cx) / (cx + cy + cz) : NAN;
8959 double cx_rd = (ct > 0) ? (1. * n_obs * n_for) / ct : NAN;
8960 double ets = (cx + cy + cz - cx_rd > 0) ?
8961 (100. * (cx - cx_rd)) / (cx + cy + cz - cx_rd) : NAN;
8962 double rho_p =
8963 (n > 0) ? gsl_stats_correlation(x, 1, y, 1, (size_t) n) : NAN;
8964 double rho_s =
8965 (n > 0) ? gsl_stats_spearman(x, 1, y, 1, (size_t) n, work) : NAN;
8966 for (int i = 0; i < n; i++) {
8967 work[i] = x[i] - y[i];
8968 work2[i] = (obsstdn[i] != 0) ? (x[i] - y[i]) / obsstdn[i] : 0;
8969 }
8970 double mean = (n > 0) ? gsl_stats_mean(work, 1, (size_t) n) : NAN;
8971 double rmse = (n > 0) ? gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n,
8972 0.0) : NAN;
8973 double absdev =
8974 (n > 0) ? gsl_stats_absdev_m(work, 1, (size_t) n, 0.0) : NAN;
8975 double loglikelihood =
8976 (n > 0) ? gsl_stats_tss(work2, 1, (size_t) n) * (-0.5) : GSL_NAN;
8977
8978 /* Write... */
8979 fprintf(out,
8980 "%.2f %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n", t,
8981 cx, cy, cz, n_obs, n_for, bias, pod, far, csi, cx_rd, ets, rho_p,
8982 rho_s, mean, rmse, absdev, loglikelihood, n);
8983
8984 /* Set counters to zero... */
8985 n = ct = cx = cy = cz = 0;
8986 }
8987
8988 /* Free... */
8989 free(modmean);
8990 free(obsmean);
8991 free(obscount);
8992 free(obsstd);
8993
8994 /* Finalize... */
8995 if (t == ctl->t_stop) {
8996
8997 /* Close output file... */
8998 fclose(out);
8999
9000 /* Free... */
9001 free(area);
9002 free(rt);
9003 free(rz);
9004 free(rlon);
9005 free(rlat);
9006 free(robs);
9007 }
9008}
void read_obs(const char *filename, 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:7842
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:5570
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:1804
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:251
Here is the call graph for this function:

◆ write_ens()

void write_ens ( const char *  filename,
ctl_t ctl,
atm_t atm,
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 9012 of file mptrac.c.

9016 {
9017
9018 static FILE *out;
9019
9020 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
9021 x[3], zm[NENS];
9022
9023 static int n[NENS];
9024
9025 /* Set timer... */
9026 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
9027
9028 /* Check quantities... */
9029 if (ctl->qnt_ens < 0)
9030 ERRMSG("Missing ensemble IDs!");
9031
9032 /* Set time interval... */
9033 double t0 = t - 0.5 * ctl->dt_mod;
9034 double t1 = t + 0.5 * ctl->dt_mod;
9035
9036 /* Init... */
9037 for (int i = 0; i < NENS; i++) {
9038 for (int iq = 0; iq < ctl->nq; iq++)
9039 qm[iq][i] = qs[iq][i] = 0;
9040 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
9041 n[i] = 0;
9042 }
9043
9044 /* Loop over air parcels... */
9045 for (int ip = 0; ip < atm->np; ip++) {
9046
9047 /* Check time... */
9048 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9049 continue;
9050
9051 /* Check ensemble ID... */
9052 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
9053 ERRMSG("Ensemble ID is out of range!");
9054
9055 /* Get means... */
9056 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
9057 for (int iq = 0; iq < ctl->nq; iq++) {
9058 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
9059 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
9060 }
9061 xm[ctl->qnt_ens][0] += x[0];
9062 xm[ctl->qnt_ens][1] += x[1];
9063 xm[ctl->qnt_ens][2] += x[2];
9064 zm[ctl->qnt_ens] += Z(atm->p[ip]);
9065 n[ctl->qnt_ens]++;
9066 }
9067
9068 /* Create file... */
9069 LOG(1, "Write ensemble data: %s", filename);
9070 if (!(out = fopen(filename, "w")))
9071 ERRMSG("Cannot create file!");
9072
9073 /* Write header... */
9074 fprintf(out,
9075 "# $1 = time [s]\n"
9076 "# $2 = altitude [km]\n"
9077 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
9078 for (int iq = 0; iq < ctl->nq; iq++)
9079 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
9080 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9081 for (int iq = 0; iq < ctl->nq; iq++)
9082 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
9083 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9084 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
9085
9086 /* Write data... */
9087 for (int i = 0; i < NENS; i++)
9088 if (n[i] > 0) {
9089 cart2geo(xm[i], &dummy, &lon, &lat);
9090 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
9091 for (int iq = 0; iq < ctl->nq; iq++) {
9092 fprintf(out, " ");
9093 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
9094 }
9095 for (int iq = 0; iq < ctl->nq; iq++) {
9096 fprintf(out, " ");
9097 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
9098 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
9099 }
9100 fprintf(out, " %d\n", n[i]);
9101 }
9102
9103 /* Close file... */
9104 fclose(out);
9105}
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:271
Here is the call graph for this function:

◆ write_grid()

void write_grid ( const char *  filename,
ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
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 9109 of file mptrac.c.

9115 {
9116
9117 static double kz[EP], kw[EP];
9118
9119 static int nk;
9120
9121 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
9122
9123 int *ixs, *iys, *izs, *np;
9124
9125 /* Set timer... */
9126 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
9127
9128 /* Write info... */
9129 LOG(1, "Write grid data: %s", filename);
9130
9131 /* Init... */
9132 if (t == ctl->t_start) {
9133
9134 /* Read kernel data... */
9135 if (ctl->grid_kernel[0] != '-')
9136 read_kernel(ctl->grid_kernel, kz, kw, &nk);
9137 }
9138
9139 /* Allocate... */
9140 ALLOC(cd, double,
9141 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9142 for (int iq = 0; iq < ctl->nq; iq++) {
9143 ALLOC(mean[iq], double,
9144 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9145 ALLOC(sigma[iq], double,
9146 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9147 }
9148 ALLOC(vmr_impl, double,
9149 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9150 ALLOC(z, double,
9151 ctl->grid_nz);
9152 ALLOC(lon, double,
9153 ctl->grid_nx);
9154 ALLOC(lat, double,
9155 ctl->grid_ny);
9156 ALLOC(area, double,
9157 ctl->grid_ny);
9158 ALLOC(press, double,
9159 ctl->grid_nz);
9160 ALLOC(np, int,
9161 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9162 ALLOC(ixs, int,
9163 atm->np);
9164 ALLOC(iys, int,
9165 atm->np);
9166 ALLOC(izs, int,
9167 atm->np);
9168
9169 /* Set grid box size... */
9170 double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
9171 double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
9172 double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
9173
9174 /* Set vertical coordinates... */
9175#pragma omp parallel for default(shared)
9176 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9177 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
9178 press[iz] = P(z[iz]);
9179 }
9180
9181 /* Set horizontal coordinates... */
9182 for (int ix = 0; ix < ctl->grid_nx; ix++)
9183 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
9184#pragma omp parallel for default(shared)
9185 for (int iy = 0; iy < ctl->grid_ny; iy++) {
9186 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
9187 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.)
9188 * cos(lat[iy] * M_PI / 180.);
9189 }
9190
9191 /* Set time interval for output... */
9192 double t0 = t - 0.5 * ctl->dt_mod;
9193 double t1 = t + 0.5 * ctl->dt_mod;
9194
9195 /* Get grid box indices... */
9196#pragma omp parallel for default(shared)
9197 for (int ip = 0; ip < atm->np; ip++) {
9198 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
9199 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
9200 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
9201 if (atm->time[ip] < t0 || atm->time[ip] > t1
9202 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
9203 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
9204 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
9205 izs[ip] = -1;
9206 }
9207
9208 /* Average data... */
9209 for (int ip = 0; ip < atm->np; ip++)
9210 if (izs[ip] >= 0) {
9211 int idx =
9212 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
9213 double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
9214 np[idx]++;
9215 for (int iq = 0; iq < ctl->nq; iq++) {
9216 mean[iq][idx] += kernel * atm->q[iq][ip];
9217 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
9218 }
9219 }
9220
9221 /* Calculate column density and volume mixing ratio... */
9222#pragma omp parallel for default(shared)
9223 for (int ix = 0; ix < ctl->grid_nx; ix++)
9224 for (int iy = 0; iy < ctl->grid_ny; iy++)
9225 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9226
9227 /* Get grid index... */
9228 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
9229
9230 /* Calculate column density... */
9231 cd[idx] = NAN;
9232 if (ctl->qnt_m >= 0)
9233 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
9234
9235 /* Calculate volume mixing ratio (implicit)... */
9236 vmr_impl[idx] = NAN;
9237 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
9238 && met1 != NULL) {
9239 vmr_impl[idx] = 0;
9240 if (mean[ctl->qnt_m][idx] > 0) {
9241
9242 /* Get temperature... */
9243 double temp;
9245 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
9246 lon[ix], lat[iy], &temp, ci, cw, 1);
9247
9248 /* Calculate volume mixing ratio... */
9249 vmr_impl[idx] = MA / ctl->molmass * mean[ctl->qnt_m][idx]
9250 / (RHO(press[iz], temp) * 1e6 * area[iy] * 1e3 * dz);
9251 }
9252 }
9253
9254 /* Calculate mean... */
9255 if (np[idx] > 0)
9256 for (int iq = 0; iq < ctl->nq; iq++) {
9257 mean[iq][idx] /= np[idx];
9258 double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
9259 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
9260 } else
9261 for (int iq = 0; iq < ctl->nq; iq++) {
9262 mean[iq][idx] = NAN;
9263 sigma[iq][idx] = NAN;
9264 }
9265 }
9266
9267 /* Write ASCII data... */
9268 if (ctl->grid_type == 0)
9269 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
9270 t, z, lon, lat, area, dz, np);
9271
9272 /* Write netCDF data... */
9273 else if (ctl->grid_type == 1)
9274 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
9275 t, z, lon, lat, area, dz, np);
9276
9277 /* Error message... */
9278 else
9279 ERRMSG("Grid data format GRID_TYPE unknown!");
9280
9281 /* Free... */
9282 free(cd);
9283 for (int iq = 0; iq < ctl->nq; iq++) {
9284 free(mean[iq]);
9285 free(sigma[iq]);
9286 }
9287 free(vmr_impl);
9288 free(z);
9289 free(lon);
9290 free(lat);
9291 free(area);
9292 free(press);
9293 free(np);
9294 free(ixs);
9295 free(iys);
9296 free(izs);
9297}
void write_grid_asc(const char *filename, ctl_t *ctl, double *cd, double *mean[NQ], double *sigma[NQ], double *vmr_impl, double t, double *z, double *lon, double *lat, double *area, double dz, int *np)
Writes grid data to an ASCII file.
Definition: mptrac.c:9301
void write_grid_nc(const char *filename, ctl_t *ctl, double *cd, double *mean[NQ], double *sigma[NQ], double *vmr_impl, double t, double *z, double *lon, double *lat, double *area, double dz, int *np)
Writes grid data to a NetCDF file.
Definition: mptrac.c:9405
Here is the call graph for this function:

◆ write_grid_asc()

void write_grid_asc ( const char *  filename,
ctl_t ctl,
double *  cd,
double *  mean[NQ],
double *  sigma[NQ],
double *  vmr_impl,
double  t,
double *  z,
double *  lon,
double *  lat,
double *  area,
double  dz,
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 9301 of file mptrac.c.

9314 {
9315
9316 FILE *out;
9317
9318 /* Check if gnuplot output is requested... */
9319 if (ctl->grid_gpfile[0] != '-') {
9320
9321 /* Create gnuplot pipe... */
9322 if (!(out = popen("gnuplot", "w")))
9323 ERRMSG("Cannot create pipe to gnuplot!");
9324
9325 /* Set plot filename... */
9326 fprintf(out, "set out \"%s.png\"\n", filename);
9327
9328 /* Set time string... */
9329 double r;
9330 int year, mon, day, hour, min, sec;
9331 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9332 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
9333 year, mon, day, hour, min);
9334
9335 /* Dump gnuplot file to pipe... */
9336 FILE *in;
9337 char line[LEN];
9338 if (!(in = fopen(ctl->grid_gpfile, "r")))
9339 ERRMSG("Cannot open file!");
9340 while (fgets(line, LEN, in))
9341 fprintf(out, "%s", line);
9342 fclose(in);
9343 }
9344
9345 else {
9346
9347 /* Create file... */
9348 if (!(out = fopen(filename, "w")))
9349 ERRMSG("Cannot create file!");
9350 }
9351
9352 /* Write header... */
9353 fprintf(out,
9354 "# $1 = time [s]\n"
9355 "# $2 = altitude [km]\n"
9356 "# $3 = longitude [deg]\n"
9357 "# $4 = latitude [deg]\n"
9358 "# $5 = surface area [km^2]\n"
9359 "# $6 = layer depth [km]\n"
9360 "# $7 = column density (implicit) [kg/m^2]\n"
9361 "# $8 = volume mixing ratio (implicit) [ppv]\n"
9362 "# $9 = number of particles [1]\n");
9363 for (int iq = 0; iq < ctl->nq; iq++)
9364 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
9365 ctl->qnt_unit[iq]);
9366 if (ctl->grid_stddev)
9367 for (int iq = 0; iq < ctl->nq; iq++)
9368 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
9369 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9370 fprintf(out, "\n");
9371
9372 /* Write data... */
9373 for (int ix = 0; ix < ctl->grid_nx; ix++) {
9374 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
9375 fprintf(out, "\n");
9376 for (int iy = 0; iy < ctl->grid_ny; iy++) {
9377 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
9378 fprintf(out, "\n");
9379 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9380 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
9381 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
9382 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
9383 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
9384 for (int iq = 0; iq < ctl->nq; iq++) {
9385 fprintf(out, " ");
9386 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
9387 }
9388 if (ctl->grid_stddev)
9389 for (int iq = 0; iq < ctl->nq; iq++) {
9390 fprintf(out, " ");
9391 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
9392 }
9393 fprintf(out, "\n");
9394 }
9395 }
9396 }
9397 }
9398
9399 /* Close file... */
9400 fclose(out);
9401}
Here is the call graph for this function:

◆ write_grid_nc()

void write_grid_nc ( const char *  filename,
ctl_t ctl,
double *  cd,
double *  mean[NQ],
double *  sigma[NQ],
double *  vmr_impl,
double  t,
double *  z,
double *  lon,
double *  lat,
double *  area,
double  dz,
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 9405 of file mptrac.c.

9418 {
9419
9420 char longname[2 * LEN], varname[2 * LEN];
9421
9422 double *help;
9423
9424 int *help2, ncid, dimid[10], varid;
9425
9426 size_t start[2], count[2];
9427
9428 /* Allocate... */
9429 ALLOC(help, double,
9430 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9431 ALLOC(help2, int,
9432 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9433
9434 /* Create file... */
9435 NC(nc_create(filename, NC_CLOBBER, &ncid));
9436
9437 /* Define dimensions... */
9438 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
9439 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
9440 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
9441 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
9442 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
9443
9444 /* Define variables and their attributes... */
9445 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
9446 "seconds since 2000-01-01 00:00:00 UTC");
9447 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km");
9448 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north");
9449 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east");
9450 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km");
9451 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2");
9452 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2");
9453 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
9454 "volume mixing ratio (implicit)", "ppv");
9455 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1");
9456 for (int iq = 0; iq < ctl->nq; iq++) {
9457 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
9458 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
9459 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq]);
9460 if (ctl->grid_stddev) {
9461 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
9462 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
9463 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq]);
9464 }
9465 }
9466 /* End definitions... */
9467 NC(nc_enddef(ncid));
9468
9469 /* Write data... */
9470 NC_PUT_DOUBLE("time", &t, 0);
9471 NC_PUT_DOUBLE("lon", lon, 0);
9472 NC_PUT_DOUBLE("lat", lat, 0);
9473 NC_PUT_DOUBLE("z", z, 0);
9474 NC_PUT_DOUBLE("area", area, 0);
9475 NC_PUT_DOUBLE("dz", &dz, 0);
9476
9477 for (int ix = 0; ix < ctl->grid_nx; ix++)
9478 for (int iy = 0; iy < ctl->grid_ny; iy++)
9479 for (int iz = 0; iz < ctl->grid_nz; iz++)
9480 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9481 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9482 NC_PUT_DOUBLE("cd", help, 0);
9483
9484 for (int ix = 0; ix < ctl->grid_nx; ix++)
9485 for (int iy = 0; iy < ctl->grid_ny; iy++)
9486 for (int iz = 0; iz < ctl->grid_nz; iz++)
9487 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9488 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9489 NC_PUT_DOUBLE("vmr_impl", help, 0);
9490
9491 for (int ix = 0; ix < ctl->grid_nx; ix++)
9492 for (int iy = 0; iy < ctl->grid_ny; iy++)
9493 for (int iz = 0; iz < ctl->grid_nz; iz++)
9494 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9495 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9496 NC_PUT_INT("np", help2, 0);
9497
9498 for (int iq = 0; iq < ctl->nq; iq++) {
9499 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
9500 for (int ix = 0; ix < ctl->grid_nx; ix++)
9501 for (int iy = 0; iy < ctl->grid_ny; iy++)
9502 for (int iz = 0; iz < ctl->grid_nz; iz++)
9503 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9504 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9505 NC_PUT_DOUBLE(varname, help, 0);
9506 }
9507
9508 if (ctl->grid_stddev)
9509 for (int iq = 0; iq < ctl->nq; iq++) {
9510 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
9511 for (int ix = 0; ix < ctl->grid_nx; ix++)
9512 for (int iy = 0; iy < ctl->grid_ny; iy++)
9513 for (int iz = 0; iz < ctl->grid_nz; iz++)
9514 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9515 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9516 NC_PUT_DOUBLE(varname, help, 0);
9517 }
9518
9519 /* Close file... */
9520 NC(nc_close(ncid));
9521
9522 /* Free... */
9523 free(help);
9524 free(help2);
9525}
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1124

◆ write_met()

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

Writes meteorological data to a binary file.

The write_met function writes meteorological data, including surface data and level data, to a binary file specified by the filename parameter. The data is written in binary format for efficient storage and transfer.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
metA pointer to a met_t structure containing meteorological data.

The function performs the following steps:

  • Sets a timer to measure the execution time.
  • Writes information about the meteorological data being written to the log.
  • Checks if compression flags are enabled and displays error messages if required compression methods are not available.
  • Writes binary data to the file, including the type and version of the data, grid data (time, dimensions, coordinates), surface data, and level data.
  • Closes the file after writing all data.
Returns
Returns an integer value indicating the success or failure of the function. A value of 0 indicates successful execution.
Note
This function supports writing meteorological data in different binary formats, including uncompressed and compressed formats using various compression algorithms such as packing, ZFP, ZSTD, and cmultiscale. The specific compression method used depends on the configuration specified in the ctl_t structure.
Author
Lars Hoffmann

Definition at line 9529 of file mptrac.c.

9532 {
9533
9534 /* Set timer... */
9535 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
9536
9537 /* Write info... */
9538 LOG(1, "Write meteo data: %s", filename);
9539
9540 /* Check compression flags... */
9541#ifndef ZFP
9542 if (ctl->met_type == 3)
9543 ERRMSG("MPTRAC was compiled without zfp compression!");
9544#endif
9545#ifndef ZSTD
9546 if (ctl->met_type == 4)
9547 ERRMSG("MPTRAC was compiled without zstd compression!");
9548#endif
9549#ifndef CMS
9550 if (ctl->met_type == 5)
9551 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
9552#endif
9553
9554 /* Write binary data... */
9555 if (ctl->met_type >= 1 && ctl->met_type <= 5) {
9556
9557 /* Create file... */
9558 FILE *out;
9559 if (!(out = fopen(filename, "w")))
9560 ERRMSG("Cannot create file!");
9561
9562 /* Write type of binary data... */
9563 FWRITE(&ctl->met_type, int,
9564 1,
9565 out);
9566
9567 /* Write version of binary data... */
9568 int version = 102;
9569 FWRITE(&version, int,
9570 1,
9571 out);
9572
9573 /* Write grid data... */
9574 FWRITE(&met->time, double,
9575 1,
9576 out);
9577 FWRITE(&met->nx, int,
9578 1,
9579 out);
9580 FWRITE(&met->ny, int,
9581 1,
9582 out);
9583 FWRITE(&met->np, int,
9584 1,
9585 out);
9586 FWRITE(met->lon, double,
9587 (size_t) met->nx,
9588 out);
9589 FWRITE(met->lat, double,
9590 (size_t) met->ny,
9591 out);
9592 FWRITE(met->p, double,
9593 (size_t) met->np,
9594 out);
9595
9596 /* Write surface data... */
9597 write_met_bin_2d(out, met, met->ps, "PS");
9598 write_met_bin_2d(out, met, met->ts, "TS");
9599 write_met_bin_2d(out, met, met->zs, "ZS");
9600 write_met_bin_2d(out, met, met->us, "US");
9601 write_met_bin_2d(out, met, met->vs, "VS");
9602 write_met_bin_2d(out, met, met->lsm, "LSM");
9603 write_met_bin_2d(out, met, met->sst, "SST");
9604 write_met_bin_2d(out, met, met->pbl, "PBL");
9605 write_met_bin_2d(out, met, met->pt, "PT");
9606 write_met_bin_2d(out, met, met->tt, "TT");
9607 write_met_bin_2d(out, met, met->zt, "ZT");
9608 write_met_bin_2d(out, met, met->h2ot, "H2OT");
9609 write_met_bin_2d(out, met, met->pct, "PCT");
9610 write_met_bin_2d(out, met, met->pcb, "PCB");
9611 write_met_bin_2d(out, met, met->cl, "CL");
9612 write_met_bin_2d(out, met, met->plcl, "PLCL");
9613 write_met_bin_2d(out, met, met->plfc, "PLFC");
9614 write_met_bin_2d(out, met, met->pel, "PEL");
9615 write_met_bin_2d(out, met, met->cape, "CAPE");
9616 write_met_bin_2d(out, met, met->cin, "CIN");
9617
9618 /* Write level data... */
9619 write_met_bin_3d(out, ctl, met, met->z, "Z",
9620 (ctl->met_zfp_tol_z <= 0 ? ctl->met_zfp_prec : 0),
9621 ctl->met_zfp_tol_z);
9622 write_met_bin_3d(out, ctl, met, met->t, "T",
9623 (ctl->met_zfp_tol_t <= 0 ? ctl->met_zfp_prec : 0),
9624 ctl->met_zfp_tol_t);
9625 write_met_bin_3d(out, ctl, met, met->u, "U", ctl->met_zfp_prec, 0);
9626 write_met_bin_3d(out, ctl, met, met->v, "V", ctl->met_zfp_prec, 0);
9627 write_met_bin_3d(out, ctl, met, met->w, "W", ctl->met_zfp_prec, 0);
9628 write_met_bin_3d(out, ctl, met, met->pv, "PV", ctl->met_zfp_prec, 0);
9629 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", ctl->met_zfp_prec, 0);
9630 write_met_bin_3d(out, ctl, met, met->o3, "O3", ctl->met_zfp_prec, 0);
9631 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", ctl->met_zfp_prec, 0);
9632 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", ctl->met_zfp_prec, 0);
9633 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", ctl->met_zfp_prec, 0);
9634 write_met_bin_3d(out, ctl, met, met->swc, "SWC", ctl->met_zfp_prec, 0);
9635 write_met_bin_3d(out, ctl, met, met->cc, "CC", ctl->met_zfp_prec, 0);
9636
9637 /* Write final flag... */
9638 int final = 999;
9639 FWRITE(&final, int,
9640 1,
9641 out);
9642
9643 /* Close file... */
9644 fclose(out);
9645 }
9646
9647 return 0;
9648}
void write_met_bin_3d(FILE *out, ctl_t *ctl, met_t *met, float var[EX][EY][EP], char *varname, int precision, double tolerance)
Writes a 3-dimensional meteorological variable to a binary file.
Definition: mptrac.c:9681
void write_met_bin_2d(FILE *out, met_t *met, float var[EX][EY], char *varname)
Writes a 2-dimensional meteorological variable to a binary file.
Definition: mptrac.c:9652
int met_zfp_prec
ZFP compression precision for all variables, except z and T.
Definition: mptrac.h:2471
double met_zfp_tol_t
ZFP compression tolerance for temperature.
Definition: mptrac.h:2474
double met_zfp_tol_z
ZFP compression tolerance for geopotential height.
Definition: mptrac.h:2477
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],
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 9652 of file mptrac.c.

9656 {
9657
9658 float *help;
9659
9660 /* Allocate... */
9661 ALLOC(help, float,
9662 EX * EY);
9663
9664 /* Copy data... */
9665 for (int ix = 0; ix < met->nx; ix++)
9666 for (int iy = 0; iy < met->ny; iy++)
9667 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
9668
9669 /* Write uncompressed data... */
9670 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
9671 FWRITE(help, float,
9672 (size_t) (met->nx * met->ny),
9673 out);
9674
9675 /* Free... */
9676 free(help);
9677}

◆ write_met_bin_3d()

void write_met_bin_3d ( FILE *  out,
ctl_t ctl,
met_t met,
float  var[EX][EY][EP],
char *  varname,
int  precision,
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 9681 of file mptrac.c.

9688 {
9689
9690 float *help;
9691
9692 /* Allocate... */
9693 ALLOC(help, float,
9694 EX * EY * EP);
9695
9696 /* Copy data... */
9697#pragma omp parallel for default(shared) collapse(2)
9698 for (int ix = 0; ix < met->nx; ix++)
9699 for (int iy = 0; iy < met->ny; iy++)
9700 for (int ip = 0; ip < met->np; ip++)
9701 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
9702
9703 /* Write uncompressed data... */
9704 if (ctl->met_type == 1) {
9705 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
9706 FWRITE(help, float,
9707 (size_t) (met->nx * met->ny * met->np),
9708 out);
9709 }
9710
9711 /* Write packed data... */
9712 else if (ctl->met_type == 2)
9713 compress_pck(varname, help, (size_t) (met->ny * met->nx),
9714 (size_t) met->np, 0, out);
9715
9716 /* Write zfp data... */
9717#ifdef ZFP
9718 else if (ctl->met_type == 3) {
9719 FWRITE(&precision, int,
9720 1,
9721 out);
9722 FWRITE(&tolerance, double,
9723 1,
9724 out);
9725 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
9726 tolerance, 0, out);
9727 }
9728#endif
9729
9730 /* Write zstd data... */
9731#ifdef ZSTD
9732 else if (ctl->met_type == 4)
9733 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
9734 out);
9735#endif
9736
9737 /* Write cmultiscale data... */
9738#ifdef CMS
9739 else if (ctl->met_type == 5) {
9740 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
9741 (size_t) met->np, 0, out);
9742 }
9743#endif
9744
9745 /* Unknown method... */
9746 else {
9747 ERRMSG("MET_TYPE not supported!");
9748 LOG(3, "%d %g", precision, tolerance);
9749 }
9750
9751 /* Free... */
9752 free(help);
9753}
Here is the call graph for this function:

◆ write_output()

void write_output ( const char *  dirname,
ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
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 9757 of file mptrac.c.

9763 {
9764
9765 char ext[10], filename[2 * LEN];
9766
9767 double r;
9768
9769 int year, mon, day, hour, min, sec;
9770
9771 /* Get time... */
9772 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9773
9774 /* Update host... */
9775#ifdef _OPENACC
9776 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
9777 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
9778 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
9779 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
9780 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
9781 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0)) {
9782 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_D2H);
9783#pragma acc update host(atm[:1])
9784 }
9785#endif
9786
9787 /* Write atmospheric data... */
9788 if (ctl->atm_basename[0] != '-' &&
9789 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
9790 if (ctl->atm_type_out == 0)
9791 sprintf(ext, "tab");
9792 else if (ctl->atm_type_out == 1)
9793 sprintf(ext, "bin");
9794 else if (ctl->atm_type_out == 2)
9795 sprintf(ext, "nc");
9796 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
9797 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
9798 write_atm(filename, ctl, atm, t);
9799 }
9800
9801 /* Write gridded data... */
9802 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
9803 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
9804 dirname, ctl->grid_basename, year, mon, day, hour, min,
9805 ctl->grid_type == 0 ? "tab" : "nc");
9806 write_grid(filename, ctl, met0, met1, atm, t);
9807 }
9808
9809 /* Write CSI data... */
9810 if (ctl->csi_basename[0] != '-') {
9811 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
9812 write_csi(filename, ctl, atm, t);
9813 }
9814
9815 /* Write ensemble data... */
9816 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
9817 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
9818 dirname, ctl->ens_basename, year, mon, day, hour, min);
9819 write_ens(filename, ctl, atm, t);
9820 }
9821
9822 /* Write profile data... */
9823 if (ctl->prof_basename[0] != '-') {
9824 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
9825 write_prof(filename, ctl, met0, met1, atm, t);
9826 }
9827
9828 /* Write sample data... */
9829 if (ctl->sample_basename[0] != '-') {
9830 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
9831 write_sample(filename, ctl, met0, met1, atm, t);
9832 }
9833
9834 /* Write station data... */
9835 if (ctl->stat_basename[0] != '-') {
9836 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
9837 write_station(filename, ctl, atm, t);
9838 }
9839
9840 /* Write VTK data... */
9841 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
9842 static int nvtk;
9843 if (t == ctl->t_start)
9844 nvtk = 0;
9845 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
9846 write_vtk(filename, ctl, atm, t);
9847 }
9848}
void write_vtk(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes VTK (Visualization Toolkit) data to a specified file.
Definition: mptrac.c:10329
void write_grid(const char *filename, ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double t)
Writes grid data to a file in ASCII or netCDF format.
Definition: mptrac.c:9109
void write_sample(const char *filename, ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double t)
Writes sample data to a specified file.
Definition: mptrac.c:10080
void write_station(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes station data to a specified file.
Definition: mptrac.c:10243
void write_atm(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes air parcel data to a file in various formats.
Definition: mptrac.c:8317
void write_csi(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes Critical Success Index (CSI) data to a file.
Definition: mptrac.c:8752
void write_prof(const char *filename, ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double t)
Writes profile data to a specified file.
Definition: mptrac.c:9852
void write_ens(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes ensemble data to a file.
Definition: mptrac.c:9012
Here is the call graph for this function:

◆ write_prof()

void write_prof ( const char *  filename,
ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
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 9852 of file mptrac.c.

9858 {
9859
9860 static FILE *out;
9861
9862 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
9863 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
9864
9865 static int nobs, *obscount, ip, okay;
9866
9867 /* Set timer... */
9868 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
9869
9870 /* Init... */
9871 if (t == ctl->t_start) {
9872
9873 /* Check quantity index for mass... */
9874 if (ctl->qnt_m < 0)
9875 ERRMSG("Need quantity mass!");
9876
9877 /* Check molar mass... */
9878 if (ctl->molmass <= 0)
9879 ERRMSG("Specify molar mass!");
9880
9881 /* Allocate... */
9882 ALLOC(lon, double,
9883 ctl->prof_nx);
9884 ALLOC(lat, double,
9885 ctl->prof_ny);
9886 ALLOC(area, double,
9887 ctl->prof_ny);
9888 ALLOC(z, double,
9889 ctl->prof_nz);
9890 ALLOC(press, double,
9891 ctl->prof_nz);
9892 ALLOC(rt, double,
9893 NOBS);
9894 ALLOC(rz, double,
9895 NOBS);
9896 ALLOC(rlon, double,
9897 NOBS);
9898 ALLOC(rlat, double,
9899 NOBS);
9900 ALLOC(robs, double,
9901 NOBS);
9902
9903 /* Read observation data... */
9904 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
9905
9906 /* Create new output file... */
9907 LOG(1, "Write profile data: %s", filename);
9908 if (!(out = fopen(filename, "w")))
9909 ERRMSG("Cannot create file!");
9910
9911 /* Write header... */
9912 fprintf(out,
9913 "# $1 = time [s]\n"
9914 "# $2 = altitude [km]\n"
9915 "# $3 = longitude [deg]\n"
9916 "# $4 = latitude [deg]\n"
9917 "# $5 = pressure [hPa]\n"
9918 "# $6 = temperature [K]\n"
9919 "# $7 = volume mixing ratio [ppv]\n"
9920 "# $8 = H2O volume mixing ratio [ppv]\n"
9921 "# $9 = O3 volume mixing ratio [ppv]\n"
9922 "# $10 = observed BT index [K]\n"
9923 "# $11 = number of observations\n");
9924
9925 /* Set grid box size... */
9926 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
9927 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
9928 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
9929
9930 /* Set vertical coordinates... */
9931 for (int iz = 0; iz < ctl->prof_nz; iz++) {
9932 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
9933 press[iz] = P(z[iz]);
9934 }
9935
9936 /* Set horizontal coordinates... */
9937 for (int ix = 0; ix < ctl->prof_nx; ix++)
9938 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
9939 for (int iy = 0; iy < ctl->prof_ny; iy++) {
9940 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
9941 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.)
9942 * cos(lat[iy] * M_PI / 180.);
9943 }
9944 }
9945
9946 /* Set time interval... */
9947 double t0 = t - 0.5 * ctl->dt_mod;
9948 double t1 = t + 0.5 * ctl->dt_mod;
9949
9950 /* Allocate... */
9951 ALLOC(mass, double,
9952 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
9953 ALLOC(obsmean, double,
9954 ctl->prof_nx * ctl->prof_ny);
9955 ALLOC(obscount, int,
9956 ctl->prof_nx * ctl->prof_ny);
9957
9958 /* Loop over observations... */
9959 for (int i = 0; i < nobs; i++) {
9960
9961 /* Check time... */
9962 if (rt[i] < t0)
9963 continue;
9964 else if (rt[i] >= t1)
9965 break;
9966
9967 /* Check observation data... */
9968 if (!isfinite(robs[i]))
9969 continue;
9970
9971 /* Calculate indices... */
9972 int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
9973 int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
9974
9975 /* Check indices... */
9976 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
9977 continue;
9978
9979 /* Get mean observation index... */
9980 int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
9981 obsmean[idx] += robs[i];
9982 obscount[idx]++;
9983 }
9984
9985 /* Analyze model data... */
9986 for (ip = 0; ip < atm->np; ip++) {
9987
9988 /* Check time... */
9989 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9990 continue;
9991
9992 /* Get indices... */
9993 int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
9994 int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
9995 int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
9996
9997 /* Check indices... */
9998 if (ix < 0 || ix >= ctl->prof_nx ||
9999 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
10000 continue;
10001
10002 /* Get total mass in grid cell... */
10003 int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10004 mass[idx] += atm->q[ctl->qnt_m][ip];
10005 }
10006
10007 /* Extract profiles... */
10008 for (int ix = 0; ix < ctl->prof_nx; ix++)
10009 for (int iy = 0; iy < ctl->prof_ny; iy++) {
10010 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
10011 if (obscount[idx2] > 0) {
10012
10013 /* Check profile... */
10014 okay = 0;
10015 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10016 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10017 if (mass[idx3] > 0) {
10018 okay = 1;
10019 break;
10020 }
10021 }
10022 if (!okay)
10023 continue;
10024
10025 /* Write output... */
10026 fprintf(out, "\n");
10027
10028 /* Loop over altitudes... */
10029 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10030
10031 /* Get temperature, water vapor, and ozone... */
10033 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
10034 lon[ix], lat[iy], &temp, ci, cw, 1);
10035 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
10036 lon[ix], lat[iy], &h2o, ci, cw, 0);
10037 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
10038 lon[ix], lat[iy], &o3, ci, cw, 0);
10039
10040 /* Calculate volume mixing ratio... */
10041 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10042 vmr = MA / ctl->molmass * mass[idx3]
10043 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
10044
10045 /* Write output... */
10046 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
10047 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
10048 obsmean[idx2] / obscount[idx2], obscount[idx2]);
10049 }
10050 }
10051 }
10052
10053 /* Free... */
10054 free(mass);
10055 free(obsmean);
10056 free(obscount);
10057
10058 /* Finalize... */
10059 if (t == ctl->t_stop) {
10060
10061 /* Close output file... */
10062 fclose(out);
10063
10064 /* Free... */
10065 free(lon);
10066 free(lat);
10067 free(area);
10068 free(z);
10069 free(press);
10070 free(rt);
10071 free(rz);
10072 free(rlon);
10073 free(rlat);
10074 free(robs);
10075 }
10076}
Here is the call graph for this function:

◆ write_sample()

void write_sample ( const char *  filename,
ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
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 10080 of file mptrac.c.

10086 {
10087
10088 static FILE *out;
10089
10090 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
10091 kw[EP];
10092
10093 static int nobs, nk;
10094
10095 /* Set timer... */
10096 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
10097
10098 /* Init... */
10099 if (t == ctl->t_start) {
10100
10101 /* Allocate... */
10102 ALLOC(rt, double,
10103 NOBS);
10104 ALLOC(rz, double,
10105 NOBS);
10106 ALLOC(rlon, double,
10107 NOBS);
10108 ALLOC(rlat, double,
10109 NOBS);
10110 ALLOC(robs, double,
10111 NOBS);
10112
10113 /* Read observation data... */
10114 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
10115
10116 /* Read kernel data... */
10117 if (ctl->sample_kernel[0] != '-')
10118 read_kernel(ctl->sample_kernel, kz, kw, &nk);
10119
10120 /* Create output file... */
10121 LOG(1, "Write sample data: %s", filename);
10122 if (!(out = fopen(filename, "w")))
10123 ERRMSG("Cannot create file!");
10124
10125 /* Write header... */
10126 fprintf(out,
10127 "# $1 = time [s]\n"
10128 "# $2 = altitude [km]\n"
10129 "# $3 = longitude [deg]\n"
10130 "# $4 = latitude [deg]\n"
10131 "# $5 = surface area [km^2]\n"
10132 "# $6 = layer depth [km]\n"
10133 "# $7 = number of particles [1]\n"
10134 "# $8 = column density [kg/m^2]\n"
10135 "# $9 = volume mixing ratio [ppv]\n"
10136 "# $10 = observed BT index [K]\n\n");
10137
10138 /* Set latitude range, squared radius, and area... */
10139 dlat = DY2DEG(ctl->sample_dx);
10140 rmax2 = SQR(ctl->sample_dx);
10141 area = M_PI * rmax2;
10142 }
10143
10144 /* Set time interval for output... */
10145 double t0 = t - 0.5 * ctl->dt_mod;
10146 double t1 = t + 0.5 * ctl->dt_mod;
10147
10148 /* Loop over observations... */
10149 for (int i = 0; i < nobs; i++) {
10150
10151 /* Check time... */
10152 if (rt[i] < t0)
10153 continue;
10154 else if (rt[i] >= t1)
10155 break;
10156
10157 /* Calculate Cartesian coordinates... */
10158 double x0[3];
10159 geo2cart(0, rlon[i], rlat[i], x0);
10160
10161 /* Set pressure range... */
10162 double rp = P(rz[i]);
10163 double ptop = P(rz[i] + ctl->sample_dz);
10164 double pbot = P(rz[i] - ctl->sample_dz);
10165
10166 /* Init... */
10167 double mass = 0;
10168 int np = 0;
10169
10170 /* Loop over air parcels... */
10171#pragma omp parallel for default(shared) reduction(+:mass,np)
10172 for (int ip = 0; ip < atm->np; ip++) {
10173
10174 /* Check time... */
10175 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10176 continue;
10177
10178 /* Check latitude... */
10179 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
10180 continue;
10181
10182 /* Check horizontal distance... */
10183 double x1[3];
10184 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
10185 if (DIST2(x0, x1) > rmax2)
10186 continue;
10187
10188 /* Check pressure... */
10189 if (ctl->sample_dz > 0)
10190 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
10191 continue;
10192
10193 /* Add mass... */
10194 if (ctl->qnt_m >= 0)
10195 mass +=
10196 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
10197 np++;
10198 }
10199
10200 /* Calculate column density... */
10201 double cd = mass / (1e6 * area);
10202
10203 /* Calculate volume mixing ratio... */
10204 double vmr = 0;
10205 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
10206 if (mass > 0) {
10207
10208 /* Get temperature... */
10209 double temp;
10211 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
10212 rlon[i], rlat[i], &temp, ci, cw, 1);
10213
10214 /* Calculate volume mixing ratio... */
10215 vmr = MA / ctl->molmass * mass
10216 / (RHO(rp, temp) * 1e6 * area * 1e3 * ctl->sample_dz);
10217 }
10218 } else
10219 vmr = NAN;
10220
10221 /* Write output... */
10222 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
10223 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
10224 }
10225
10226 /* Finalize...... */
10227 if (t == ctl->t_stop) {
10228
10229 /* Close output file... */
10230 fclose(out);
10231
10232 /* Free... */
10233 free(rt);
10234 free(rz);
10235 free(rlon);
10236 free(rlat);
10237 free(robs);
10238 }
10239}
Here is the call graph for this function:

◆ write_station()

void write_station ( const char *  filename,
ctl_t ctl,
atm_t atm,
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 10243 of file mptrac.c.

10247 {
10248
10249 static FILE *out;
10250
10251 static double rmax2, x0[3], x1[3];
10252
10253 /* Set timer... */
10254 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
10255
10256 /* Init... */
10257 if (t == ctl->t_start) {
10258
10259 /* Write info... */
10260 LOG(1, "Write station data: %s", filename);
10261
10262 /* Create new file... */
10263 if (!(out = fopen(filename, "w")))
10264 ERRMSG("Cannot create file!");
10265
10266 /* Write header... */
10267 fprintf(out,
10268 "# $1 = time [s]\n"
10269 "# $2 = altitude [km]\n"
10270 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
10271 for (int iq = 0; iq < ctl->nq; iq++)
10272 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
10273 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10274 fprintf(out, "\n");
10275
10276 /* Set geolocation and search radius... */
10277 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
10278 rmax2 = SQR(ctl->stat_r);
10279 }
10280
10281 /* Set time interval for output... */
10282 double t0 = t - 0.5 * ctl->dt_mod;
10283 double t1 = t + 0.5 * ctl->dt_mod;
10284
10285 /* Loop over air parcels... */
10286 for (int ip = 0; ip < atm->np; ip++) {
10287
10288 /* Check time... */
10289 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10290 continue;
10291
10292 /* Check time range for station output... */
10293 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
10294 continue;
10295
10296 /* Check station flag... */
10297 if (ctl->qnt_stat >= 0)
10298 if ((int) atm->q[ctl->qnt_stat][ip])
10299 continue;
10300
10301 /* Get Cartesian coordinates... */
10302 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
10303
10304 /* Check horizontal distance... */
10305 if (DIST2(x0, x1) > rmax2)
10306 continue;
10307
10308 /* Set station flag... */
10309 if (ctl->qnt_stat >= 0)
10310 atm->q[ctl->qnt_stat][ip] = 1;
10311
10312 /* Write data... */
10313 fprintf(out, "%.2f %g %g %g",
10314 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
10315 for (int iq = 0; iq < ctl->nq; iq++) {
10316 fprintf(out, " ");
10317 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
10318 }
10319 fprintf(out, "\n");
10320 }
10321
10322 /* Close file... */
10323 if (t == ctl->t_stop)
10324 fclose(out);
10325}
Here is the call graph for this function:

◆ write_vtk()

void write_vtk ( const char *  filename,
ctl_t ctl,
atm_t atm,
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 10329 of file mptrac.c.

10333 {
10334
10335 FILE *out;
10336
10337 /* Set timer... */
10338 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
10339
10340 /* Write info... */
10341 LOG(1, "Write VTK data: %s", filename);
10342
10343 /* Set time interval for output... */
10344 double t0 = t - 0.5 * ctl->dt_mod;
10345 double t1 = t + 0.5 * ctl->dt_mod;
10346
10347 /* Create file... */
10348 if (!(out = fopen(filename, "w")))
10349 ERRMSG("Cannot create file!");
10350
10351 /* Count data points... */
10352 int np = 0;
10353 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10354 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10355 continue;
10356 np++;
10357 }
10358
10359 /* Write header... */
10360 fprintf(out,
10361 "# vtk DataFile Version 3.0\n"
10362 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
10363
10364 /* Write point coordinates... */
10365 fprintf(out, "POINTS %d float\n", np);
10366 if (ctl->vtk_sphere) {
10367 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10368 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10369 continue;
10370 double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
10371 + ctl->vtk_offset) / RE;
10372 double x = radius * cos(atm->lat[ip] / 180. * M_PI)
10373 * cos(atm->lon[ip] / 180. * M_PI);
10374 double y = radius * cos(atm->lat[ip] / 180. * M_PI)
10375 * sin(atm->lon[ip] / 180. * M_PI);
10376 double z = radius * sin(atm->lat[ip] / 180. * M_PI);
10377 fprintf(out, "%g %g %g\n", x, y, z);
10378 }
10379 } else
10380 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10381 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10382 continue;
10383 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
10384 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
10385 }
10386
10387 /* Write point data... */
10388 fprintf(out, "POINT_DATA %d\n", np);
10389 for (int iq = 0; iq < ctl->nq; iq++) {
10390 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
10391 ctl->qnt_name[iq]);
10392 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10393 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10394 continue;
10395 fprintf(out, "%g\n", atm->q[iq][ip]);
10396 }
10397 }
10398
10399 /* Close file... */
10400 fclose(out);
10401}