MPTRAC
Data Structures | Macros | Functions
mptrac.h File Reference

MPTRAC library declarations. More...

#include <ctype.h>
#include <gsl/gsl_fft_complex.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_sort.h>
#include <gsl/gsl_spline.h>
#include <gsl/gsl_statistics.h>
#include <math.h>
#include <netcdf.h>
#include <omp.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

Go to the source code of this file.

Data Structures

struct  ctl_t
 Control parameters. More...
 
struct  atm_t
 Air parcel data. More...
 
struct  particle_t
 Particle data. More...
 
struct  cache_t
 Cache data structure. More...
 
struct  depo_t
 Ground inventories of deposited radionuclides. More...
 
struct  clim_photo_t
 Climatological data in the form of photolysis rates. More...
 
struct  clim_ts_t
 Climatological data in the form of time series. More...
 
struct  clim_zm_t
 Climatological data in the form of zonal means. More...
 
struct  clim_t
 Climatological data. More...
 
struct  met_t
 Meteo data structure. More...
 
struct  dd_t
 Domain decomposition data structure. More...
 

Macros

#define codes_handle   void*
 Placeholder when ECCODES is not available. More...
 
#define AVO   6.02214076e23
 Avogadro constant [1/mol]. More...
 
#define CPD   1003.5
 Specific heat of dry air at constant pressure [J/(kg K)]. More...
 
#define EPS   (MH2O / MA)
 Ratio of the specific gas constant of dry air and water vapor [1]. More...
 
#define G0   9.80665
 Standard gravity [m/s^2]. More...
 
#define H0   7.0
 Scale height [km]. More...
 
#define LV   2501000.
 Latent heat of vaporization of water [J/kg]. More...
 
#define KARMAN   0.40
 Karman's constant. More...
 
#define KB   1.3806504e-23
 Boltzmann constant [kg m^2/(K s^2)]. More...
 
#define MA   28.9644
 Molar mass of dry air [g/mol]. More...
 
#define MH2O   18.01528
 Molar mass of water vapor [g/mol]. More...
 
#define MO3   48.00
 Molar mass of ozone [g/mol]. More...
 
#define P0   1013.25
 Standard pressure [hPa]. More...
 
#define RA   (1e3 * RI / MA)
 Specific gas constant of dry air [J/(kg K)]. More...
 
#define RE   6367.421
 Mean radius of Earth [km]. More...
 
#define RI   8.3144598
 Ideal gas constant [J/(mol K)]. More...
 
#define KAPPA   0.286
 Exponent used for potential-temperature calculations [1]. More...
 
#define OMEGA_EARTH   7.2921e-5
 Angular velocity of Earth [s^-1]. More...
 
#define DOBSON_UNIT   2.1415e-5
 Ozone column mass corresponding to one Dobson unit [kg/m^2]. More...
 
#define M_AIR_MOLECULE   4.8096e-26
 Mean mass of an air molecule [kg]. More...
 
#define CHEM_REF_TEMP   298.15
 Reference temperature for chemical equilibrium constants [K]. More...
 
#define H2O2_SO2_RATE_REF   9.1e7
 Reference rate for aqueous H2O2-SO2 chemistry [L^2/(mol^2 s)]. More...
 
#define H2O2_SO2_RATE_TEMP   29700.
 Temperature parameter for the aqueous H2O2-SO2 rate [K]. More...
 
#define SO2_HENRY_REF   1.3e-2
 Henry constant of SO2 at CHEM_REF_TEMP [mol/(L atm)]. More...
 
#define SO2_HENRY_TEMP   2900.
 Temperature dependence of the SO2 Henry constant [K]. More...
 
#define H2O2_HENRY_REF   8.3e2
 Henry constant of H2O2 at CHEM_REF_TEMP [mol/(L atm)]. More...
 
#define H2O2_HENRY_TEMP   7600.
 Temperature dependence of the H2O2 Henry constant [K]. More...
 
#define SO2_CORR_A   3.12541941e-06
 Scale factor of the high-SO2 correction [1]. More...
 
#define SO2_CORR_B   -5.72532259e-01
 Exponent of the high-SO2 correction [1]. More...
 
#define O1D_RATE_CCL4_A   3.30e-10
 O(1D) reaction pre-factor for CCl4 [cm^3/s]. More...
 
#define O1D_RATE_CCL4_B   0.
 O(1D) reaction temperature parameter for CCl4 [K]. More...
 
#define O1D_RATE_CFC11_A   2.30e-10
 O(1D) reaction pre-factor for CFC-11 [cm^3/s]. More...
 
#define O1D_RATE_CFC11_B   0.
 O(1D) reaction temperature parameter for CFC-11 [K]. More...
 
#define O1D_RATE_CFC12_A   1.40e-10
 O(1D) reaction pre-factor for CFC-12 [cm^3/s]. More...
 
#define O1D_RATE_CFC12_B   -25.
 O(1D) reaction temperature parameter for CFC-12 [K]. More...
 
#define O1D_RATE_N2O_A   1.19e-10
 O(1D) reaction pre-factor for N2O [cm^3/s]. More...
 
#define O1D_RATE_N2O_B   -20.
 O(1D) reaction temperature parameter for N2O [K]. More...
 
#define SO2_DISS_K1_REF   1.23e-2
 First SO2 dissociation constant at CHEM_REF_TEMP [mol/L]. More...
 
#define SO2_DISS_K1_TEMP   2.01e3
 Temperature dependence of the first SO2 dissociation constant [K]. More...
 
#define SO2_DISS_K2_REF   6e-8
 Second SO2 dissociation constant at CHEM_REF_TEMP [mol/L]. More...
 
#define SO2_DISS_K2_TEMP   1.12e3
 Temperature dependence of the second SO2 dissociation constant [K]. More...
 
#define WET_DEPO_T_LIQUID   T0
 Upper temperature of the ice-cloud retention transition [K]. More...
 
#define WET_DEPO_T_ICE   238.15
 Lower temperature of the ice-cloud retention transition [K]. More...
 
#define WET_DEPO_T_LIQUID_BC   270.
 Temperature threshold for below-cloud retention [K]. More...
 
#define RADIO_HALF_LIFE_RN222   (3.8235 * 86400.0)
 Half-life of Rn-222 [s]. More...
 
#define RADIO_HALF_LIFE_PB210   (22.3 * 365.25 * 86400.0)
 Half-life of Pb-210 [s]. More...
 
#define RADIO_HALF_LIFE_BE7   (53.22 * 86400.0)
 Half-life of Be-7 [s]. More...
 
#define RADIO_HALF_LIFE_CS137   (30.05 * 365.25 * 86400.0)
 Half-life of Cs-137 [s]. More...
 
#define RADIO_HALF_LIFE_I131   (8.02 * 86400.0)
 Half-life of I-131 [s]. More...
 
#define RADIO_HALF_LIFE_XE133   (5.2474 * 86400.0)
 Half-life of Xe-133 [s]. More...
 
#define RADIO_DRY_VDEP_PB210   0.002
 Dry deposition velocity of Pb-210 [m/s]. More...
 
#define RADIO_DRY_VDEP_BE7   0.001
 Dry deposition velocity of Be-7 [m/s]. More...
 
#define RADIO_DRY_VDEP_CS137   0.002
 Dry deposition velocity of Cs-137 [m/s]. More...
 
#define RADIO_DRY_VDEP_I131   0.0005
 Dry deposition velocity of aerosol-bound I-131 [m/s]. More...
 
#define RADIO_WET_COEFF_PB210   1e-4
 Wet deposition coefficient of Pb-210 [s^-1]. More...
 
#define RADIO_WET_COEFF_BE7   5e-5
 Wet deposition coefficient of Be-7 [s^-1]. More...
 
#define RADIO_WET_COEFF_CS137   1e-4
 Wet deposition coefficient of Cs-137 [s^-1]. More...
 
#define RADIO_WET_COEFF_I131   5e-5
 Wet deposition coefficient of aerosol-bound I-131 [s^-1]. More...
 
#define T0   273.15
 Standard temperature [K]. More...
 
#define EP   140
 Maximum number of pressure levels for meteo data. More...
 
#define EX   1444
 Maximum number of longitudes for meteo data. More...
 
#define EY   724
 Maximum number of latitudes for meteo data. More...
 
#define LEN   5000
 Maximum length of ASCII data lines. More...
 
#define METVAR   13
 Number of 3-D meteorological variables. More...
 
#define NP   10000000
 Maximum number of atmospheric data points. More...
 
#define NQ   15
 Maximum number of quantities per data point. More...
 
#define NCSI   1000000
 Maximum number of data points for CSI calculation. More...
 
#define NENS   2000
 Maximum number of data points for ensemble analysis. More...
 
#define NOBS   10000000
 Maximum number of observation data points. More...
 
#define NTHREADS   512
 Maximum number of OpenMP threads. More...
 
#define CY   250
 Maximum number of latitudes for climatological data. More...
 
#define CO3   30
 Maximum number of total column ozone data for climatological data. More...
 
#define CP   70
 Maximum number of pressure levels for climatological data. More...
 
#define CSZA   50
 Maximum number of solar zenith angles for climatological data. More...
 
#define CT   12
 Maximum number of time steps for climatological data. More...
 
#define CTS   1000
 Maximum number of data points of climatological time series. More...
 
#define DD_EX_GLOB   (EX * 16)
 Maximum number of longitudes of global meteo data. More...
 
#define DD_EY_GLOB   (EY * 16)
 Maximum number of latitudes of global meteo data. More...
 
#define ALLOC(ptr, type, n)
 Allocate memory for a pointer with error handling. More...
 
#define ARRAY_2D(ix, iy, ny)    ((ix) * (ny) + (iy))
 Macro for computing the linear index of a 2D array element. More...
 
#define ARRAY_3D(ix, iy, ny, iz, nz)    (((ix)*(ny) + (iy)) * (nz) + (iz))
 Compute the linear index of a 3D array element. More...
 
#define ARRHENIUS(a, b, t)    ((a) * exp( -(b) / (t)))
 Calculate the Arrhenius rate constant. More...
 
#define CLAMP(v, lo, hi)    (((v) < (lo)) ? (lo) : (((v) > (hi)) ? (hi) : (v)))
 Clamp a value to a specified range. More...
 
#define COMPRESS_SPEED(nbytes, dt)    ((dt) > 0 ? ((double)(nbytes)) / ((dt) * 1024. * 1024.) : NAN)
 Calculate compression throughput in MiB/s. More...
 
#define COMPRESS_RATIO(raw_size, stored_size)    ((double) (raw_size) / (double) (stored_size))
 Calculate the compression ratio from raw and stored byte counts. More...
 
#define COMPRESS_BPV(n, stored_size)    ((8.0 * (double) (stored_size)) / (double) (n))
 Calculate bits per value from stored size and element count. More...
 
#define DEG2DX(dlon, lat)    (RE * DEG2RAD(dlon) * cos(DEG2RAD(lat)))
 Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude. More...
 
#define DEG2DY(dlat)    (RE * DEG2RAD(dlat))
 Convert a latitude difference to a distance in the y-direction (north-south). More...
 
#define DEG2RAD(deg)    ((deg) * (M_PI / 180.0))
 Converts degrees to radians. More...
 
#define DP2DZ(dp, p)    (- (dp) * H0 / (p))
 Convert a pressure difference to a height difference in the vertical direction. More...
 
#define DX2DEG(dx, lat)
 Convert a distance in kilometers to degrees longitude at a given latitude. More...
 
#define DY2DEG(dy)    ((dy) * 180. / (M_PI * RE))
 Convert a distance in kilometers to degrees latitude. More...
 
#define DZ2DP(dz, p)    (-(dz) * (p) / H0)
 Convert a change in altitude to a change in pressure. More...
 
#define DX2COORD(met, dx, lat)   (((met)->coord_type == 0)? DX2DEG((dx) / 1000.0, (lat)) : ((dx) ))
 Convert a distance in meters to a coordinate value based on grid type. More...
 
#define DY2COORD(met, dy)   (((met)->coord_type == 0)? DY2DEG((dy) / 1000.0) : ((dy) ))
 Convert a distance to coordinate value based on grid type. More...
 
#define DIST(a, b)    sqrt(DIST2(a, b))
 Calculate the distance between two points in Cartesian coordinates. More...
 
#define DIST2(a, b)    ((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])+(a[2]-b[2])*(a[2]-b[2]))
 Calculate the squared Euclidean distance between two points in Cartesian coordinates. More...
 
#define DOTP(a, b)    (a[0]*b[0]+a[1]*b[1]+a[2]*b[2])
 Calculate the dot product of two vectors. More...
 
#define ECC(cmd)
 Execute an ECCODES command and check for errors. More...
 
#define ECC_READ_2D(variable, target, scaling_factor, found_flag)
 Writes 2-D data from a grib message into the meteo struct. More...
 
#define ECC_READ_3D(variable, level, target, scaling_factor, found_flag)
 Writes 3D data from a grib message into the meteo struct. More...
 
#define FMOD(x, y)    ((x) - (int) ((x) / (y)) * (y))
 Calculate the floating-point remainder of dividing x by y. More...
 
#define FREAD(ptr, type, size, in)
 Read data from a file stream and store it in memory. More...
 
#define FWRITE(ptr, type, size, out)
 Write data from memory to a file stream. More...
 
#define INTPOL_INIT    double cw[4] = {0.0, 0.0, 0.0, 0.0}; int ci[3] = {0, 0, 0};
 Initialize arrays for interpolation. More...
 
#define INTPOL_2D(var, init)
 Perform 2D interpolation for a meteorological variable. More...
 
#define INTPOL_3D(var, init)
 Perform 3D interpolation for a meteorological variable. More...
 
#define INTPOL_SPACE_ALL(p, lon, lat)
 Interpolate multiple meteorological variables in space. More...
 
#define INTPOL_TIME_ALL(time, p, lon, lat)
 Interpolate multiple meteorological variables in time. More...
 
#define LAPSE(p1, t1, p2, t2)
 Calculate lapse rate. More...
 
#define LIN(x0, y0, x1, y1, x)    ((y0)+((y1)-(y0))/((x1)-(x0))*((x)-(x0)))
 Linear interpolation. More...
 
#define MAX(a, b)    (((a)>(b))?(a):(b))
 Macro to determine the maximum of two values. More...
 
#define MET_HEADER
 Write header for meteorological data file. More...
 
#define MIN(a, b)    (((a)<(b))?(a):(b))
 Macro to determine the minimum of two values. More...
 
#define MOLEC_DENS(p, t)    (AVO * 1e-6 * ((p) * 100) / (RI * (t)))
 Calculate the density of a gas molecule. More...
 
#define NC(cmd)
 Execute a NetCDF command and check for errors. More...
 
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
 Define a NetCDF variable with attributes. More...
 
#define NC_DEF_VAR_QUANTIZE(quant)
 
#define NC_GET_DOUBLE(varname, ptr, force)
 Retrieve a double-precision variable from a NetCDF file. More...
 
#define NC_INQ_DIM(dimname, ptr, min, max, check)
 Inquire the length of a dimension in a NetCDF file. More...
 
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
 Write double precision data to a NetCDF variable. More...
 
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
 Write a float array to a NetCDF file. More...
 
#define NC_PUT_INT(varname, ptr, hyperslab)
 Write integer data to a NetCDF variable. More...
 
#define NC_PUT_ATT(varname, attname, text)
 Add a text attribute to a NetCDF variable. More...
 
#define NC_PUT_ATT_GLOBAL(attname, text)    NC(nc_put_att_text(ncid, NC_GLOBAL, attname, strnlen(text, LEN), text));
 Add a global text attribute to a NetCDF file. More...
 
#define NN(x0, y0, x1, y1, x)    (fabs((x) - (x0)) <= fabs((x) - (x1)) ? (y0) : (y1))
 Perform nearest-neighbor interpolation. More...
 
#define PARTICLE_LOOP(ip0, ip1, check_dt, ...)
 Loop over particle indices with OpenACC acceleration. More...
 
#define P(z)    (P0 * exp(-(z) / H0))
 Compute pressure at given altitude. More...
 
#define PSAT(t)    (6.112 * exp(17.62 * ((t) - T0) / (243.12 + (t) - T0)))
 Compute saturation pressure over water. More...
 
#define PSICE(t)    (6.112 * exp(22.46 * ((t) - T0) / (272.62 + (t) - T0)))
 Compute saturation pressure over ice (WMO, 2018). More...
 
#define PW(p, h2o)    ((p) * MAX((h2o), 0.1e-6) / (1. + (1. - EPS) * MAX((h2o), 0.1e-6)))
 Calculate partial water vapor pressure. More...
 
#define RAD2DEG(rad)    ((rad) * (180.0 / M_PI))
 Converts radians to degrees. More...
 
#define RH(p, t, h2o)    (PW(p, h2o) / PSAT(t) * 100.)
 Compute relative humidity over water. More...
 
#define RHICE(p, t, h2o)    (PW(p, h2o) / PSICE(t) * 100.)
 Compute relative humidity over ice. More...
 
#define RHO(p, t)    (100. * (p) / (RA * (t)))
 Compute density of air. More...
 
#define SET_ATM(qnt, val)
 Set atmospheric quantity value. More...
 
#define SET_QNT(qnt, name, longname, unit)
 Set atmospheric quantity index. More...
 
#define SH(h2o)    (EPS * MAX((h2o), 0.1e-6))
 Compute specific humidity from water vapor volume mixing ratio. More...
 
#define SQR(x)    ((x)*(x))
 Compute the square of a value. More...
 
#define SWAP(x, y, type)    do {type tmp = x; x = y; y = tmp;} while(0);
 Swap two values. More...
 
#define TDEW(p, h2o)
 Calculate dew point temperature. More...
 
#define TICE(p, h2o)
 Calculate frost point temperature (WMO, 2018). More...
 
#define THETA(p, t)    ((t) * pow(1000. / (p), KAPPA))
 Compute potential temperature. More...
 
#define THETAVIRT(p, t, h2o)    (TVIRT(THETA((p), (t)), MAX((h2o), 0.1e-6)))
 Compute virtual potential temperature. More...
 
#define TOK(line, tok, format, var)
 Get string tokens. More...
 
#define TVIRT(t, h2o)    ((t) * (1. + (1. - EPS) * MAX((h2o), 0.1e-6)))
 Compute virtual temperature. More...
 
#define USAGE
 Print usage information on -h or --help. More...
 
#define Z(p)    (H0 * log(P0 / (p)))
 Convert pressure to altitude. More...
 
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
 Calculate geopotential height difference. More...
 
#define ZETA(ps, p, t)
 Computes the value of the zeta vertical coordinate. More...
 
#define LOGLEV   2
 Level of log messages (0=none, 1=basic, 2=detailed, 3=debug). More...
 
#define LOG(level, ...)
 Print a log message with a specified logging level. More...
 
#define WARN(...)
 Print a warning message with contextual information. More...
 
#define ERRMSG(...)
 Print an error message with contextual information and terminate the program. More...
 
#define PRINT(format, var)
 Print the value of a variable with contextual information. More...
 
#define NTIMER   100
 Maximum number of timers. More...
 
#define PRINT_TIMERS    timer("END", "END", 1);
 Print the current state of all timers. More...
 
#define SELECT_TIMER(id, group)    timer(id, group, 0);
 Select and start a timer with specific attributes. More...
 

Functions

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

Detailed Description

MPTRAC library declarations.

Definition in file mptrac.h.

Macro Definition Documentation

◆ codes_handle

#define codes_handle   void*

Placeholder when ECCODES is not available.

Definition at line 240 of file mptrac.h.

◆ AVO

#define AVO   6.02214076e23

Avogadro constant [1/mol].

Definition at line 249 of file mptrac.h.

◆ CPD

#define CPD   1003.5

Specific heat of dry air at constant pressure [J/(kg K)].

Definition at line 254 of file mptrac.h.

◆ EPS

#define EPS   (MH2O / MA)

Ratio of the specific gas constant of dry air and water vapor [1].

Definition at line 259 of file mptrac.h.

◆ G0

#define G0   9.80665

Standard gravity [m/s^2].

Definition at line 264 of file mptrac.h.

◆ H0

#define H0   7.0

Scale height [km].

Definition at line 269 of file mptrac.h.

◆ LV

#define LV   2501000.

Latent heat of vaporization of water [J/kg].

Definition at line 274 of file mptrac.h.

◆ KARMAN

#define KARMAN   0.40

Karman's constant.

Definition at line 279 of file mptrac.h.

◆ KB

#define KB   1.3806504e-23

Boltzmann constant [kg m^2/(K s^2)].

Definition at line 284 of file mptrac.h.

◆ MA

#define MA   28.9644

Molar mass of dry air [g/mol].

Definition at line 289 of file mptrac.h.

◆ MH2O

#define MH2O   18.01528

Molar mass of water vapor [g/mol].

Definition at line 294 of file mptrac.h.

◆ MO3

#define MO3   48.00

Molar mass of ozone [g/mol].

Definition at line 299 of file mptrac.h.

◆ P0

#define P0   1013.25

Standard pressure [hPa].

Definition at line 304 of file mptrac.h.

◆ RA

#define RA   (1e3 * RI / MA)

Specific gas constant of dry air [J/(kg K)].

Definition at line 309 of file mptrac.h.

◆ RE

#define RE   6367.421

Mean radius of Earth [km].

Definition at line 314 of file mptrac.h.

◆ RI

#define RI   8.3144598

Ideal gas constant [J/(mol K)].

Definition at line 319 of file mptrac.h.

◆ KAPPA

#define KAPPA   0.286

Exponent used for potential-temperature calculations [1].

Definition at line 324 of file mptrac.h.

◆ OMEGA_EARTH

#define OMEGA_EARTH   7.2921e-5

Angular velocity of Earth [s^-1].

Definition at line 329 of file mptrac.h.

◆ DOBSON_UNIT

#define DOBSON_UNIT   2.1415e-5

Ozone column mass corresponding to one Dobson unit [kg/m^2].

Definition at line 334 of file mptrac.h.

◆ M_AIR_MOLECULE

#define M_AIR_MOLECULE   4.8096e-26

Mean mass of an air molecule [kg].

Definition at line 339 of file mptrac.h.

◆ CHEM_REF_TEMP

#define CHEM_REF_TEMP   298.15

Reference temperature for chemical equilibrium constants [K].

Definition at line 344 of file mptrac.h.

◆ H2O2_SO2_RATE_REF

#define H2O2_SO2_RATE_REF   9.1e7

Reference rate for aqueous H2O2-SO2 chemistry [L^2/(mol^2 s)].

Definition at line 349 of file mptrac.h.

◆ H2O2_SO2_RATE_TEMP

#define H2O2_SO2_RATE_TEMP   29700.

Temperature parameter for the aqueous H2O2-SO2 rate [K].

Definition at line 354 of file mptrac.h.

◆ SO2_HENRY_REF

#define SO2_HENRY_REF   1.3e-2

Henry constant of SO2 at CHEM_REF_TEMP [mol/(L atm)].

Definition at line 359 of file mptrac.h.

◆ SO2_HENRY_TEMP

#define SO2_HENRY_TEMP   2900.

Temperature dependence of the SO2 Henry constant [K].

Definition at line 364 of file mptrac.h.

◆ H2O2_HENRY_REF

#define H2O2_HENRY_REF   8.3e2

Henry constant of H2O2 at CHEM_REF_TEMP [mol/(L atm)].

Definition at line 369 of file mptrac.h.

◆ H2O2_HENRY_TEMP

#define H2O2_HENRY_TEMP   7600.

Temperature dependence of the H2O2 Henry constant [K].

Definition at line 374 of file mptrac.h.

◆ SO2_CORR_A

#define SO2_CORR_A   3.12541941e-06

Scale factor of the high-SO2 correction [1].

Definition at line 379 of file mptrac.h.

◆ SO2_CORR_B

#define SO2_CORR_B   -5.72532259e-01

Exponent of the high-SO2 correction [1].

Definition at line 384 of file mptrac.h.

◆ O1D_RATE_CCL4_A

#define O1D_RATE_CCL4_A   3.30e-10

O(1D) reaction pre-factor for CCl4 [cm^3/s].

Definition at line 389 of file mptrac.h.

◆ O1D_RATE_CCL4_B

#define O1D_RATE_CCL4_B   0.

O(1D) reaction temperature parameter for CCl4 [K].

Definition at line 394 of file mptrac.h.

◆ O1D_RATE_CFC11_A

#define O1D_RATE_CFC11_A   2.30e-10

O(1D) reaction pre-factor for CFC-11 [cm^3/s].

Definition at line 399 of file mptrac.h.

◆ O1D_RATE_CFC11_B

#define O1D_RATE_CFC11_B   0.

O(1D) reaction temperature parameter for CFC-11 [K].

Definition at line 404 of file mptrac.h.

◆ O1D_RATE_CFC12_A

#define O1D_RATE_CFC12_A   1.40e-10

O(1D) reaction pre-factor for CFC-12 [cm^3/s].

Definition at line 409 of file mptrac.h.

◆ O1D_RATE_CFC12_B

#define O1D_RATE_CFC12_B   -25.

O(1D) reaction temperature parameter for CFC-12 [K].

Definition at line 414 of file mptrac.h.

◆ O1D_RATE_N2O_A

#define O1D_RATE_N2O_A   1.19e-10

O(1D) reaction pre-factor for N2O [cm^3/s].

Definition at line 419 of file mptrac.h.

◆ O1D_RATE_N2O_B

#define O1D_RATE_N2O_B   -20.

O(1D) reaction temperature parameter for N2O [K].

Definition at line 424 of file mptrac.h.

◆ SO2_DISS_K1_REF

#define SO2_DISS_K1_REF   1.23e-2

First SO2 dissociation constant at CHEM_REF_TEMP [mol/L].

Definition at line 429 of file mptrac.h.

◆ SO2_DISS_K1_TEMP

#define SO2_DISS_K1_TEMP   2.01e3

Temperature dependence of the first SO2 dissociation constant [K].

Definition at line 434 of file mptrac.h.

◆ SO2_DISS_K2_REF

#define SO2_DISS_K2_REF   6e-8

Second SO2 dissociation constant at CHEM_REF_TEMP [mol/L].

Definition at line 439 of file mptrac.h.

◆ SO2_DISS_K2_TEMP

#define SO2_DISS_K2_TEMP   1.12e3

Temperature dependence of the second SO2 dissociation constant [K].

Definition at line 444 of file mptrac.h.

◆ WET_DEPO_T_LIQUID

#define WET_DEPO_T_LIQUID   T0

Upper temperature of the ice-cloud retention transition [K].

Definition at line 449 of file mptrac.h.

◆ WET_DEPO_T_ICE

#define WET_DEPO_T_ICE   238.15

Lower temperature of the ice-cloud retention transition [K].

Definition at line 454 of file mptrac.h.

◆ WET_DEPO_T_LIQUID_BC

#define WET_DEPO_T_LIQUID_BC   270.

Temperature threshold for below-cloud retention [K].

Definition at line 459 of file mptrac.h.

◆ RADIO_HALF_LIFE_RN222

#define RADIO_HALF_LIFE_RN222   (3.8235 * 86400.0)

Half-life of Rn-222 [s].

Definition at line 464 of file mptrac.h.

◆ RADIO_HALF_LIFE_PB210

#define RADIO_HALF_LIFE_PB210   (22.3 * 365.25 * 86400.0)

Half-life of Pb-210 [s].

Definition at line 469 of file mptrac.h.

◆ RADIO_HALF_LIFE_BE7

#define RADIO_HALF_LIFE_BE7   (53.22 * 86400.0)

Half-life of Be-7 [s].

Definition at line 474 of file mptrac.h.

◆ RADIO_HALF_LIFE_CS137

#define RADIO_HALF_LIFE_CS137   (30.05 * 365.25 * 86400.0)

Half-life of Cs-137 [s].

Definition at line 479 of file mptrac.h.

◆ RADIO_HALF_LIFE_I131

#define RADIO_HALF_LIFE_I131   (8.02 * 86400.0)

Half-life of I-131 [s].

Definition at line 484 of file mptrac.h.

◆ RADIO_HALF_LIFE_XE133

#define RADIO_HALF_LIFE_XE133   (5.2474 * 86400.0)

Half-life of Xe-133 [s].

Definition at line 489 of file mptrac.h.

◆ RADIO_DRY_VDEP_PB210

#define RADIO_DRY_VDEP_PB210   0.002

Dry deposition velocity of Pb-210 [m/s].

Definition at line 494 of file mptrac.h.

◆ RADIO_DRY_VDEP_BE7

#define RADIO_DRY_VDEP_BE7   0.001

Dry deposition velocity of Be-7 [m/s].

Definition at line 499 of file mptrac.h.

◆ RADIO_DRY_VDEP_CS137

#define RADIO_DRY_VDEP_CS137   0.002

Dry deposition velocity of Cs-137 [m/s].

Definition at line 504 of file mptrac.h.

◆ RADIO_DRY_VDEP_I131

#define RADIO_DRY_VDEP_I131   0.0005

Dry deposition velocity of aerosol-bound I-131 [m/s].

Definition at line 509 of file mptrac.h.

◆ RADIO_WET_COEFF_PB210

#define RADIO_WET_COEFF_PB210   1e-4

Wet deposition coefficient of Pb-210 [s^-1].

Definition at line 514 of file mptrac.h.

◆ RADIO_WET_COEFF_BE7

#define RADIO_WET_COEFF_BE7   5e-5

Wet deposition coefficient of Be-7 [s^-1].

Definition at line 519 of file mptrac.h.

◆ RADIO_WET_COEFF_CS137

#define RADIO_WET_COEFF_CS137   1e-4

Wet deposition coefficient of Cs-137 [s^-1].

Definition at line 524 of file mptrac.h.

◆ RADIO_WET_COEFF_I131

#define RADIO_WET_COEFF_I131   5e-5

Wet deposition coefficient of aerosol-bound I-131 [s^-1].

Definition at line 529 of file mptrac.h.

◆ T0

#define T0   273.15

Standard temperature [K].

Definition at line 534 of file mptrac.h.

◆ EP

#define EP   140

Maximum number of pressure levels for meteo data.

Definition at line 543 of file mptrac.h.

◆ EX

#define EX   1444

Maximum number of longitudes for meteo data.

Definition at line 548 of file mptrac.h.

◆ EY

#define EY   724

Maximum number of latitudes for meteo data.

Definition at line 553 of file mptrac.h.

◆ LEN

#define LEN   5000

Maximum length of ASCII data lines.

Definition at line 558 of file mptrac.h.

◆ METVAR

#define METVAR   13

Number of 3-D meteorological variables.

Definition at line 563 of file mptrac.h.

◆ NP

#define NP   10000000

Maximum number of atmospheric data points.

Definition at line 568 of file mptrac.h.

◆ NQ

#define NQ   15

Maximum number of quantities per data point.

Definition at line 573 of file mptrac.h.

◆ NCSI

#define NCSI   1000000

Maximum number of data points for CSI calculation.

Definition at line 578 of file mptrac.h.

◆ NENS

#define NENS   2000

Maximum number of data points for ensemble analysis.

Definition at line 583 of file mptrac.h.

◆ NOBS

#define NOBS   10000000

Maximum number of observation data points.

Definition at line 588 of file mptrac.h.

◆ NTHREADS

#define NTHREADS   512

Maximum number of OpenMP threads.

Definition at line 593 of file mptrac.h.

◆ CY

#define CY   250

Maximum number of latitudes for climatological data.

Definition at line 598 of file mptrac.h.

◆ CO3

#define CO3   30

Maximum number of total column ozone data for climatological data.

Definition at line 603 of file mptrac.h.

◆ CP

#define CP   70

Maximum number of pressure levels for climatological data.

Definition at line 608 of file mptrac.h.

◆ CSZA

#define CSZA   50

Maximum number of solar zenith angles for climatological data.

Definition at line 613 of file mptrac.h.

◆ CT

#define CT   12

Maximum number of time steps for climatological data.

Definition at line 618 of file mptrac.h.

◆ CTS

#define CTS   1000

Maximum number of data points of climatological time series.

Definition at line 623 of file mptrac.h.

◆ DD_EX_GLOB

#define DD_EX_GLOB   (EX * 16)

Maximum number of longitudes of global meteo data.

Definition at line 628 of file mptrac.h.

◆ DD_EY_GLOB

#define DD_EY_GLOB   (EY * 16)

Maximum number of latitudes of global meteo data.

Definition at line 633 of file mptrac.h.

◆ ALLOC

#define ALLOC (   ptr,
  type,
 
)
Value:
if((ptr=calloc((size_t)(n), sizeof(type)))==NULL) \
ERRMSG("Out of memory!");

Allocate memory for a pointer with error handling.

This macro allocates memory for a pointer of a given type and size using the calloc function. It includes error handling to check if memory allocation was successful. If the code is being compiled with OpenACC support (_OPENACC macro defined), it additionally checks if the code is running on a GPU device, and if not, it raises an error.

Parameters
ptrPointer variable to be allocated.
typeData type of the pointer.
nNumber of elements to allocate memory for.
Note
If the code is compiled without OpenACC support, the conditional check for GPU device is skipped.
Author
Lars Hoffmann

Definition at line 666 of file mptrac.h.

◆ ARRAY_2D

#define ARRAY_2D (   ix,
  iy,
  ny 
)     ((ix) * (ny) + (iy))

Macro for computing the linear index of a 2D array element.

The ARRAY_2D macro computes the linear index of a 2D array element based on the specified row index (ix), column index (iy), and number of columns (ny).

Parameters
ixInteger representing the row index of the 2D array element.
iyInteger representing the column index of the 2D array element.
nyInteger representing the number of columns in the 2D array.
Returns
The computed linear index of the 2D array element.

The macro computes the linear index using the formula: (ix) * (ny) + (iy). This formula assumes row-major storage, where elements of each row are stored sequentially in memory.

Author
Lars Hoffmann

Definition at line 689 of file mptrac.h.

◆ ARRAY_3D

#define ARRAY_3D (   ix,
  iy,
  ny,
  iz,
  nz 
)     (((ix)*(ny) + (iy)) * (nz) + (iz))

Compute the linear index of a 3D array element.

This macro computes the linear index of a 3D array element based on the specified row index (ix), column index (iy), depth index (iz), number of columns (ny), and number of depths (nz).

Parameters
ixRow index of the 3D array element.
iyColumn index of the 3D array element.
nyNumber of columns in the 3D array.
izDepth index of the 3D array element.
nzNumber of depths in the 3D array.
Returns
Linear index of the 3D array element.
Author
Lars Hoffmann

Definition at line 708 of file mptrac.h.

◆ ARRHENIUS

#define ARRHENIUS (   a,
  b,
 
)     ((a) * exp( -(b) / (t)))

Calculate the Arrhenius rate constant.

The Arrhenius equation is commonly used in chemical kinetics to describe the temperature dependence of reaction rates. This macro calculates the rate constant (k) based on the Arrhenius equation:

\[ k = a \times \exp( -b / T ), \]

where:

  • k is the rate constant.
  • a is the pre-exponential factor or frequency factor.
  • b is the activation energy.
  • T is the temperature in Kelvin.
Parameters
aPre-exponential factor or frequency factor.
bActivation energy.
tTemperature in Kelvin.
Returns
Calculated rate constant based on the Arrhenius equation.
Author
Mingzhao Liu

Definition at line 733 of file mptrac.h.

◆ CLAMP

#define CLAMP (   v,
  lo,
  hi 
)     (((v) < (lo)) ? (lo) : (((v) > (hi)) ? (hi) : (v)))

Clamp a value to a specified range.

Ensures that v lies between lo and hi. If v < lo, returns lo. If v > hi, returns hi. Otherwise, returns v unchanged.

This macro works with any numeric type (e.g., int, float, double). All arguments are evaluated exactly once — avoid passing expressions with side effects (e.g., ++ operators or function calls).

Parameters
vInput value to clamp.
loLower bound.
hiUpper bound.
Returns
The clamped value between lo and hi.
Author
Lars Hoffmann

Definition at line 755 of file mptrac.h.

◆ COMPRESS_SPEED

#define COMPRESS_SPEED (   nbytes,
  dt 
)     ((dt) > 0 ? ((double)(nbytes)) / ((dt) * 1024. * 1024.) : NAN)

Calculate compression throughput in MiB/s.

This helper converts a processed byte count and elapsed wall-clock time into a throughput value expressed in MiB/s.

Parameters
nbytesNumber of processed bytes.
dtElapsed time in seconds.
Returns
Throughput in MiB/s, or NAN if dt is not positive.
Author
Lars Hoffmann

Definition at line 770 of file mptrac.h.

◆ COMPRESS_RATIO

#define COMPRESS_RATIO (   raw_size,
  stored_size 
)     ((double) (raw_size) / (double) (stored_size))

Calculate the compression ratio from raw and stored byte counts.

Parameters
raw_sizeUncompressed payload size in bytes.
stored_sizeCompressed/stored payload size in bytes.
Returns
Compression ratio.
Author
Lars Hoffmann

Definition at line 782 of file mptrac.h.

◆ COMPRESS_BPV

#define COMPRESS_BPV (   n,
  stored_size 
)     ((8.0 * (double) (stored_size)) / (double) (n))

Calculate bits per value from stored size and element count.

Parameters
nNumber of stored values.
stored_sizeCompressed/stored payload size in bytes.
Returns
Bits per stored value.
Author
Lars Hoffmann

Definition at line 794 of file mptrac.h.

◆ DEG2DX

#define DEG2DX (   dlon,
  lat 
)     (RE * DEG2RAD(dlon) * cos(DEG2RAD(lat)))

Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.

This macro calculates the distance in the x-direction (east-west) corresponding to a given longitude difference at a specific latitude using the formula:

\[ dx = dlon \times \pi \times RE / 180 times \cos(lat), \]

where:

  • dx is the distance in the x-direction (east-west).
  • dlon is the difference in longitudes in degrees.
  • RE is the Earth's radius.
  • lat is the latitude in degrees.
Parameters
dlonDifference in longitudes in degrees.
latLatitude in degrees.
Returns
Distance in the x-direction (east-west) corresponding to the given longitude difference at the specified latitude.
Author
Lars Hoffmann

Definition at line 818 of file mptrac.h.

◆ DEG2DY

#define DEG2DY (   dlat)     (RE * DEG2RAD(dlat))

Convert a latitude difference to a distance in the y-direction (north-south).

This macro calculates the distance in the y-direction (north-south) corresponding to a given latitude difference using the formula:

\[ dy = dlat \times \pi \times RE / 180, \]

where:

  • dy is the distance in the y-direction (north-south).
  • dlat is the difference in latitudes in degrees.
  • RE is the Earth's radius.
Parameters
dlatDifference in latitudes in degrees.
Returns
Distance in the y-direction (north-south) corresponding to the given latitude difference.
Author
Lars Hoffmann

Definition at line 839 of file mptrac.h.

◆ DEG2RAD

#define DEG2RAD (   deg)     ((deg) * (M_PI / 180.0))

Converts degrees to radians.

This macro converts an angle from degrees to radians using the formula: radians = degrees * (Ï€ / 180)

Parameters
degThe angle in degrees to be converted.
Returns
The angle in radians.
Note
This macro uses the M_PI constant from <math.h> for the value of π.
Author
Lars Hoffmann

Definition at line 856 of file mptrac.h.

◆ DP2DZ

#define DP2DZ (   dp,
 
)     (- (dp) * H0 / (p))

Convert a pressure difference to a height difference in the vertical direction.

This macro calculates the change in height (altitude) corresponding to a given pressure difference using the formula:

\[ dz = - (dp) \times H_0 / p \]

where:

  • dz is the change in height (altitude) in meters.
  • dp is the pressure difference in hPa.
  • H0 is a reference scale height in km.
  • p is the reference pressure in hPa.
Parameters
dpPressure difference in hPa.
pReference pressure in hPa.
Returns
Change in height (altitude) in kilometers corresponding to the given pressure difference.
Warning
Don't use this for large values of dp!
Author
Lars Hoffmann

Definition at line 881 of file mptrac.h.

◆ DX2DEG

#define DX2DEG (   dx,
  lat 
)
Value:
(((lat) < -89.999 || (lat) > 89.999) ? 0 \
: (dx) * 180. / (M_PI * RE * cos(DEG2RAD(lat))))
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:314
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:856

Convert a distance in kilometers to degrees longitude at a given latitude.

This macro calculates the change in longitude in degrees corresponding to a given distance in kilometers at a specified latitude on the Earth's surface. It uses the formula:

\[ dlon = \frac{dx \times 180}{\pi \times RE \times \cos(lat)} \]

Parameters
dxDistance in kilometers.
latLatitude in degrees.
Returns
Change in longitude in degrees.
Note
The latitude must be in the range [-89.999, 89.999] degrees. Otherwise, the macro return value will be zero. This avoids issues with the singularities at the poles.
Author
Lars Hoffmann

Definition at line 903 of file mptrac.h.

◆ DY2DEG

#define DY2DEG (   dy)     ((dy) * 180. / (M_PI * RE))

Convert a distance in kilometers to degrees latitude.

This macro calculates the change in latitude in degrees corresponding to a given distance in kilometers on the Earth's surface. It uses the formula:

\[ dlat = \frac{dy \times 180}{\pi \times RE} \]

Parameters
dyDistance in kilometers.
Returns
Change in latitude in degrees.
Author
Lars Hoffmann

Definition at line 921 of file mptrac.h.

◆ DZ2DP

#define DZ2DP (   dz,
 
)     (-(dz) * (p) / H0)

Convert a change in altitude to a change in pressure.

This macro calculates the change in pressure corresponding to a given change in altitude. It uses the hydrostatic equation:

\[ dp = -\left(dz \times \frac{p}{H_0}\right) \]

Parameters
dzChange in altitude in kilometers.
pCurrent pressure in hPa.
Returns
Change in pressure in hPa.
Warning
Don't use this for large values of dz!
Author
Lars Hoffmann

Definition at line 940 of file mptrac.h.

◆ DX2COORD

#define DX2COORD (   met,
  dx,
  lat 
)    (((met)->coord_type == 0)? DX2DEG((dx) / 1000.0, (lat)) : ((dx) ))

Convert a distance in meters to a coordinate value based on grid type.

This macro converts a distance in meters to either degrees longitude (for latitude/longitude grids) or keeps it as metres (for UTM grids), depending on the coordinate system type specified in the met_t structure.

For coord_type = 0 (latitude/longitude grid):

  • Converts meters to kilometers
  • Call DX2DEG() to convert to degrees

For coord_type = 1 (UTM grid):

  • Keeps input distance unchanged (in meters)
Parameters
metPointer to met_t structure containing coordinate system information.
dxDistance in meters to be converted.
latLatitude in degrees (used for degree conversion in lat/lon grids).
Returns
Coordinate value in either degrees longitude (for coord_type=0) or meters (for coord_type=1).
Author
Robin Brase

Definition at line 965 of file mptrac.h.

◆ DY2COORD

#define DY2COORD (   met,
  dy 
)    (((met)->coord_type == 0)? DY2DEG((dy) / 1000.0) : ((dy) ))

Convert a distance to coordinate value based on grid type.

This macro converts a distance in meters to either degrees latitude (for latitude/longitude grids) or keeps it as metres (for UTM grids), depending on the coordinate system type specified in the met_t structure.

For coord_type = 0 (latitude/longitude grid):

  • Converts meters to kilometers
  • Call DY2DEG() to convert to degrees

For coord_type = 1 (UTM grid):

  • Keeps input distance unchanged (in meters)
Parameters
metPointer to met_t structure containing coordinate system information.
dyDistance in meters to be converted.
Returns
Coordinate value in either degrees latitude (for coord_type=0) or meters (for coord_type=1).
Author
Robin Brase

Definition at line 988 of file mptrac.h.

◆ DIST

#define DIST (   a,
 
)     sqrt(DIST2(a, b))

Calculate the distance between two points in Cartesian coordinates.

This macro calculates the Euclidean distance between two points in Cartesian coordinates. It uses the square root of the square of the distance obtained from the DIST2 macro.

Parameters
aCoordinates of the first point as an array of doubles.
bCoordinates of the second point as an array of doubles.
Returns
The distance between the two points.
Author
Lars Hoffmann

Definition at line 1003 of file mptrac.h.

◆ DIST2

#define DIST2 (   a,
 
)     ((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])+(a[2]-b[2])*(a[2]-b[2]))

Calculate the squared Euclidean distance between two points in Cartesian coordinates.

This macro calculates the squared Euclidean distance between two points in Cartesian coordinates. It computes the sum of the squares of the differences of corresponding coordinates.

Parameters
aCoordinates of the first point as an array of doubles.
bCoordinates of the second point as an array of doubles.
Returns
The squared distance between the two points.
Author
Lars Hoffmann

Definition at line 1019 of file mptrac.h.

◆ DOTP

#define DOTP (   a,
 
)     (a[0]*b[0]+a[1]*b[1]+a[2]*b[2])

Calculate the dot product of two vectors.

This macro computes the dot product of two vectors represented as arrays of doubles. It multiplies corresponding components of the vectors and sums the results.

Parameters
aThe first vector as an array of doubles.
bThe second vector as an array of doubles.
Returns
The dot product of the two vectors.
Author
Lars Hoffmann

Definition at line 1035 of file mptrac.h.

◆ ECC

#define ECC (   cmd)
Value:
{ \
int ecc_result=(cmd); \
if(ecc_result!=0) \
ERRMSG("ECCODES error: %s", codes_get_error_message(ecc_result)); \
}

Execute an ECCODES command and check for errors.

This macro executes an ECCODES command and checks the result. If the result indicates an error, it prints the error message using ERRMSG.

Parameters
cmdECCODES command to execute.
Author
Nils Nobre Wittwer

Definition at line 1049 of file mptrac.h.

◆ ECC_READ_2D

#define ECC_READ_2D (   variable,
  target,
  scaling_factor,
  found_flag 
)
Value:
{ \
if(strcmp(short_name, variable) == 0) { \
if ((found_flag) == 0) \
LOG(2, "Read 2-D variable: %s (GRIB)", variable); \
for (int ix = 0; ix < met->nx; ix++) \
for (int iy = 0; iy < met->ny; iy++) \
target[ix][iy] = (float)(values[iy * met->nx + ix] * scaling_factor); \
found_flag = 1; \
} \
}

Writes 2-D data from a grib message into the meteo struct.

This macro writes 2-D data from a one-dimensional grib message into the corresponding 2-D variable in the meteo struct.

Parameters
variableName of the current meteorological variable
targetPointer to the 2-D array in the meteo struct where the data will be stored.
scaling_factorScaling factor to apply to the data.
found_flagFlag to store, that the variable was found in the grib message.
Author
Nils Nobre Wittwer

Definition at line 1068 of file mptrac.h.

◆ ECC_READ_3D

#define ECC_READ_3D (   variable,
  level,
  target,
  scaling_factor,
  found_flag 
)
Value:
{ \
if(strcmp(short_name, variable) == 0) { \
if ((found_flag) == 0) \
LOG(2, "Read 3-D variable: %s (GRIB)", variable); \
for (int ix = 0; ix < met->nx; ix++) \
for (int iy = 0; iy < met->ny; iy++) \
target[ix][iy][level] = (float) (values[iy * met->nx + ix] * scaling_factor); \
found_flag += 1; \
} \
}

Writes 3D data from a grib message into the meteo struct.

This macro writes 3D data from a one-dimensional grib message into the corresponding 3D variable in the meteo struct.

Parameters
variableName of the current meteorological variable.
levelIndex of the vertical level in the 3D array where the data should be stored.
targetPointer to the 3D array in the meteo struct where the data will be stored.
scaling_factorScaling factor to apply to the data.
found_flagCounter to store, how many messages containing data for this variable have been read.
Author
Nils Nobre Wittwer

Definition at line 1093 of file mptrac.h.

◆ FMOD

#define FMOD (   x,
 
)     ((x) - (int) ((x) / (y)) * (y))

Calculate the floating-point remainder of dividing x by y.

This macro computes the floating-point remainder of dividing x by y. It calculates this remainder as x minus the integer part of (x / y) times y.

Parameters
xThe dividend.
yThe divisor.
Returns
The floating-point remainder of x divided by y.
Note
Macro has been added as a substitute when a GPU version of fmod() is missing.
Author
Lars Hoffmann

Definition at line 1120 of file mptrac.h.

◆ FREAD

#define FREAD (   ptr,
  type,
  size,
  in 
)
Value:
{ \
if(fread(ptr, sizeof(type), size, in)!=size) \
ERRMSG("Error while reading!"); \
}

Read data from a file stream and store it in memory.

This macro reads data of a specified type from the given input file stream and stores it in the specified memory location. It ensures that the correct amount of data is read from the file stream, and if not, it raises an error.

Parameters
ptrPointer to the memory location where the data will be stored.
typeType of the data elements to be read.
sizeNumber of elements to read.
inFile stream from which to read the data.
Author
Lars Hoffmann

Definition at line 1138 of file mptrac.h.

◆ FWRITE

#define FWRITE (   ptr,
  type,
  size,
  out 
)
Value:
{ \
if(fwrite(ptr, sizeof(type), size, out)!=size) \
ERRMSG("Error while writing!"); \
}

Write data from memory to a file stream.

This macro writes data of a specified type from the specified memory location to the given output file stream. It ensures that the correct amount of data is written to the file stream, and if not, it raises an error.

Parameters
ptrPointer to the memory location containing the data to be written.
typeType of the data elements to be written.
sizeNumber of elements to write.
outFile stream to which the data will be written.
Author
Lars Hoffmann

Definition at line 1158 of file mptrac.h.

◆ INTPOL_INIT

#define INTPOL_INIT    double cw[4] = {0.0, 0.0, 0.0, 0.0}; int ci[3] = {0, 0, 0};

Initialize arrays for interpolation.

This macro initializes arrays used for interpolation. It sets the weights cw and indices ci to zero. These arrays are used during interpolation to store the interpolation weights and indices.

Author
Lars Hoffmann

Definition at line 1173 of file mptrac.h.

◆ INTPOL_2D

#define INTPOL_2D (   var,
  init 
)
Value:
intpol_met_time_2d(met0, met0->var, met1, met1->var, \
atm->time[ip], atm->lon[ip], atm->lat[ip], \
&var, ci, cw, init);
void intpol_met_time_2d(const met_t *met0, float array0[EX][EY], const met_t *met1, float array1[EX][EY], const double ts, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological data in 2D space and time.
Definition: mptrac.c:3141

Perform 2D interpolation for a meteorological variable.

This macro performs 2D interpolation for a given meteorological variable at a specific time and location.

Parameters
varThe variable to interpolate.
initA flag indicating whether to initialize the interpolation arrays (cw and ci). Set to 1 for initialization, 0 otherwise.
Returns
The interpolated value of the variable var.
Author
Lars Hoffmann

Definition at line 1187 of file mptrac.h.

◆ INTPOL_3D

#define INTPOL_3D (   var,
  init 
)
Value:
intpol_met_time_3d(met0, met0->var, met1, met1->var, \
atm->time[ip], atm->p[ip], \
atm->lon[ip], atm->lat[ip], \
&var, ci, cw, init);
void intpol_met_time_3d(const met_t *met0, float array0[EX][EY][EP], const met_t *met1, float array1[EX][EY][EP], const double ts, const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological data in 3D space and time.
Definition: mptrac.c:3112

Perform 3D interpolation for a meteorological variable.

This macro performs 3D interpolation for a given meteorological variable at a specific time, pressure level, and location.

Parameters
varThe variable to interpolate.
initA flag indicating whether to initialize the interpolation arrays (cw and ci). Set to 1 for initialization, 0 otherwise.
Returns
The interpolated value of the variable var.
Author
Lars Hoffmann

Definition at line 1204 of file mptrac.h.

◆ INTPOL_SPACE_ALL

#define INTPOL_SPACE_ALL (   p,
  lon,
  lat 
)

Interpolate multiple meteorological variables in space.

This macro performs spatial interpolation for multiple meteorological variables at a given pressure level, longitude, and latitude.

Parameters
pThe pressure level at which to interpolate the variables.
lonThe longitude at which to interpolate the variables.
latThe latitude at which to interpolate the variables.
Author
Lars Hofmann

Definition at line 1223 of file mptrac.h.

◆ INTPOL_TIME_ALL

#define INTPOL_TIME_ALL (   time,
  p,
  lon,
  lat 
)

Interpolate multiple meteorological variables in time.

This macro performs temporal interpolation for multiple meteorological variables at a given time, pressure level, longitude, and latitude.

Parameters
timeThe time at which to interpolate the variables.
pThe pressure level at which to interpolate the variables.
lonThe longitude at which to interpolate the variables.
latThe latitude at which to interpolate the variables.
Author
Lars Hoffmann

Definition at line 1277 of file mptrac.h.

◆ LAPSE

#define LAPSE (   p1,
  t1,
  p2,
  t2 
)
Value:
(1e3 * G0 / RA * ((t2) - (t1)) / ((t2) + (t1)) \
* ((p2) + (p1)) / ((p2) - (p1)))
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:309
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:264

Calculate lapse rate.

This macro calculates the lapse rate between two pressure levels given their temperatures and pressures.

Parameters
p1Pressure at the first level (in hPa).
t1Temperature at the first level (in K).
p2Pressure at the second level (in hPa).
t2Temperature at the second level (in K).
Returns
The lapse rate (in K/km).
Author
Lars Hoffmann

Definition at line 1331 of file mptrac.h.

◆ LIN

#define LIN (   x0,
  y0,
  x1,
  y1,
 
)     ((y0)+((y1)-(y0))/((x1)-(x0))*((x)-(x0)))

Linear interpolation.

This macro performs linear interpolation to estimate the value of y at a given x based on two points (x0, y0) and (x1, y1).

Parameters
x0X-coordinate of the first point.
y0Y-coordinate of the first point.
x1X-coordinate of the second point.
y1Y-coordinate of the second point.
xThe x-coordinate at which to estimate the y-value.
Returns
The estimated y-value at the given x-coordinate.
Author
Lars Hoffmann

Definition at line 1350 of file mptrac.h.

◆ MAX

#define MAX (   a,
 
)     (((a)>(b))?(a):(b))

Macro to determine the maximum of two values.

This macro evaluates to the larger of its two arguments, a and b. It uses a ternary conditional operator to compare the values of a and b and returns a if a is greater than b; otherwise, it returns b.

Parameters
aThe first value to compare. Can be of any type that supports comparison.
bThe second value to compare. Can be of any type that supports comparison.
Returns
The larger of the two values, a or b.
Note
Both a and b are evaluated twice. If a or b have side effects (e.g., increment operators, function calls), the side effects will occur more than once. This can lead to unexpected behavior.
Warning
The macro does not perform type checking, so a and b should be of compatible types to avoid potential issues with comparison and return value.
Author
Lars Hoffmann

Definition at line 1377 of file mptrac.h.

◆ MET_HEADER

#define MET_HEADER

Write header for meteorological data file.

This macro writes a header to a meteorological data file, providing information about the variables stored in the file and their corresponding columns.

Parameters
outPointer to the file stream where the header will be written.
Author
Lars Hoffmann

Definition at line 1391 of file mptrac.h.

◆ MIN

#define MIN (   a,
 
)     (((a)<(b))?(a):(b))

Macro to determine the minimum of two values.

This macro evaluates to the smaller of its two arguments, a and b. It uses a ternary conditional operator to compare the values of a and b and returns a if a is less than b; otherwise, it returns b.

Parameters
aThe first value to compare. Can be of any type that supports comparison.
bThe second value to compare. Can be of any type that supports comparison.
Returns
The smaller of the two values, a or b.
Note
Both a and b are evaluated twice. If a or b have side effects (e.g., increment operators, function calls), the side effects will occur more than once. This can lead to unexpected behavior.
Warning
The macro does not perform type checking, so a and b should be of compatible types to avoid potential issues with comparison and return value.
Author
Lars Hoffmann

Definition at line 1478 of file mptrac.h.

◆ MOLEC_DENS

#define MOLEC_DENS (   p,
 
)     (AVO * 1e-6 * ((p) * 100) / (RI * (t)))

Calculate the density of a gas molecule.

This macro calculates the density of a gas molecule using the provided pressure and temperature values.

Parameters
pPressure of the gas in Pascals.
tTemperature of the gas in Kelvin.
Returns
Density of the gas molecule in kg/m^3.
Author
Lars Hoffmann

Definition at line 1493 of file mptrac.h.

◆ NC

#define NC (   cmd)
Value:
{ \
int nc_result=(cmd); \
if(nc_result!=NC_NOERR) \
ERRMSG("%s", nc_strerror(nc_result)); \
}

Execute a NetCDF command and check for errors.

This macro executes a NetCDF command and checks the result. If the result indicates an error, it prints the error message using ERRMSG.

Parameters
cmdNetCDF command to execute.
Author
Lars Hoffmann

Definition at line 1507 of file mptrac.h.

◆ NC_DEF_VAR

#define NC_DEF_VAR (   varname,
  type,
  ndims,
  dims,
  long_name,
  units,
  level,
  quant 
)
Value:
{ \
NC(nc_def_var(ncid, varname, type, ndims, dims, &varid)); \
NC(nc_put_att_text(ncid, varid, "long_name", strnlen(long_name, LEN), long_name)); \
NC(nc_put_att_text(ncid, varid, "units", strnlen(units, LEN), units)); \
NC_DEF_VAR_QUANTIZE(quant); \
if((level) != 0) { \
NC(nc_def_var_deflate(ncid, varid, 1, 1, level)); \
/* unsigned int ulevel = (unsigned int)level; */ \
/* NC(nc_def_var_filter(ncid, varid, 32015, 1, (unsigned int[]){ulevel})); */ \
} \
}
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:558

Define a NetCDF variable with attributes.

This macro defines a NetCDF variable with the specified name, data type, dimensions, long name, and units. It also sets the long_name and units attributes for the variable. It enables compression and quantizatio of the data.

Parameters
varnameName of the variable.
typeData type of the variable.
ndimsNumber of dimensions for the variable.
dimsArray of dimension IDs.
long_nameLong name of the variable.
unitsUnits of the variable.
levelzlib compression level (0 = off).
quantNumber of digits for quantization (0 = off).
Note
To enable ZSTD compression, replace nc_def_var_deflate() by nc_def_var_filter() below. Use dynamic linking, static linking does not work. Set environment variable HDF5_PLUGIN_PATH to ./libs/build/share/netcdf-plugins/.
Author
Lars Hoffmann

Definition at line 1536 of file mptrac.h.

◆ NC_DEF_VAR_QUANTIZE

#define NC_DEF_VAR_QUANTIZE (   quant)
Value:
do { \
if((quant) > 0) \
ERRMSG("NetCDF quantization is not supported by this NetCDF version"); \
} while(0)

Definition at line 1554 of file mptrac.h.

◆ NC_GET_DOUBLE

#define NC_GET_DOUBLE (   varname,
  ptr,
  force 
)
Value:
{ \
if(force) { \
NC(nc_inq_varid(ncid, varname, &varid)); \
NC(nc_get_var_double(ncid, varid, ptr)); \
} else { \
if(nc_inq_varid(ncid, varname, &varid) == NC_NOERR) { \
NC(nc_get_var_double(ncid, varid, ptr)); \
WARN("netCDF variable %s is missing!", varname); \
} \
}
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:2383

Retrieve a double-precision variable from a NetCDF file.

This macro retrieves a double-precision variable from a NetCDF file. It first checks if the variable exists in the file and then reads its data into the specified pointer. If the force parameter is set to true, it forces the retrieval of the variable, raising an error if the variable does not exist. If force is false, it retrieves the variable if it exists and issues a warning if it does not.

Parameters
varnameName of the variable to retrieve.
ptrPointer to the memory location where the data will be stored.
forceBoolean flag indicating whether to force retrieval (true) or not (false).
Author
Lars Hoffmann

Definition at line 1577 of file mptrac.h.

◆ NC_INQ_DIM

#define NC_INQ_DIM (   dimname,
  ptr,
  min,
  max,
  check 
)
Value:
{ \
int dimid; size_t naux; \
NC(nc_inq_dimid(ncid, dimname, &dimid)); \
NC(nc_inq_dimlen(ncid, dimid, &naux)); \
*ptr = (int)naux; \
if (check) \
if ((*ptr) < (min) || (*ptr) > (max)) \
ERRMSG("Dimension %s is out of range!", dimname); \
}

Inquire the length of a dimension in a NetCDF file.

This macro retrieves the length of a specified dimension from a NetCDF file. It checks if the length of the dimension is within a specified range and assigns the length to the provided pointer. If the length is outside the specified range, an error message is raised.

Parameters
dimnameName of the dimension to inquire.
ptrPointer to an integer where the dimension length will be stored.
minMinimum acceptable length for the dimension.
maxMaximum acceptable length for the dimension.
checkFlag to check bounds. Set to 1 for bounds check.
Author
Lars Hoffmann
Jan Clemens

Definition at line 1607 of file mptrac.h.

◆ NC_PUT_DOUBLE

#define NC_PUT_DOUBLE (   varname,
  ptr,
  hyperslab 
)
Value:
{ \
NC(nc_inq_varid(ncid, varname, &varid)); \
if(hyperslab) { \
NC(nc_put_vara_double(ncid, varid, start, count, ptr)); \
} else { \
NC(nc_put_var_double(ncid, varid, ptr)); \
} \
}

Write double precision data to a NetCDF variable.

This macro writes data to a specified NetCDF variable. It can handle both full variable writes and hyperslab writes depending on the hyperslab parameter. If hyperslab is true, the data is written as a hyperslab; otherwise, the entire variable is written.

Parameters
varnameName of the NetCDF variable to write to.
ptrPointer to the data to be written.
hyperslabBoolean indicating whether to write the data as a hyperslab.
Author
Lars Hoffmann

Definition at line 1631 of file mptrac.h.

◆ NC_PUT_FLOAT

#define NC_PUT_FLOAT (   varname,
  ptr,
  hyperslab 
)
Value:
{ \
NC(nc_inq_varid(ncid, varname, &varid)); \
if(hyperslab) { \
NC(nc_put_vara_float(ncid, varid, start, count, ptr)); \
} else { \
NC(nc_put_var_float(ncid, varid, ptr)); \
} \
}

Write a float array to a NetCDF file.

This macro writes a float array to a specified variable in a NetCDF file. Depending on the value of the hyperslab parameter, the data can be written as a hyperslab or as a whole variable.

Parameters
varnameName of the variable to which the float array will be written.
ptrPointer to the float array to be written.
hyperslabBoolean flag indicating if the data should be written as a hyperslab.
  • If true, the data will be written as a hyperslab using the start and count arrays.
  • If false, the data will be written to the entire variable.
Author
Lars Hoffmann

Definition at line 1655 of file mptrac.h.

◆ NC_PUT_INT

#define NC_PUT_INT (   varname,
  ptr,
  hyperslab 
)
Value:
{ \
NC(nc_inq_varid(ncid, varname, &varid)); \
if(hyperslab) { \
NC(nc_put_vara_int(ncid, varid, start, count, ptr)); \
} else { \
NC(nc_put_var_int(ncid, varid, ptr)); \
} \
}

Write integer data to a NetCDF variable.

This macro writes data to a specified NetCDF variable. It can handle both full variable writes and hyperslab writes depending on the hyperslab parameter. If hyperslab is true, the data is written as a hyperslab; otherwise, the entire variable is written.

Parameters
varnameName of the NetCDF variable to write to.
ptrPointer to the data to be written.
hyperslabBoolean indicating whether to write the data as a hyperslab.
Author
Lars Hoffmann

Definition at line 1678 of file mptrac.h.

◆ NC_PUT_ATT

#define NC_PUT_ATT (   varname,
  attname,
  text 
)
Value:
{ \
NC(nc_inq_varid(ncid, varname, &varid)); \
NC(nc_put_att_text(ncid, varid, attname, strnlen(text, LEN), text)); \
}

Add a text attribute to a NetCDF variable.

This macro adds a text attribute to a specified NetCDF variable. It first retrieves the variable ID using its name, then it attaches the text attribute to the variable.

Parameters
varnameName of the NetCDF variable to which the attribute will be added.
attnameName of the attribute to be added.
textText of the attribute to be added.
Author
Lars Hoffmann

Definition at line 1700 of file mptrac.h.

◆ NC_PUT_ATT_GLOBAL

#define NC_PUT_ATT_GLOBAL (   attname,
  text 
)     NC(nc_put_att_text(ncid, NC_GLOBAL, attname, strnlen(text, LEN), text));

Add a global text attribute to a NetCDF file.

This macro adds a text attribute to the global attributes of a NetCDF file. It directly attaches the attribute to the file, rather than to a specific variable.

Parameters
attnameName of the global attribute to be added.
textText of the attribute to be added.
Author
Lars Hoffmann

Definition at line 1717 of file mptrac.h.

◆ NN

#define NN (   x0,
  y0,
  x1,
  y1,
 
)     (fabs((x) - (x0)) <= fabs((x) - (x1)) ? (y0) : (y1))

Perform nearest-neighbor interpolation.

This macro returns the value of the nearest neighbor (y0 or y1) for a given x value. It compares the distances between x and x0, and between x and x1, and returns the y value corresponding to the closer x value.

Parameters
x0The x-coordinate of the first point.
y0The y-coordinate of the first point.
x1The x-coordinate of the second point.
y1The y-coordinate of the second point.
xThe x-coordinate for which the nearest neighbor is to be found.
Returns
The y-coordinate of the nearest neighbor (either y0 or y1).
Author
Lars Hoffmann

Definition at line 1737 of file mptrac.h.

◆ PARTICLE_LOOP

#define PARTICLE_LOOP (   ip0,
  ip1,
  check_dt,
  ... 
)
Value:
const int ip0_const = ip0; \
const int ip1_const = ip1; \
_Pragma("omp parallel for default(shared)") \
for (int ip = ip0_const; ip < ip1_const; ip++) \
if (!check_dt || cache->dt[ip] != 0)

Loop over particle indices with OpenACC acceleration.

This macro defines a loop over particle indices from ip0 to ip1 with optional checking of dt. If _OPENACC is defined, the loop is accelerated using OpenACC directives. Otherwise, OpenMP parallelization is used.

Parameters
ip0The starting index of the loop (inclusive).
ip1The ending index of the loop (exclusive).
check_dtFlag indicating whether to check the array dt for non-zero values.
...Optional pragma directives to be applied.
Author
Lars Hoffmann

Definition at line 1764 of file mptrac.h.

◆ P

#define P (   z)     (P0 * exp(-(z) / H0))

Compute pressure at given altitude.

This macro calculates the pressure at a given altitude using the barometric formula.

Parameters
zThe altitude in kilometers.
Returns
The pressure in hPa at the given altitude.

The barometric formula used for this calculation is:

\[ P(z) = P_0 \times e^{-(z / H_0)}, \]

where:

  • \( P(z) \) is the pressure at altitude \( z \),
  • \( P_0 \) is the standard pressure,
  • \( H_0 \) is the scale height.
Note
The constants \( P_0 \) and \( H_0 \) must be defined before using this macro.
Author
Lars Hoffmann

Definition at line 1794 of file mptrac.h.

◆ PSAT

#define PSAT (   t)     (6.112 * exp(17.62 * ((t) - T0) / (243.12 + (t) - T0)))

Compute saturation pressure over water.

This macro calculates the saturation pressure over water based on the WMO (2018) formula.

Parameters
tThe temperature in degrees Celsius.
Returns
The saturation pressure over water at the given temperature.

The saturation pressure over water is calculated using the formula:

\[ P_{\textrm{sat}}(t) = 6.112 \times e^{17.62 \times \frac{(t - T_0)}{243.12 + (t - T_0)}}, \]

where:

  • \( P_{\textrm{sat}}(t) \) is the saturation pressure over water at temperature \( t \),
  • \( T_0 \) is the reference temperature (0°C).
Note
The constants \( T_0 \) must be defined before using this macro.
Author
Lars Hoffmann

Definition at line 1818 of file mptrac.h.

◆ PSICE

#define PSICE (   t)     (6.112 * exp(22.46 * ((t) - T0) / (272.62 + (t) - T0)))

Compute saturation pressure over ice (WMO, 2018).

This macro calculates the saturation pressure over ice based on the WMO (2018) formula.

Parameters
tThe temperature in K.
Returns
The saturation pressure over ice at the given temperature.

The saturation pressure over ice is calculated using the formula:

\[ P_{\textrm{ice}}(t) = 6.112 \times e^{22.46 \times \frac{(t - T_0)}{272.62 + (t - T_0)}}, \]

where:

  • \( P_{\textrm{ice}}(t) \) is the saturation pressure over ice at temperature \( t \),
  • \( T_0 \) is the reference temperature (0°C).
Note
The constant \( T_0 \) must be defined before using this macro.
Author
Lars Hoffmann

Definition at line 1842 of file mptrac.h.

◆ PW

#define PW (   p,
  h2o 
)     ((p) * MAX((h2o), 0.1e-6) / (1. + (1. - EPS) * MAX((h2o), 0.1e-6)))

Calculate partial water vapor pressure.

This macro calculates the partial water vapor pressure using the given total pressure and water vapor mixing ratio.

Parameters
pThe total pressure in hPa (hectopascals).
h2oThe water vapor mixing ratio in ppv (parts per volume).
Returns
The partial water vapor pressure.

The partial water vapor pressure is calculated using the formula:

\[ P_{\textrm{w}}(p, h_2o) = \frac{p \times \max(h_2o, 0.1 \times 10^{-6})}{1 + (1 - \epsilon) \times \max(h_2o, 0.1 \times 10^{-6})}, \]

where:

  • \( P_{\textrm{w}}(p, h_2o) \) is the partial water vapor pressure,
  • \( p \) is the total pressure in hPa,
  • \( h_2o \) is the water vapor mixing ratio in ppv,
  • \( \epsilon \) is the factor to account for saturation vapor pressure over water.
Note
The constant \( \epsilon \) must be defined before using this macro.
Author
Lars Hoffmann

Definition at line 1869 of file mptrac.h.

◆ RAD2DEG

#define RAD2DEG (   rad)     ((rad) * (180.0 / M_PI))

Converts radians to degrees.

This macro converts an angle from radians to degrees using the formula: degrees = radians * (180 / π)

Parameters
radThe angle in radians to be converted.
Returns
The angle in degrees.
Note
This macro uses the M_PI constant from <math.h> for the value of π.
Author
Lars Hoffmann

Definition at line 1886 of file mptrac.h.

◆ RH

#define RH (   p,
  t,
  h2o 
)     (PW(p, h2o) / PSAT(t) * 100.)

Compute relative humidity over water.

This macro calculates the relative humidity over water using the given total pressure, temperature, and water vapor mixing ratio.

Parameters
pThe total pressure in hPa.
tThe temperature in K.
h2oThe water vapor mixing ratio in ppv (parts per volume).
Returns
The relative humidity over water in percentage.

The relative humidity over water is calculated using the formula:

\[ RH_{\textrm{w}}(p, t, h_2o) = \frac{P_{\textrm{w}}(p, h_2o)}{P_{\textrm{sat}}(t)} \times 100, \]

where:

  • \( RH_{\textrm{w}}(p, t, h_2o) \) is the relative humidity over water,
  • \( P_{\textrm{w}}(p, h_2o) \) is the partial water vapor pressure,
  • \( P_{\textrm{sat}}(t) \) is the saturation pressure over water at the given temperature,
  • \( p \) is the total pressure in hPa,
  • \( t \) is the temperature in Kelvin,
  • \( h_2o \) is the water vapor mixing ratio in ppv.
Note
The macros PW() and PSAT() must be defined before using this macro.
Author
Lars Hoffmann

Definition at line 1916 of file mptrac.h.

◆ RHICE

#define RHICE (   p,
  t,
  h2o 
)     (PW(p, h2o) / PSICE(t) * 100.)

Compute relative humidity over ice.

This macro calculates the relative humidity over ice using the given total pressure, temperature, and water vapor mixing ratio.

Parameters
pThe total pressure in hPa.
tThe temperature in K.
h2oThe water vapor mixing ratio in ppv (parts per volume).
Returns
The relative humidity over ice in percentage.

The relative humidity over ice is calculated using the formula:

\[ RH_{\textrm{ice}}(p, t, h_2o) = \frac{P_{\textrm{w}}(p, h_2o)}{P_{\textrm{ice}}(t)} \times 100, \]

where:

  • \( RH_{\textrm{ice}}(p, t, h_2o) \) is the relative humidity over ice,
  • \( P_{\textrm{w}}(p, h_2o) \) is the partial water vapor pressure,
  • \( P_{\textrm{ice}}(t) \) is the saturation pressure over ice at the given temperature,
  • \( p \) is the total pressure in hPa,
  • \( t \) is the temperature in Kelvin,
  • \( h_2o \) is the water vapor mixing ratio in ppv.
Note
The macros PW() and PSICE() must be defined before using this macro.
Author
Lars Hoffmann

Definition at line 1946 of file mptrac.h.

◆ RHO

#define RHO (   p,
 
)     (100. * (p) / (RA * (t)))

Compute density of air.

This macro calculates the density of air using the given total pressure and temperature.

Parameters
pThe total pressure in hPa.
tThe temperature in K.
Returns
The density of air in kg/m^3.

The density of air is calculated using the formula:

\[ \rho(p, t) = \frac{100 \times p}{R_a \times t}, \]

where:

  • \( \rho(p, t) \) is the density of air,
  • \( p \) is the total pressure in hPa,
  • \( t \) is the temperature in Kelvin,
  • \( R_a \) is the specific gas constant for dry air (287.05 J/(kg·K)).
Author
Lars Hoffmann

Definition at line 1971 of file mptrac.h.

◆ SET_ATM

#define SET_ATM (   qnt,
  val 
)
Value:
if (ctl->qnt >= 0) \
atm->q[ctl->qnt][ip] = val;

Set atmospheric quantity value.

This macro sets the value of a specific atmospheric quantity at a given index 'ip'. The macro first checks if the control index 'ctl->qnt' is non-negative before assigning the value, ensuring that the quantity index is valid.

Parameters
qntThe index representing the atmospheric quantity to set.
valThe value to set for the atmospheric quantity.
Note
The macro assumes the existence of structures 'ctl' and 'atm' containing the control indices and atmospheric data, respectively, and an index 'ip' representing the data point.
Author
Lars Hoffmann

Definition at line 1990 of file mptrac.h.

◆ SET_QNT

#define SET_QNT (   qnt,
  name,
  longname,
  unit 
)
Value:
if (strcasecmp(ctl->qnt_name[iq], name) == 0) { \
ctl->qnt = iq; \
sprintf(ctl->qnt_longname[iq], longname); \
sprintf(ctl->qnt_unit[iq], unit); \
} else

Set atmospheric quantity index.

This macro sets the index, long name, and unit of a specific atmospheric quantity based on its name. It compares the name parameter with the name of the atmospheric quantity stored in 'ctl->qnt_name'. If a match is found, it assigns the index to 'ctl->qnt', updates the long name, and updates the unit.

Parameters
qntThe index representing the atmospheric quantity.
nameThe name of the atmospheric quantity.
longnameThe long name of the atmospheric quantity.
unitThe unit of the atmospheric quantity.
Note
The macro assumes the existence of structures 'ctl' containing control information. It also assumes the presence of 'iq', representing the index of the atmospheric quantity.
Author
Lars Hoffmann

Definition at line 2013 of file mptrac.h.

◆ SH

#define SH (   h2o)     (EPS * MAX((h2o), 0.1e-6))

Compute specific humidity from water vapor volume mixing ratio.

This macro calculates the specific humidity from the water vapor volume mixing ratio. Specific humidity represents the ratio of the mass of water vapor to the total mass of air and is dimensionless.

Parameters
h2oThe water vapor volume mixing ratio.
Returns
The specific humidity.
Note
The macro assumes that 'EPS' is defined and represents the ratio of the molecular weight of water vapor to the molecular weight of dry air.
Author
Lars Hoffmann

Definition at line 2034 of file mptrac.h.

◆ SQR

#define SQR (   x)     ((x)*(x))

Compute the square of a value.

This macro computes the square of the input value.

Parameters
xThe input value.
Returns
The square of the input value.
Author
Lars Hoffmann

Definition at line 2047 of file mptrac.h.

◆ SWAP

#define SWAP (   x,
  y,
  type 
)     do {type tmp = x; x = y; y = tmp;} while(0);

Swap two values.

This macro swaps the values of two variables of the specified type.

Parameters
xThe first variable to be swapped.
yThe second variable to be swapped.
typeThe type of the variables.
Author
Lars Hoffmann

Definition at line 2061 of file mptrac.h.

◆ TDEW

#define TDEW (   p,
  h2o 
)
Value:
(T0 + 243.12 * log(PW((p), (h2o)) / 6.112) \
/ (17.62 - log(PW((p), (h2o)) / 6.112)))
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1869
#define T0
Standard temperature [K].
Definition: mptrac.h:534

Calculate dew point temperature.

This macro computes the dew point temperature using the formula provided by the World Meteorological Organization (WMO, 2018).

Parameters
pThe atmospheric pressure in hPa.
h2oThe water vapor volume mixing ratio.
Returns
The dew point temperature in Kelvin.

Formula:

\[ T_{\textrm{dew}} = T_0 + \frac{243.12 \times \ln\left(\frac{{P_W(p, h_{2}O)}}{6.112}\right)}{17.62 - \ln\left(\frac{{P_W(p, h_{2}O)}}{6.112}\right)} \]

where:

  • \( T_{\textrm{dew}} \) is the dew point temperature.
  • \( T_0 \) is the reference temperature in Kelvin (typically 273.15 K).
  • \( P_W(p, h_{2}O) \) is the partial water vapor pressure.
Author
Lars Hoffmann

Definition at line 2085 of file mptrac.h.

◆ TICE

#define TICE (   p,
  h2o 
)
Value:
(T0 + 272.62 * log(PW((p), (h2o)) / 6.112) \
/ (22.46 - log(PW((p), (h2o)) / 6.112)))

Calculate frost point temperature (WMO, 2018).

This macro computes the frost point temperature using the formula provided by the World Meteorological Organization (WMO, 2018).

Parameters
pThe atmospheric pressure in hPa.
h2oThe water vapor volume mixing ratio.
Returns
The frost point temperature in Kelvin.

Formula:

\[ T_{\textrm{ice}} = T_0 + \frac{272.62 \times \ln\left(\frac{{P_W(p, h_{2}O)}}{6.112}\right)}{22.46 - \ln\left(\frac{{P_W(p, h_{2}O)}}{6.112}\right)} \]

where:

  • \( T_{\textrm{ice}} \) is the frost point temperature.
  • \( T_0 \) is the reference temperature in Kelvin (typically 273.15 K).
  • \( P_W(p, h_{2}O) \) is the partial water vapor pressure.
Author
Lars Hoffmann

Definition at line 2110 of file mptrac.h.

◆ THETA

#define THETA (   p,
 
)     ((t) * pow(1000. / (p), KAPPA))

Compute potential temperature.

This macro calculates the potential temperature of the atmosphere.

Parameters
pThe atmospheric pressure in hPa.
tThe temperature in Kelvin.
Returns
The potential temperature in Kelvin.

Formula:

\[ \theta = T \left( \frac{1000}{P} \right)^{\kappa} \]

where:

  • \( \theta \) is the potential temperature.
  • \( T \) is the temperature in Kelvin.
  • \( P \) is the atmospheric pressure in hPa.
Author
Lars Hoffmann

Definition at line 2134 of file mptrac.h.

◆ THETAVIRT

#define THETAVIRT (   p,
  t,
  h2o 
)     (TVIRT(THETA((p), (t)), MAX((h2o), 0.1e-6)))

Compute virtual potential temperature.

This macro calculates the virtual potential temperature of the atmosphere, which takes into account the effect of water vapor on the atmosphere's buoyancy.

Parameters
pThe atmospheric pressure in hPa.
tThe temperature in Kelvin.
h2oThe water vapor volume mixing ratio (ppv).
Returns
The virtual potential temperature in Kelvin.

Formula:

The virtual potential temperature ( \( \theta_v \)) is computed as

\[ \theta_v = \theta \left( 1 + \frac{0.61 \times q}{\epsilon} \right), \]

where:

  • \( \theta_v \) is the virtual potential temperature.
  • \( \theta \) is the potential temperature.
  • \( q \) is the specific humidity.
  • \( \epsilon \) is the ratio of the molecular weight of water vapor to dry air.
Author
Lars Hoffmann

Definition at line 2163 of file mptrac.h.

◆ TOK

#define TOK (   line,
  tok,
  format,
  var 
)
Value:
{ \
if(((tok)=strtok((line), " \t"))) { \
if(sscanf(tok, format, &(var))!=1) continue; \
} else ERRMSG("Error while reading!"); \
}
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2416

Get string tokens.

This macro extracts tokens from a given string, typically used for parsing input lines.

Parameters
lineThe input string containing tokens.
tokA pointer to the token string.
formatThe format string specifying the expected format of the token.
varThe variable to store the parsed token value.

The macro tokenizes the input line using space and tab characters as delimiters. It then parses each token according to the specified format string and stores the parsed value in the provided variable.

Author
Lars Hoffmann

Definition at line 2184 of file mptrac.h.

◆ TVIRT

#define TVIRT (   t,
  h2o 
)     ((t) * (1. + (1. - EPS) * MAX((h2o), 0.1e-6)))

Compute virtual temperature.

This macro calculates the virtual temperature of air given its temperature and water vapor volume mixing ratio.

Parameters
tThe temperature of the air in Kelvin.
h2oThe water vapor volume mixing ratio.
Returns
The virtual temperature of the air.

The virtual temperature (T_v) is computed as the temperature (t) multiplied by (1 + (1 - EPS) * max(h2o, 0.1e-6)), where EPS is the ratio of the molar mass of water vapor to the molar mass of dry air.

Note
EPS is typically defined as 0.622.
Author
Lars Hoffmann

Definition at line 2209 of file mptrac.h.

◆ USAGE

#define USAGE
Value:
do { \
int iusage; \
for (iusage = 1; iusage < argc; iusage++) \
if (!strcmp(argv[iusage], "-h") \
|| !strcmp(argv[iusage], "--help")) { \
usage(); \
return EXIT_SUCCESS; \
} \
} while (0)

Print usage information on -h or --help.

Calls the local usage() function and exits successfully when any command argument is -h or --help.

Note
This macro expects local argc and argv variables and a local usage() function.
Author
Lars Hoffmann

Definition at line 2223 of file mptrac.h.

◆ Z

#define Z (   p)     (H0 * log(P0 / (p)))

Convert pressure to altitude.

This macro calculates the altitude from the given pressure using the barometric formula.

Parameters
pThe pressure in hPa (hectopascal).
Returns
The altitude in kilometers (km).

Formula:

The altitude (z) is computed as H0 times the natural logarithm of the ratio of the reference pressure (P0) to the given pressure (p), where H0 is the scale height and P0 is the reference pressure at sea level.

Note
H0 and P0 are typically defined as constants specific to the atmosphere.
Author
Lars Hoffmann

Definition at line 2253 of file mptrac.h.

◆ ZDIFF

#define ZDIFF (   lnp0,
  t0,
  h2o0,
  lnp1,
  t1,
  h2o1 
)
Value:
(RI / MA / G0 * 0.5 * (TVIRT((t0), (h2o0)) + TVIRT((t1), (h2o1))) \
* ((lnp0) - (lnp1)))
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:2209
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:289
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:319

Calculate geopotential height difference.

This macro calculates the geopotential height difference between two pressure levels using the hypsometric equation.

Parameters
lnp0The natural logarithm of the pressure at the first level.
t0The temperature at the first level in Kelvin (K).
h2o0The water vapor volume mixing ratio at the first level.
lnp1The natural logarithm of the pressure at the second level.
t1The temperature at the second level in Kelvin (K).
h2o1The water vapor volume mixing ratio at the second level.
Returns
The geopotential height difference in kilometers (km).

Formula: The geopotential height difference (dz) is computed as a function of the difference in natural logarithm of pressure (lnp) between the two levels, the average virtual temperature (ThetaVirt) of the two levels, the specific gas constant for dry air (RI), and the acceleration due to gravity at the surface of the Earth (G0).

Note
The specific gas constant for dry air (RI), the molar mass of dry air (MA), and the acceleration due to gravity at the surface of the Earth (G0) are typically defined as constants specific to the atmosphere.
Author
Lars Hoffmann

Definition at line 2284 of file mptrac.h.

◆ ZETA

#define ZETA (   ps,
  p,
 
)
Value:
(((p) / (ps) <= 0.3 ? 1. : \
sin(M_PI / 2. * (1. - (p) / (ps)) / (1. - 0.3))) \
* THETA((p), (t)))
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:2134

Computes the value of the zeta vertical coordinate.

This macro calculates the zeta vertical coordinate based on the given surface pressure (ps), pressure (p), and temperature (t). The calculation depends on the ratio p/ps:

  • If p/ps <= 0.3, the function returns 1.0 multiplied by THETA(p, t).
  • Otherwise, it computes a sine function transformation scaled by THETA(p, t).
Parameters
psSurface pressure.
pPressure at the given level.
tTemperature at the given level.
Returns
Computed zeta vertical coordinate value.
Author
Lars Hoffmann

Definition at line 2303 of file mptrac.h.

◆ LOGLEV

#define LOGLEV   2

Level of log messages (0=none, 1=basic, 2=detailed, 3=debug).

Definition at line 2314 of file mptrac.h.

◆ LOG

#define LOG (   level,
  ... 
)
Value:
{ \
if(level >= 2) \
printf(" "); \
if(level <= LOGLEV) { \
printf(__VA_ARGS__); \
printf("\n"); \
} \
}
#define LOGLEV
Level of log messages (0=none, 1=basic, 2=detailed, 3=debug).
Definition: mptrac.h:2314

Print a log message with a specified logging level.

This macro prints a formatted log message to the standard output if the specified logging level meets certain conditions. The message will be indented if the logging level is greater than or equal to 2.

Parameters
levelThe logging level of the message. This should be an integer value.
...The formatted message string and its arguments, similar to printf.

The LOG macro provides a simple way to log messages with different levels of importance. The message is only printed if the specified level is less than or equal to the pre-defined LOGLEV macro. If the level is greater than or equal to 2, the message is preceded by two spaces for indentation.

The macro expands to a block of code that:

  • Checks if the level is greater than or equal to 2, and if so, prints two spaces.
  • Checks if the level is less than or equal to LOGLEV, and if so, prints the formatted message followed by a newline.
Note
The LOGLEV macro must be defined with an appropriate logging level before using the LOG macro.
Author
Lars Hoffmann

Definition at line 2346 of file mptrac.h.

◆ WARN

#define WARN (   ...)
Value:
{ \
printf("\nWarning (%s, %s, l%d): ", __FILE__, __func__, __LINE__); \
LOG(0, __VA_ARGS__); \
}

Print a warning message with contextual information.

This macro prints a formatted warning message to the standard output, including the file name, function name, and line number where the warning occurred. The message is then passed to the LOG macro with a logging level of 0.

Parameters
...The formatted warning message string and its arguments, similar to printf.

The WARN macro is used to print warning messages with additional context about where the warning was triggered. The message includes the following contextual information:

  • The name of the source file where the macro is called (__FILE__).
  • The name of the function where the macro is called (__func__).
  • The line number in the source file where the macro is called (__LINE__).

After printing this contextual information, the macro uses the LOG macro with a logging level of 0 to print the actual warning message. This ensures that warning messages are always logged, regardless of the value of LOGLEV.

Note
The LOG macro must be defined before using the WARN macro.
Author
Lars Hoffmann

Definition at line 2383 of file mptrac.h.

◆ ERRMSG

#define ERRMSG (   ...)
Value:
{ \
printf("\nError (%s, %s, l%d): ", __FILE__, __func__, __LINE__); \
LOG(0, __VA_ARGS__); \
exit(EXIT_FAILURE); \
}

Print an error message with contextual information and terminate the program.

This macro prints a formatted error message to the standard output, including the file name, function name, and line number where the error occurred. After printing the message, the program is terminated with an exit status indicating failure.

Parameters
...The formatted error message string and its arguments, similar to printf.

The ERRMSG macro is used to report critical errors that require the program to terminate immediately. The message includes the following contextual information:

  • The name of the source file where the macro is called (__FILE__).
  • The name of the function where the macro is called (__func__).
  • The line number in the source file where the macro is called (__LINE__).

After printing this contextual information, the macro uses the LOG macro with a logging level of 0 to print the actual error message. Finally, the program exits with a failure status (EXIT_FAILURE).

Note
The LOG macro must be defined before using the ERRMSG macro.
Author
Lars Hoffmann

Definition at line 2416 of file mptrac.h.

◆ PRINT

#define PRINT (   format,
  var 
)
Value:
printf("Print (%s, %s, l%d): %s= "format"\n", \
__FILE__, __func__, __LINE__, #var, var);

Print the value of a variable with contextual information.

This macro prints the value of a variable to the standard output, including the file name, function name, and line number where the macro is called. The output also includes the variable's name and value in a formatted string.

Parameters
formatThe format string used to print the variable's value, similar to printf.
varThe variable to be printed.

The PRINT macro is used to output the value of a variable along with additional context about where the macro is called. The message includes:

  • The name of the source file where the macro is called (__FILE__).
  • The name of the function where the macro is called (__func__).
  • The line number in the source file where the macro is called (__LINE__).
  • The name of the variable being printed (#var).
  • The value of the variable, formatted according to the provided format string (format).

This macro is particularly useful for debugging purposes, providing a convenient way to trace variable values and their locations in the code.

Note
The format string must be compatible with the type of the variable being printed.
Author
Lars Hoffmann

Definition at line 2451 of file mptrac.h.

◆ NTIMER

#define NTIMER   100

Maximum number of timers.

Definition at line 2460 of file mptrac.h.

◆ PRINT_TIMERS

#define PRINT_TIMERS    timer("END", "END", 1);

Print the current state of all timers.

This macro calls the timer function with predefined arguments to signify the end of the timer logging process. It is used to print the results of all the timers that have been tracked.

Note
The timer function must be defined elsewhere in the codebase for this macro to function correctly.
Author
Lars Hoffmann

Definition at line 2475 of file mptrac.h.

◆ SELECT_TIMER

#define SELECT_TIMER (   id,
  group 
)     timer(id, group, 0);

Select and start a timer with specific attributes.

This macro stops the current timer (if any) and starts a new timer with the specified ID and group. It uses the timer function to log the timer start event.

Parameters
idThe identifier for the timer.
groupThe group name associated with the timer.
Author
Lars Hoffmann

Definition at line 2490 of file mptrac.h.

Function Documentation

◆ broadcast_large_data()

void broadcast_large_data ( void *  data,
size_t  N 
)

Broadcasts large data across all processes in an MPI communicator.

This function divides the data into manageable chunks and broadcasts each chunk sequentially. This approach is necessary because the data size may exceed the maximum allowable message size for a single MPI_Bcast operation.

Parameters
dataPointer to the data to be broadcasted.
NSize of the data in bytes.

The function first broadcasts the total size of the data to all processes. Then, it calculates the number of chunks needed to broadcast the entire data. Each chunk is broadcasted in sequence until the entire data has been sent.

The maximum chunk size is defined as CHUNK_SIZE (2147483647 bytes).

Note
The function assumes that the MPI environment has been initialized before calling this function and will be finalized afterward.
Author
Lars Hoffmann

◆ cart2geo()

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

Converts Cartesian coordinates to geographic coordinates.

This function converts a point from Cartesian coordinates (x, y, z) to geographic coordinates (longitude, latitude, and altitude). It uses the spherical Earth approximation for the conversion.

Parameters
xPointer to an array containing the Cartesian coordinates (x, y, z) in kilometers.
zPointer to a double where the computed altitude (above the reference ellipsoid) will be stored, in kilometers.
lonPointer to a double where the computed longitude (in degrees) will be stored.
latPointer to a double where the computed latitude (in degrees) will be stored.
Author
Lars Hoffmann

Converts Cartesian coordinates to geographic coordinates.

Definition at line 74 of file mptrac.c.

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

◆ clim_oh()

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

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

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

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

Definition at line 89 of file mptrac.c.

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

◆ clim_oh_diurnal_correction()

void clim_oh_diurnal_correction ( const ctl_t ctl,
clim_t clim 
)

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

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

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

Definition at line 124 of file mptrac.c.

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

◆ clim_photo()

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

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

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

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

This function performs the following steps:

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

Definition at line 156 of file mptrac.c.

161 {
162
163 /* Check pressure range... */
164 double p_help = p;
165 if (p < photo->p[photo->np - 1])
166 p_help = photo->p[photo->np - 1];
167 else if (p > photo->p[0])
168 p_help = photo->p[0];
169
170 /* Check sza range... */
171 double sza_help = sza;
172 if (sza < photo->sza[0])
173 sza_help = photo->sza[0];
174 else if (sza > photo->sza[photo->nsza - 1])
175 sza_help = photo->sza[photo->nsza - 1];
176
177 /* Check ozone column range... */
178 double o3c_help = o3c;
179 if (o3c < photo->o3c[0])
180 o3c_help = photo->o3c[0];
181 else if (o3c > photo->o3c[photo->no3c - 1])
182 o3c_help = photo->o3c[photo->no3c - 1];
183
184 /* Get indices... */
185 const int ip = locate_irr(photo->p, photo->np, p_help);
186 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
187 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
188
189 /* Interpolate photolysis rate... */
190 const double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
191 photo->p[ip + 1], rate[ip + 1][isza][io3c],
192 p_help);
193 const double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
194 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1],
195 p_help);
196 const double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
197 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c],
198 p_help);
199 const double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
200 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
201 p_help);
202 const double aux0 =
203 LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
204 const double aux1 =
205 LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
206 const double aux =
207 LIN(photo->sza[isza], aux0, photo->sza[isza + 1], aux1, sza_help);
208 return MAX(aux, 0.0);
209}
int locate_reg(const double *xx, const int n, const double x)
Locate the index of the interval containing a given value in a regular grid.
Definition: mptrac.c:3559
int locate_irr(const double *xx, const int n, const double x)
Locate the index of the interval containing a given value in a sorted array.
Definition: mptrac.c:3495
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:1350
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1377
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3702
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3711
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3708
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3714
int np
Number of pressure levels.
Definition: mptrac.h:3699
int no3c
Number of total ozone columns.
Definition: mptrac.h:3705
Here is the call graph for this function:

◆ clim_tropo()

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

Calculates the tropopause pressure based on climatological data.

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

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

This function performs the following steps:

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

Definition at line 213 of file mptrac.c.

216 {
217
218 /* Get seconds since begin of year... */
219 double sec = FMOD(t, 365.25 * 86400.);
220 while (sec < 0)
221 sec += 365.25 * 86400.;
222
223 /* Get indices... */
224 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
225 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
226
227 /* Interpolate tropopause pressure... */
228 const double p0 = LIN(clim->tropo_lat[ilat],
229 clim->tropo[isec][ilat],
230 clim->tropo_lat[ilat + 1],
231 clim->tropo[isec][ilat + 1], lat);
232 const double p1 = LIN(clim->tropo_lat[ilat],
233 clim->tropo[isec + 1][ilat],
234 clim->tropo_lat[ilat + 1],
235 clim->tropo[isec + 1][ilat + 1], lat);
236 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
237}
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:1120
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3807
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3816
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3810
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3819
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3813
Here is the call graph for this function:

◆ clim_tropo_init()

void clim_tropo_init ( clim_t clim)

Initializes the tropopause data in the climatology structure.

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

Parameters
climPointer to the climatology structure to be initialized.

This function performs the following steps:

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

Definition at line 241 of file mptrac.c.

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

◆ clim_ts()

double clim_ts ( const clim_ts_t ts,
const double  t 
)

Interpolates a time series of climatological variables.

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

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

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

Author
Lars Hoffmann

Definition at line 396 of file mptrac.c.

398 {
399
400 /* Interpolate... */
401 if (t <= ts->time[0])
402 return ts->vmr[0];
403 else if (t >= ts->time[ts->ntime - 1])
404 return ts->vmr[ts->ntime - 1];
405 else {
406 const int idx = locate_irr(ts->time, ts->ntime, t);
407 return LIN(ts->time[idx], ts->vmr[idx],
408 ts->time[idx + 1], ts->vmr[idx + 1], t);
409 }
410}
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3761
double time[CTS]
Time [s].
Definition: mptrac.h:3758
int ntime
Number of timesteps.
Definition: mptrac.h:3755
Here is the call graph for this function:

◆ clim_zm()

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

Interpolates monthly mean zonal mean climatological variables.

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

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

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

Author
Lars Hoffmann

Definition at line 414 of file mptrac.c.

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

◆ compress_log_level()

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

Write one row of per-level compression diagnostics.

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

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

Definition at line 666 of file mptrac.c.

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

◆ compress_log_levels_3d()

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

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

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

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

Definition at line 765 of file mptrac.c.

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

◆ compress_cms()

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

Compresses or decompresses a 3-D meteorological field using cmultiscale.

This routine compresses or decompresses a meteorological field described by the metadata in met. Compression thresholds are selected from ctl based on varname.

Parameters
[in]ctlControl/settings structure providing CMS parameters.
[in]metMeteorological metadata describing the field layout.
[in]varnameVariable name used for selecting the CMS epsilon threshold.
[in,out]arrayField data buffer (decompress: output, compress: input).
[in]decompressNon-zero to decompress; zero to compress.
[in,out]level_logOptional output stream for per-level compression diagnostics, or NULL to disable.
[in,out]inoutBinary stream used for CMS I/O (decompress: read, compress: write).
Author
Lars Hoffmann

◆ compress_scale_to_unit()

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

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

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

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

Definition at line 811 of file mptrac.c.

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

◆ compress_unscale_from_unit()

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

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

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

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

Definition at line 854 of file mptrac.c.

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

◆ compress_read_lossy_scale()

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

Read optional lossyscaling metadata for a 3-D field.

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

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

Definition at line 874 of file mptrac.c.

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

◆ compress_write_lossy_scale()

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

Write optional lossyscaling metadata for a 3-D field.

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

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

Definition at line 909 of file mptrac.c.

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

◆ compress_metvar_index()

int compress_metvar_index ( const char *  varname)

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

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

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

Definition at line 969 of file mptrac.c.

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

◆ compress_pck()

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

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

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

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

Definition at line 986 of file mptrac.c.

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

◆ compress_sz3()

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

Compresses or decompresses a 3-D float array using the SZ3 library.

This function either compresses a 3-D floating-point array and writes it to a file stream, or reads compressed SZ3 data from a file stream and decompresses it into the provided array. The SZ3 error bound can be specified either by relative precision (bits) or absolute tolerance.

Parameters
[in]ctlControl structure with compression parameters.
[in]metMeteorological data providing dimensions.
[in]varnameVariable name for logging.
[in,out]arrayFloat array to compress or decompress.
[in]decompressNon-zero to decompress; zero to compress.
[in,out]level_logOptional per-level diagnostics stream, or NULL.
[in,out]inoutFile stream for reading/writing compressed data.
Note
The function uses ctl->met_sz3_prec[] and ctl->met_sz3_tol[] to determine the error bound.
Exactly one of ctl->met_sz3_prec[] or ctl->met_sz3_tol[] must be set to a positive value.
The SZ3 data type is fixed to SZ_FLOAT for this function.
Exceptions
ERRMSGif input parameters are invalid, memory allocation fails, compression/decompression fails, or file I/O errors occur.
See also
SZ_compress_args
SZ_decompress
Author
Lars Hoffmann

◆ compress_zfp()

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

Compresses or decompresses a 3D array of floats using the ZFP library.

This function either compresses or decompresses a 3D array of floats based on the value of the decompress parameter. Compression reduces the storage size using the ZFP compression algorithm, which supports fixed-precision or fixed-accuracy modes. Decompression restores the original float values from the compressed representation.

Parameters
[in]ctlControl structure with compression parameters.
[in]metMeteorological data providing dimensions.
[in]varnameVariable name for logging.
[in,out]arrayFloat array to compress or decompress.
[in]decompressNon-zero to decompress; zero to compress.
[in,out]level_logOptional per-level diagnostics stream, or NULL.
[in,out]inoutFile stream for reading/writing compressed data.

The function performs the following steps:

  • Allocates metadata for the 3D array and the ZFP compressed stream.
  • Sets the compression mode based on the precision or tolerance parameters.
  • Allocates a buffer for the compressed data.
  • Associates a bit stream with the allocated buffer and sets up the ZFP stream.
  • If decompressing:
    • Reads the size of the compressed data and the compressed data itself from the file.
    • Decompresses the data and stores it in the array.
  • If compressing:
    • Compresses the data and writes the compressed data size and the compressed data itself to the file.

The function logs the compression or decompression details and frees allocated resources before returning.

Note
The function uses ctl->met_zfp_prec[] and ctl->met_zfp_tol[] to determine the error bound.
Ensure that either the precision or tolerance parameter is set to a value greater than 0.
Author
Lars Hoffmann

◆ compress_zstd()

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

Compresses or decompresses a float array using ZSTD.

The routine compresses or decompresses one full 3-D meteorological field as a raw byte stream. It does not apply level-wise scaling or quantization; the reconstructed field is the direct result of the ZSTD frame decode.

Parameters
[in]ctlControl structure with compression parameters.
[in]metMeteorological data providing grid dimensions and pressure levels.
[in]varnameVariable name for logging.
[in,out]arrayFloat array to compress or decompress.
[in]decompressNon-zero to decompress; zero to compress.
[in,out]level_logOptional per-level diagnostics stream, or NULL.
[in,out]inoutFile stream for reading/writing the ZSTD payload.
Note
This function uses ZSTD's advanced compression API (ZSTD_compress2) and may use multiple workers as configured in ctl.
Author
Lars Hoffmann

◆ compress_lz4()

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

Compresses or decompresses a float array using LZ4.

The routine compresses or decompresses one full 3-D meteorological field as a raw byte stream. It does not apply level-wise scaling or quantization; the reconstructed field is the direct result of the LZ4 block decode.

Parameters
[in]ctlControl structure with compression parameters.
[in]metMeteorological data providing grid dimensions and pressure levels.
[in]varnameVariable name for logging.
[in,out]arrayFloat array to compress or decompress.
[in]decompressNon-zero to decompress; zero to compress.
[in,out]level_logOptional per-level diagnostics stream, or NULL.
[in,out]inoutFile pointer for input/output. Used for reading or writing compressed data.
Note
This function uses the block API (LZ4_compress_fast / LZ4_decompress_safe).
The default acceleration factor is 1 when ctl->met_lz4_accel is not positive.
Author
Lars Hoffmann

◆ cos_sza()

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

Calculates the cosine of the solar zenith angle.

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

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

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

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

Definition at line 1857 of file mptrac.c.

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

◆ day2doy()

void day2doy ( const int  year,
const int  mon,
const int  day,
int *  doy 
)

Get day of year from date.

Converts a given date to the day of the year (DOY).

This function computes the day of the year (DOY) for a given date specified by the year, month, and day. It takes into account whether the given year is a leap year or not.

Parameters
yearThe year of the date.
monThe month of the date (1-12).
dayThe day of the month (1-31).
doyPointer to an integer where the computed day of the year will be stored.

The function uses two arrays, d0 and d0l, which contain the cumulative number of days at the start of each month for non-leap years and leap years respectively. It checks if the year is a leap year and calculates the day of the year accordingly.

Note
The function assumes that the input date is valid.
Author
Lars Hoffmann

Definition at line 1898 of file mptrac.c.

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

◆ dd_assign_subdomains()

void dd_assign_subdomains ( const ctl_t ctl,
const dd_t dd,
atm_t atm,
const int  init 
)

Assign or update particle subdomain ownership.

This routine determines whether each atmospheric particle belongs to the local MPI subdomain and updates the domain-decomposition bookkeeping quantities stored in the atmospheric state.

The particle longitude and latitude are first normalized using dd_normalize_lon_lat() to ensure consistency with the longitude convention and pole handling of the global meteorological grid stored in the domain decomposition structure.

The particle position is then mapped to global grid indices using locate_reg() for longitude and locate_irr() for latitude. These indices are compared with the index range of the local subdomain owned by the current MPI rank.

If init is nonzero, the routine performs the initial ownership assignment. Particles inside the local subdomain are assigned to the current MPI rank by setting both ctl->qnt_current_subdomain and ctl->qnt_target_subdomain to that rank. Particles outside the local subdomain are marked invalid by setting both quantities to -1.

If init is zero, the routine updates only the destination rank. Particles already marked invalid (qnt_current_subdomain == -1) are skipped. For particles that remain inside the local subdomain, ctl->qnt_target_subdomain is set to the current MPI rank. For particles that have left the local subdomain, the destination rank is recomputed with dd_calc_subdomain_from_coords().

Parameters
[in]ctlControl structure containing the indices of the domain-decomposition quantities qnt_current_subdomain and qnt_target_subdomain.
[in]ddDomain decomposition structure containing the global grid and subdomain layout information.
[in,out]atmAtmospheric state. Particle positions are read from this structure and the subdomain and/or destination quantities are updated in place.
[in]initInitialization flag. If nonzero, perform the initial subdomain assignment; otherwise only update destination ranks for particle exchange.
Note
  • The local MPI rank is obtained internally from MPI_COMM_WORLD.
  • During non-initial updates, particles already marked invalid are ignored.
  • When compiled with _OPENACC, the particle loop may execute on an accelerator.
Author
Jan Clemens
Lars Hoffmann

◆ dd_atm2particles()

void dd_atm2particles ( const ctl_t ctl,
cache_t cache,
atm_t atm,
particle_t particles,
const int  npart 
)

Copy migratable atmospheric particles from the ATM state into a particle buffer.

This routine scans the domain-decomposition particle region of the atmospheric state and copies particles that must be transferred to a different MPI rank into the temporary particle communication buffer.

The routine processes atmospheric entries in the index range [atm->np, atm->np + npart). A particle is selected for export if all of the following conditions are met:

  • atm->q[ctl->qnt_target_subdomain][ip] != rank,
  • atm->q[ctl->qnt_target_subdomain][ip] >= 0,
  • atm->q[ctl->qnt_current_subdomain][ip] >= 0.

For each selected entry, the particle coordinates (time, lon, lat, p) and all quantities q[iq] are copied into particles[ip - atm->np].

After copying, the atmospheric entry is marked as inactive for local ownership by setting atm->q[ctl->qnt_current_subdomain][ip] = -1, and the cached time step cache->dt[ip] is reset to zero.

Parameters
[in]ctlPointer to the control structure containing the quantity indices qnt_target_subdomain, qnt_current_subdomain, and the number of quantities nq.
[in,out]cachePointer to the cache structure. The cached time-step values dt[ip] of exported particles are reset to zero.
[in,out]atmPointer to the atmospheric state. Particle data are read from the domain-decomposition particle region, and exported entries are marked by setting their subdomain index to -1.
[out]particlesBuffer receiving the particles selected for communication. Selected atmospheric entries are copied to index ip - atm->np.
[in]npartNumber of candidate particle entries in the atmospheric communication region.
Note
  • The current MPI rank is obtained internally from MPI_COMM_WORLD.
  • This routine does not compact the particle buffer; entries corresponding to non-selected atmospheric particles remain untouched.
  • When compiled with _OPENACC, the selection and copy loop may run on the accelerator.
Author
Jan Clemens
Lars Hoffmann

◆ dd_calc_subdomain_from_coords()

int dd_calc_subdomain_from_coords ( const ctl_t ctl,
const dd_t dd,
const double  lon,
const double  lat 
)

Determine MPI subdomain from particle coordinates.

This function maps a particle position to the corresponding MPI rank in the domain-decomposed grid. The longitude and latitude are first normalized using dd_normalize_lon_lat(). The corresponding global grid cell indices are then determined using locate_reg() for longitude and locate_irr() for latitude.

The grid indices are mapped to the zonal and meridional subdomain blocks defined by ctl->dd_subdomains_zonal and ctl->dd_subdomains_meridional. The resulting subdomain indices are converted to an MPI rank assuming the layout:

rank = zonal_rank * dd_subdomains_meridional + merid_rank

This implementation works for both regular and irregular latitude grids.

Parameters
ctlPointer to control structure.
ddPointer to domain decomposition structure.
lonLongitude of particle [deg].
latLatitude of particle [deg].
Returns
MPI rank of the target subdomain.
Author
Jan Clemens
Lars Hoffmann

◆ dd_communicate_particles()

void dd_communicate_particles ( const ctl_t ctl,
const dd_t dd,
particle_t **  particles,
int *  npart,
int *  capacity 
)

Exchange particles between MPI ranks according to their destination rank.

This routine migrates particles to their assigned destination MPI ranks using collective communication. The destination rank of each particle is read from (*particles)[ip].q[ctl->qnt_target_subdomain].

First, the routine counts how many local particles must be sent to each MPI rank, excluding particles whose destination equals the current rank. These counts are exchanged using MPI_Alltoall to determine the number of incoming particles. Temporary send and receive buffers are then allocated, the outgoing particles are packed into the send buffer, and particle data are exchanged with MPI_Alltoallv using the MPI datatype stored in dd->MPI_Particle.

After communication, the received particles replace the leading entries of the particle buffer. For each received particle, both ctl->qnt_target_subdomain and ctl->qnt_current_subdomain are reset to the current MPI rank.

If the receive buffer exceeds the currently allocated particle capacity, the particle array is automatically resized using realloc().

Parameters
[in]ctlPointer to the control structure containing the quantity indices qnt_target_subdomain and qnt_current_subdomain.
[in]ddPointer to the domain decomposition structure containing the MPI datatype MPI_Particle used for particle communication.
[in,out]particlesPointer to the particle buffer. The pointer may be updated if the buffer is resized. On output, the leading entries contain the particles received by the current MPI rank.
[in,out]npartNumber of local particles. On input, it specifies the number of valid particles stored in particles. On output, it is replaced by the number of particles received by the current MPI rank.
[in,out]capacityAllocated capacity of the particle buffer. If necessary, the routine increases this value when resizing the particle array.
Note
  • Particles whose destination rank equals the current MPI rank are not packed into the send buffer.
  • Destination ranks are validated against the number of MPI tasks and must refer to a valid MPI rank.
  • Temporary communication buffers are allocated internally and freed before returning.
Author
Jan Clemens
Lars Hoffmann

◆ dd_init()

void dd_init ( const ctl_t ctl,
dd_t dd,
atm_t atm 
)

Initialize the domain decomposition infrastructure.

This routine initializes the MPI-related data structures required for domain decomposition. It first verifies that the number of MPI ranks in MPI_COMM_WORLD matches the total number of requested subdomains,

ctl->dd_subdomains_meridional * ctl->dd_subdomains_zonal.

It then constructs and commits the MPI datatype dd->MPI_Particle corresponding to the particle_t structure. This datatype is used for particle exchange between MPI ranks.

Finally, the routine performs the initial particle-to-subdomain assignment by calling dd_assign_subdomains() with init = 1.

Parameters
[in]ctlPointer to the control structure containing the domain-decomposition settings, in particular the number of zonal and meridional subdomains.
[in,out]ddPointer to the domain decomposition structure. On return, the MPI datatype MPI_Particle is initialized and committed.
[in,out]atmPointer to the atmospheric state. Its domain-decomposition bookkeeping quantities are initialized by the call to dd_assign_subdomains().
Note
  • The routine aborts if the number of MPI ranks does not equal the total number of configured subdomains.
  • The committed MPI datatype stored in dd->MPI_Particle must be released later with MPI_Type_free() when the domain decomposition is finalized.
Author
Jan Clemens
Lars Hoffmann

◆ dd_normalize_lon_lat()

void dd_normalize_lon_lat ( const dd_t dd,
double *  lon,
double *  lat 
)

Normalize geographic coordinates to the global grid convention.

This helper routine normalizes a longitude/latitude pair so that it is consistent with the longitude convention of the global meteorological grid stored in the domain decomposition structure.

The function performs the following steps:

  • Normalizes longitude to the grid convention used by dd->lon_glob (either [-180,180) or [0,360)).
  • Wraps latitude values outside the physical range [-90,90] across the poles and shifts longitude by 180° accordingly.
  • Renormalizes longitude again after pole crossing.

This ensures that coordinates used for domain-decomposition checks and subdomain index calculations are always mapped consistently to the global grid representation.

Parameters
[in]ddPointer to the domain decomposition structure containing the global longitude grid (dd->lon_glob).
[in,out]lonPointer to longitude [deg]. The value is normalized in-place to match the grid convention.
[in,out]latPointer to latitude [deg]. Values outside [-90,90] are wrapped across the poles in-place.
Note
  • Uses the FMOD macro instead of fmod() to ensure compatibility with GPU/OpenACC builds.
  • The routine is marked with #pragma acc routine seq so it can be called from within OpenACC parallel loops.
Author
Lars Hoffmann

◆ dd_particles2atm()

void dd_particles2atm ( const ctl_t ctl,
cache_t cache,
const particle_t particles,
const int  npart,
atm_t atm 
)

Copy received particles from the communication buffer into the atmospheric state.

This routine appends particles from the temporary domain-decomposition particle buffer to the atmospheric particle arrays. The particles are written into the index range

[atm->np, atm->np + npart)

of the atmospheric state.

For each transferred particle, the routine copies the particle coordinates (time, lon, lat, p) and all particle quantities q[iq] into the atmospheric arrays. The cached time-step value cache->dt[ip] is initialized to ctl->dt_mod for each appended particle.

After all particles have been copied, the total number of atmospheric particles atm->np is increased by npart.

Parameters
[in]ctlPointer to the control structure containing the number of quantities nq and the model time step dt_mod.
[in,out]cachePointer to the cache structure. The cached time-step values for appended particles are initialized to ctl->dt_mod.
[in]particlesBuffer containing the particles to be appended to the atmospheric state.
[in]npartNumber of valid particles stored in particles.
[in,out]atmPointer to the atmospheric state. The particle data are appended to its arrays, and atm->np is incremented accordingly.
Note
  • The routine appends particles starting at the current value of atm->np.
  • The routine aborts if the updated number of atmospheric particles exceeds the compile-time limit NP.
  • When compiled with _OPENACC, particle data may be copied on the accelerator and the updated value of atm->np is synchronized to the device.
Author
Jan Clemens
Lars Hoffmann

◆ dd_push()

void dd_push ( const ctl_t ctl,
atm_t atm,
cache_t cache,
int *  npart 
)

Compact and stage non-local particles for domain decomposition transfer.

This routine scans all local atmospheric particles and moves those that need to be transferred to other MPI ranks to a contiguous region at the end of the particle arrays (starting at index atm->np).

A particle is selected for transfer if:

  • atm->q[ctl->qnt_current_subdomain][ip] != -1 (particle is active), AND
  • atm->q[ctl->qnt_target_subdomain][ip] != rank (destination is not current rank)

For each selected particle:

  • All particle data (time, p, lon, lat, all quantities q[iq]) are copied to the end of the respective arrays
  • The original particle is marked as invalid by setting both q[ctl->qnt_target_subdomain][ip] = -1 and q[ctl->qnt_current_subdomain][ip] = -1
  • The cached time step cache->dt[ip] is copied to the new location and reset to zero at the original position
Parameters
[in]ctlPointer to the control structure containing the quantity indices qnt_target_subdomain and qnt_current_subdomain.
[in,out]atmPointer to the atmospheric state. Selected particles are copied to indices [atm->np, atm->np+npart) and original entries are invalidated.
[in,out]cachePointer to the cache structure. Time-step values for moved particles are preserved; original positions are reset to zero.
[out]npartNumber of particles staged for transfer (i.e., the number of valid particles in the range [atm->np, atm->np + npart)).
Note
  • The current MPI rank is obtained internally from MPI_COMM_WORLD.
  • This routine performs a compaction operation: valid local particles remain in [0, atm->np), non-local particles are moved to [atm->np, atm->np + npart).
  • When compiled with _OPENACC, the selection and copy operations execute on the accelerator using atomic operations for the counter.
Author
Jan Clemens
Lars Hoffmann

◆ dd_read_met_nc_grid()

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

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

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

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

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

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

Definition at line 11484 of file mptrac.c.

11488 {
11489
11490 int varid;
11491
11492 /* Get the MPI information... */
11493 int rank = 0, size = 1;
11494#ifdef MPI
11495 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
11496 MPI_Comm_size(MPI_COMM_WORLD, &size);
11497#endif
11498
11499 /* Get grid dimensions... */
11500 NC_INQ_DIM("lon", &dd->nx_glob, 0, 0, 0);
11501 NC_INQ_DIM("lat", &dd->ny_glob, 0, 0, 0);
11502
11503 LOG(2, "Number of longitudes: %d", dd->nx_glob);
11504 LOG(2, "Number of latitudes: %d", dd->ny_glob);
11505
11506 /* Check grid... */
11507 if (dd->nx_glob > DD_EX_GLOB || dd->ny_glob > DD_EY_GLOB)
11508 ERRMSG("Global grid is too large!");
11509
11510 if (ctl->dd_subdomains_zonal > dd->nx_glob)
11511 ERRMSG("Too many zonal subdomains for global x grid!");
11512
11513 if (ctl->dd_subdomains_meridional > dd->ny_glob)
11514 ERRMSG("Too many meridional subdomains for global y grid!");
11515
11516 /* Read global longitudes and latitudes... */
11517 NC_GET_DOUBLE("lon", dd->lon_glob, 1);
11518 NC_GET_DOUBLE("lat", dd->lat_glob, 1);
11519
11520 LOG(2, "Longitudes: %g, %g ... %g deg",
11521 dd->lon_glob[0], dd->lon_glob[1], dd->lon_glob[dd->nx_glob - 1]);
11522 LOG(2, "Latitudes: %g, %g ... %g deg",
11523 dd->lat_glob[0], dd->lat_glob[1], dd->lat_glob[dd->ny_glob - 1]);
11524
11525 /* Rank coordinates in DD layout... */
11526 const int zonal_rank = rank / ctl->dd_subdomains_meridional;
11527 const int merid_rank = rank % ctl->dd_subdomains_meridional;
11528
11529 /* Check for edge cases... */
11530 const int left = (zonal_rank == 0);
11531 const int right = (zonal_rank == ctl->dd_subdomains_zonal - 1);
11532 const int top = (merid_rank == 0);
11533 const int bottom = (merid_rank == ctl->dd_subdomains_meridional - 1);
11534
11535 /* Core owned block (without halos)... */
11536 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
11537 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
11538
11539 const int ix0 = zonal_rank * nx_block;
11540 const int iy0 = merid_rank * ny_block;
11541
11542 int nx_core = nx_block;
11543 int ny_core = ny_block;
11544
11545 if (right)
11546 nx_core += dd->nx_glob - ctl->dd_subdomains_zonal * nx_block;
11547 if (bottom)
11548 ny_core += dd->ny_glob - ctl->dd_subdomains_meridional * ny_block;
11549
11550 /* Store core met size first... */
11551 met->nx = nx_core;
11552 met->ny = ny_core;
11553
11554 /* Set hyperslab for core subdomain... */
11555 dd->subdomain_start[0] = 0;
11556 dd->subdomain_start[1] = 0;
11557 dd->subdomain_start[2] = (size_t) iy0;
11558 dd->subdomain_start[3] = (size_t) ix0;
11559
11560 dd->subdomain_count[0] = 1;
11561 dd->subdomain_count[1] = (size_t) met->np;
11562 dd->subdomain_count[2] = (size_t) ny_core;
11563 dd->subdomain_count[3] = (size_t) nx_core;
11564
11565 /* Add inner halos to read window... */
11566 if (!left && !right) {
11567 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
11568 dd->subdomain_count[3] += (size_t) (2 * ctl->dd_halos_size);
11569 } else if (left ^ right) {
11570 dd->subdomain_count[3] += (size_t) ctl->dd_halos_size;
11571 if (!left)
11572 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
11573 }
11574
11575 if (!top && !bottom) {
11576 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
11577 dd->subdomain_count[2] += (size_t) (2 * ctl->dd_halos_size);
11578 } else if (top ^ bottom) {
11579 dd->subdomain_count[2] += (size_t) ctl->dd_halos_size;
11580 if (!top)
11581 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
11582 }
11583
11584 /* Set boundary halo hyperslabs... */
11585 double lon_shift = 0.0;
11586
11587 if (left ^ right) {
11588 dd->halo_bnd_start[0] = 0;
11589 dd->halo_bnd_start[1] = 0;
11590 dd->halo_bnd_start[2] = dd->subdomain_start[2];
11591 dd->halo_bnd_start[3] =
11592 (size_t) (left ? (dd->nx_glob - ctl->dd_halos_size) : 0);
11593
11594 dd->halo_bnd_count[0] = 1;
11595 dd->halo_bnd_count[1] = (size_t) met->np;
11596 dd->halo_bnd_count[2] =
11597 (size_t) met->ny +
11598 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
11599 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
11600
11601 dd->halo_offset_start = left ? (int) dd->halo_bnd_count[3] : 0;
11602 dd->halo_offset_end = left ? 0 : (int) dd->subdomain_count[3];
11603 lon_shift = left ? -360.0 : 360.0;
11604 } else {
11605 dd->halo_bnd_start[0] = 0;
11606 dd->halo_bnd_start[1] = 0;
11607 dd->halo_bnd_start[2] = 0;
11608 dd->halo_bnd_start[3] = 0;
11609
11610 dd->halo_bnd_count[0] = 0;
11611 dd->halo_bnd_count[1] = 0;
11612 dd->halo_bnd_count[2] = 0;
11613 dd->halo_bnd_count[3] = 0;
11614
11615 dd->halo_offset_start = 0;
11616 dd->halo_offset_end = 0;
11617 }
11618
11619 /* Focus on subdomain latitudes... */
11620 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
11621 met->lat[iy] = dd->lat_glob[(int) dd->subdomain_start[2] + iy];
11622
11623 /* Focus on subdomain longitudes... */
11624 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
11625 met->lon[ix + dd->halo_offset_start] =
11626 dd->lon_glob[(int) dd->subdomain_start[3] + ix];
11627
11628 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
11629 met->lon[ix + dd->halo_offset_end] =
11630 dd->lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
11631
11632 /* Reset halo-extended grid dimensions... */
11633 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
11634 met->ny = (int) dd->subdomain_count[2];
11635
11636 LOG(2, "Define subdomain properties.");
11637 LOG(2, "MPI information: Rank %d, Size %d", rank, size);
11638 LOG(2, "Edge position: l=%d,r=%d,t=%d,b=%d", left, right, top, bottom);
11639 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d",
11640 met->nx, met->ny, met->np);
11641 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
11642 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
11643 (int) dd->halo_bnd_count[1]);
11644 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
11645 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
11646 (int) dd->subdomain_count[1]);
11647 LOG(2, "Subdomain start: nx %ld ny %ld np %ld",
11648 dd->subdomain_start[3], dd->subdomain_start[2], dd->subdomain_start[1]);
11649 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld",
11650 dd->halo_bnd_start[3], dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
11651 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
11652 LOG(2, "%d Subdomain longitudes: %g, %g ... %g deg",
11653 rank, met->lon[0], met->lon[1], met->lon[met->nx - 1]);
11654 LOG(2, "%d Subdomain latitudes: %g, %g ... %g deg",
11655 rank, met->lat[0], met->lat[1], met->lat[met->ny - 1]);
11656}
#define DD_EY_GLOB
Maximum number of latitudes of global meteo data.
Definition: mptrac.h:633
#define DD_EX_GLOB
Maximum number of longitudes of global meteo data.
Definition: mptrac.h:628
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1577
#define NC_INQ_DIM(dimname, ptr, min, max, check)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1607
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3567
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3561
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3564
size_t halo_bnd_count[4]
Extent of the periodic boundary halo hyperslab.
Definition: mptrac.h:4072
int halo_offset_end
Offset of the periodic halo block at the end of the local x-array.
Definition: mptrac.h:4078
int nx_glob
Number of global longitudes.
Definition: mptrac.h:4047
size_t halo_bnd_start[4]
Start indices of the periodic boundary halo hyperslab.
Definition: mptrac.h:4069
double lon_glob[DD_EX_GLOB]
Longitudes of the global grid [deg].
Definition: mptrac.h:4053
double lat_glob[DD_EY_GLOB]
Latitudes of the global grid [deg].
Definition: mptrac.h:4056
int halo_offset_start
Offset of the periodic halo block at the beginning of the local x-array.
Definition: mptrac.h:4075
size_t subdomain_count[4]
Extent of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:4066
int ny_glob
Number of global latitudes.
Definition: mptrac.h:4050
size_t subdomain_start[4]
Start indices of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:4063
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3884
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3887

◆ dd_sort()

void dd_sort ( const ctl_t ctl,
const met_t met0,
atm_t atm,
dd_t dd,
int *  npart 
)

Sort local atmospheric particles and determine export counts for domain decomposition.

This routine reorders the local atmospheric particle arrays so that particles remaining on the current MPI rank are placed first, followed by particles that must be sent to other ranks, and finally particles already marked invalid with subdomain index -1.

For each particle a sorting key is constructed:

  • particles with a valid subdomain and destination equal to the current MPI rank receive a key derived from their meteorological grid-box index,
  • particles with a valid subdomain but destination on another rank receive a key larger than any valid grid-box key,
  • particles with subdomain index -1 receive the largest keys and are moved to the end of the arrays.

The resulting permutation is applied to all particle arrays (time, p, lon, lat, and all quantities q[iq]) using dd_sort_help().

After sorting, the routine

  • counts the number of particles that remain on the current rank,
  • counts the number of particles that must be exported to other ranks,
  • stores the export count in npart,
  • reduces atm->np to the number of particles kept locally.

Particles with subdomain index -1 are removed from the active particle set. A warning is issued if such particles are encountered.

Parameters
[in]ctlControl structure containing the quantity indices qnt_current_subdomain, qnt_target_subdomain, and the number of quantities nq.
[in]met0Meteorological grid used to compute sorting keys from particle longitude, latitude, and pressure.
[in,out]atmAtmospheric state. Particle arrays are reordered in place and atm->np is reduced to the number of particles retained locally.
[in,out]ddDomain decomposition structure providing the temporary arrays sort_key and perm used during sorting.
[out]npartNumber of particles that must be sent to other MPI ranks.
Note
  • The current MPI rank is obtained internally from MPI_COMM_WORLD.
  • When compiled with _OPENACC, key generation, counting, and selected data movement may execute on the accelerator.
  • When compiled with THRUST, sorting may use the GPU-based thrustSortWrapper; otherwise a GSL-based index sort is used.
Author
Jan Clemens
Lars Hoffmann

◆ dd_sort_help()

void dd_sort_help ( double *  a,
dd_t dd,
const int  np 
)

Apply the sorting permutation to a particle data array.

This helper routine reorders a one-dimensional particle data array according to the permutation indices stored in dd->perm. The reordering is performed in two passes using the temporary buffer dd->tmp:

  • first, elements are copied into the temporary buffer in permuted order,
  • then, the reordered values are copied back into the original array.

This routine is used by dd_sort() to apply the same permutation to all atmospheric particle arrays, ensuring that time, position, pressure, and tracer quantities remain consistently aligned.

Parameters
[in,out]aPointer to the array to be reordered in place.
[in,out]ddPointer to the domain decomposition structure containing:
  • dd->perm: permutation indices,
  • dd->tmp: temporary buffer used during reordering.
[in]npNumber of elements in the array.
Note
  • The permutation indices are generated by dd_sort().
  • When compiled with _OPENACC, the reordering loops may execute on the accelerator; otherwise OpenMP is used.
Author
Jan Clemens

◆ doy2day()

void doy2day ( const int  year,
const int  doy,
int *  mon,
int *  day 
)

Converts a given day of the year (DOY) to a date (month and day).

This function computes the month and day for a given day of the year (DOY) and year. It accounts for whether the given year is a leap year or not.

Parameters
yearThe year corresponding to the DOY.
doyThe day of the year (1-365 or 1-366).
monPointer to an integer where the computed month will be stored.
dayPointer to an integer where the computed day of the month will be stored.

The function uses two arrays, d0 and d0l, which contain the cumulative number of days at the start of each month for non-leap years and leap years respectively. It checks if the year is a leap year and calculates the month and day of the month accordingly.

Note
The function assumes that the input DOY is valid for the given year.
Author
Lars Hoffmann

Definition at line 2532 of file mptrac.c.

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

◆ fft_help()

void fft_help ( double *  fcReal,
double *  fcImag,
const int  n 
)

Computes the Fast Fourier Transform (FFT) of a complex sequence.

This function calculates the FFT of a complex sequence represented by separate arrays for the real and imaginary parts. The input arrays fcReal and fcImag are modified in place to contain the transformed data.

Parameters
fcRealPointer to an array of doubles representing the real part of the input sequence. The array should have at least n elements.
fcImagPointer to an array of doubles representing the imaginary part of the input sequence. The array should have at least n elements.
nThe number of complex data points in the input sequence. This value should not exceed PMAX.
Precondition
fcReal and fcImag must point to arrays of at least n elements.
n must be less than or equal to PMAX.
Postcondition
The arrays fcReal and fcImag will contain the real and imaginary parts of the FFT result, respectively.
Note
This function uses the GNU Scientific Library (GSL) for computing the FFT. Ensure that GSL is properly installed and linked in your project.
Warning
If n exceeds PMAX, the function will trigger an error message and terminate.
Author
Lars Hoffmann

Definition at line 2562 of file mptrac.c.

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

◆ geo2cart()

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

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

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

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

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

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

Definition at line 2601 of file mptrac.c.

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

◆ get_met_filename()

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

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

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

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

Definition at line 2619 of file mptrac.c.

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

◆ get_met_replace()

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

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

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

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

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

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

Definition at line 2688 of file mptrac.c.

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

◆ get_tropo()

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

Calculate tropopause data.

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

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

Definition at line 2712 of file mptrac.c.

2727 {
2728
2730
2731 ctl->met_tropo = met_tropo;
2732 read_met_tropo(ctl, clim, met);
2733#pragma omp parallel for default(shared) private(ci,cw)
2734 for (int ix = 0; ix < nx; ix++)
2735 for (int iy = 0; iy < ny; iy++) {
2736 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
2737 &pt[iy * nx + ix], ci, cw, 1);
2738 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
2739 &ps[iy * nx + ix], ci, cw, 0);
2740 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
2741 &zs[iy * nx + ix], ci, cw, 0);
2742 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
2743 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
2744 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
2745 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
2746 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
2747 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
2748 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
2749 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
2750 }
2751}
void intpol_met_space_2d(const met_t *met, float array[EX][EY], const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological variables in 2D space.
Definition: mptrac.c:3048
void read_met_tropo(const ctl_t *ctl, const clim_t *clim, met_t *met)
Calculates the tropopause and related meteorological variables based on various methods and stores th...
Definition: mptrac.c:12242
void intpol_met_space_3d(const met_t *met, float array[EX][EY][EP], const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological variables in 3D space.
Definition: mptrac.c:2985
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:1173
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:3001
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3995
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3905
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3911
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3998
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3980
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3938
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3977
Here is the call graph for this function:

◆ intpol_check_lon_lat()

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

Adjusts longitude and latitude to ensure they fall within valid bounds.

This function checks and modifies the given longitude and latitude values to fit within the specified longitude and latitude arrays. The longitude is wrapped within a 360-degree range, and the latitude is clamped within the valid range defined by the latitude array.

Parameters
[in]lonsPointer to an array of valid longitude values.
[in]nlonNumber of elements in the longitude array.
[in]latsPointer to an array of valid latitude values.
[in]nlatNumber of elements in the latitude array.
[in]lonInput longitude to be checked and adjusted.
[in]latInput latitude to be checked and adjusted.
[out]lon2Pointer to the adjusted longitude.
[out]lat2Pointer to the adjusted latitude.
Author
Lars Hoffmann

Definition at line 2755 of file mptrac.c.

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

◆ intpol_check_cartesian()

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

Clamps UTM coordinates to the valid bounds.

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

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

Definition at line 2782 of file mptrac.c.

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

◆ intpol_met_4d_zeta()

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

Interpolates meteorological variables to a given position and time.

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

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

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

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

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

Definition at line 2808 of file mptrac.c.

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

◆ intpol_met_space_3d()

void intpol_met_space_3d ( const met_t met,
float  array[EX][EY][EP],
const double  p,
const double  lon,
const double  lat,
double *  var,
int *  ci,
double *  cw,
const int  init 
)

Interpolates meteorological variables in 3D space.

This function interpolates meteorological variables at a specified pressure level and geographic position. It calculates the interpolated value based on the values provided at neighboring grid points and performs interpolation in pressure, longitude, and latitude dimensions.

Parameters
metPointer to the meteorological data.
arrayArray containing meteorological variable values.
pPressure level at which to interpolate.
lonLongitude at which to interpolate.
latLatitude at which to interpolate.
varPointer to store the interpolated variable value.
ciArray to store the calculated indices.
cwArray to store the weighting factors.
initFlag indicating if it's the first call (1) or not (0).

The function first checks the longitude and adjusts it if necessary to ensure it falls within the valid range. It then calculates the interpolation indices based on the provided pressure level, longitude, and latitude. Next, it computes the interpolation weights for pressure, longitude, and latitude.

The function interpolates vertically first and then horizontally. The interpolated value is stored in the memory location pointed to by var.

Note
Ensure that the array, ci, and cw arrays have sufficient memory allocated before calling this function.
Author
Lars Hoffmann

Definition at line 2985 of file mptrac.c.

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

◆ intpol_met_space_2d()

void intpol_met_space_2d ( const met_t met,
float  array[EX][EY],
const double  lon,
const double  lat,
double *  var,
int *  ci,
double *  cw,
const int  init 
)

Interpolates meteorological variables in 2D space.

This function interpolates meteorological variables at a specified geographic position. It calculates the interpolated value based on the values provided at neighboring grid points and performs interpolation in longitude and latitude dimensions.

Parameters
metPointer to the meteorological data.
arrayArray containing meteorological variable values.
lonLongitude at which to interpolate.
latLatitude at which to interpolate.
varPointer to store the interpolated variable value.
ciArray to store the calculated indices.
cwArray to store the weighting factors.
initFlag indicating if it's the first call (1) or not (0).

The function first checks the longitude and adjusts it if necessary to ensure it falls within the valid range. It then calculates the interpolation indices based on the provided longitude and latitude. Next, it computes the interpolation weights for longitude and latitude.

The function interpolates horizontally and stores the interpolated value in the memory location pointed to by var. If any of the data values used in interpolation are not finite, the function handles this situation by choosing a valid value or performing a simple interpolation.

Note
Ensure that the array, ci, and cw arrays have sufficient memory allocated before calling this function.
Author
Lars Hoffmann

Definition at line 3048 of file mptrac.c.

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

◆ intpol_met_time_3d()

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

Interpolates meteorological data in 3D space and time.

This function interpolates meteorological data in three dimensions (longitude, latitude, and pressure) and time. It calculates the interpolated value based on the values provided at neighboring grid points and performs interpolation both spatially and temporally.

Parameters
met0Pointer to the meteorological data at time t0.
array03D array of meteorological data at time t0.
met1Pointer to the meteorological data at time t1.
array13D array of meteorological data at time t1.
tsTime stamp at which to interpolate.
pPressure level at which to interpolate.
lonLongitude at which to interpolate.
latLatitude at which to interpolate.
varPointer to store the interpolated value.
ciArray to store the calculated indices.
cwArray to store the weighting factors.
initFlag indicating if it's the first call (1) or not (0).

The function first performs spatial interpolation for both time instances (t0 and t1) using the intpol_met_space_3d function. It then calculates the weighting factor wt based on the time stamp ts. Finally, it performs temporal interpolation using the interpolated values at t0 and t1 along with the weighting factor to compute the final interpolated value stored in var.

Note
Ensure that the ci and cw arrays have sufficient memory allocated before calling this function.
Author
Lars Hoffmann

Definition at line 3112 of file mptrac.c.

3124 {
3125
3126 double var0, var1;
3127
3128 /* Spatial interpolation... */
3129 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
3130 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
3131
3132 /* Get weighting factor... */
3133 const double wt = (met1->time - ts) / (met1->time - met0->time);
3134
3135 /* Interpolate... */
3136 *var = wt * (var0 - var1) + var1;
3137}
Here is the call graph for this function:

◆ intpol_met_time_2d()

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

Interpolates meteorological data in 2D space and time.

This function interpolates meteorological data in two dimensions (longitude and latitude) and time. It calculates the interpolated value based on the values provided at neighboring grid points and performs interpolation both spatially and temporally.

Parameters
met0Pointer to the meteorological data at time t0.
array02D array of meteorological data at time t0.
met1Pointer to the meteorological data at time t1.
array12D array of meteorological data at time t1.
tsTime stamp at which to interpolate.
lonLongitude at which to interpolate.
latLatitude at which to interpolate.
varPointer to store the interpolated value.
ciArray to store the calculated indices.
cwArray to store the weighting factors.
initFlag indicating if it's the first call (1) or not (0).

The function first performs spatial interpolation for both time instances (t0 and t1) using the intpol_met_space_2d function. It then calculates the weighting factor wt based on the time stamp ts. Finally, it performs temporal interpolation using the interpolated values at t0 and t1 along with the weighting factor to compute the final interpolated value stored in var. If one of the interpolated values is not finite, it selects the valid value based on the weighting factor wt.

Note
Ensure that the ci and cw arrays have sufficient memory allocated before calling this function.
Author
Lars Hoffmann

Definition at line 3141 of file mptrac.c.

3152 {
3153
3154 double var0, var1;
3155
3156 /* Spatial interpolation... */
3157 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
3158 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
3159
3160 /* Get weighting factor... */
3161 const double wt = (met1->time - ts) / (met1->time - met0->time);
3162
3163 /* Interpolate... */
3164 if (isfinite(var0) && isfinite(var1))
3165 *var = wt * (var0 - var1) + var1;
3166 else if (wt < 0.5)
3167 *var = var1;
3168 else
3169 *var = var0;
3170}
Here is the call graph for this function:

◆ intpol_tropo_3d()

void intpol_tropo_3d ( const double  time0,
float  array0[EX][EY],
const double  time1,
float  array1[EX][EY],
const double  lons[EX],
const double  lats[EY],
const int  nlon,
const int  nlat,
const double  time,
const double  lon,
const double  lat,
const int  method,
double *  var,
double *  sigma 
)

Interpolates tropopause data in 3D (latitude, longitude, and time).

This function performs interpolation of tropopause data at a given latitude, longitude, and time. The interpolation can be performed using either linear interpolation or nearest neighbor interpolation. The standard deviation of the data points used in the interpolation is also computed.

Parameters
time0Time corresponding to the first data array array0.
array0A 2D array of tropopause data at time0. The dimensions are EX by EY.
time1Time corresponding to the second data array array1.
array1A 2D array of tropopause data at time1. The dimensions are EX by EY.
lonsArray of longitudes with EX elements.
latsArray of latitudes with EY elements.
nlonNumber of longitudes.
nlatNumber of latitudes.
timeThe specific time at which to interpolate the data.
lonThe specific longitude at which to interpolate the data.
latThe specific latitude at which to interpolate the data.
methodInterpolation method: 1 for linear interpolation, otherwise nearest neighbor interpolation is used.
varPointer to the variable where the interpolated value will be stored.
sigmaPointer to the variable where the standard deviation of the data points will be stored.
Precondition
array0 and array1 must be 2D arrays of size EX by EY.
lons must have at least nlon elements and lats must have at least nlat elements.
Postcondition
var will contain the interpolated value.
sigma will contain the standard deviation of the data points used in the interpolation.
Note
The function adjusts the longitude to ensure it is within the range defined by lons.
This function uses the auxiliary functions locate_reg, LIN, and NN for locating indices and performing interpolation.
Warning
Ensure that EX and EY are defined appropriately to match the dimensions of array0 and array1.
Author
Lars Hoffmann

Definition at line 3174 of file mptrac.c.

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

◆ jsec2time()

void jsec2time ( const double  jsec,
int *  year,
int *  mon,
int *  day,
int *  hour,
int *  min,
int *  sec,
double *  remain 
)

Converts Julian seconds to calendar date and time components.

This function converts Julian seconds to calendar date and time components, including year, month, day, hour, minute, and second. It also calculates the fractional part of the seconds.

Parameters
jsecJulian seconds to convert.
yearPointer to store the year.
monPointer to store the month.
dayPointer to store the day.
hourPointer to store the hour.
minPointer to store the minute.
secPointer to store the second.
remainPointer to store the fractional part of seconds.

The function initializes a time structure t0 with a fixed starting date and time. It then converts the Julian seconds to a time_t type by adding the seconds to the epoch time. Next, it converts the time_t value to a UTC time structure t1. Finally, it extracts the year, month, day, hour, minute, and second components from t1 and calculates the fractional part of seconds, which is stored in remain.

Author
Lars Hoffmann

Definition at line 3265 of file mptrac.c.

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

◆ kernel_weight()

double kernel_weight ( const double  kz[EP],
const double  kw[EP],
const int  nk,
const double  p 
)

Calculates the kernel weight based on altitude and given kernel data.

This function calculates the kernel weight based on altitude and given kernel data. It takes arrays of altitudes (kz) and corresponding weights (kw), the number of data points (nk), and the current altitude (p) as input.

Parameters
kzArray of altitudes.
kwArray of corresponding weights.
nkNumber of data points.
pCurrent altitude.
Returns
The calculated kernel weight.

If the number of data points is less than 2 (nk < 2), the function returns a default weight of 1.0.

The function first computes the altitude z based on the current altitude p. Then it checks whether z is outside the range of altitudes in the kernel data. If so, it returns the corresponding weight at the nearest altitude boundary. Otherwise, it interpolates linearly between the two closest altitudes in the kernel data to determine the weight at altitude z.

Author
Lars Hoffmann

Definition at line 3298 of file mptrac.c.

3302 {
3303
3304 /* Check number of data points... */
3305 if (nk < 2)
3306 return 1.0;
3307
3308 /* Get altitude... */
3309 const double z = Z(p);
3310
3311 /* Get weighting factor... */
3312 if (z < kz[0])
3313 return kw[0];
3314 else if (z > kz[nk - 1])
3315 return kw[nk - 1];
3316 else {
3317 const int idx = locate_irr(kz, nk, z);
3318 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
3319 }
3320}
Here is the call graph for this function:

◆ lapse_rate()

double lapse_rate ( const double  t,
const double  h2o 
)

Calculates the moist adiabatic lapse rate in Kelvin per kilometer.

This function calculates the moist adiabatic lapse rate in Kelvin per kilometer from the given temperature (t) in Kelvin and water vapor volume mixing ratio (h2o).

Parameters
tTemperature in Kelvin.
h2oWater vapor volume mixing ratio.
Returns
The moist adiabatic lapse rate in Kelvin per kilometer.

The moist adiabatic lapse rate is calculated using the formula:

\[ \Gamma = \frac{{1000 \times g \times \left(a + L_v \times r \times T\right)}} {{C_{pd} \times a + L_v^2 \times r \times \epsilon}} \]

where:

  • \( \Gamma \) is the lapse rate in Kelvin per kilometer.
  • \( g \) is the acceleration due to gravity (constant).
  • \( a = R_a \times T^2 \) is a term based on the gas constant for dry air and temperature squared.
  • \( R_a \) is the gas constant for dry air.
  • \( T \) is the temperature in Kelvin.
  • \( L_v \) is the latent heat of vaporization.
  • \( r = \frac{{S_h(h_2o)}}{{1 - S_h(h_2o)}} \) is a term based on the water vapor mixing ratio.
  • \( S_h(h_2o) \) is the saturation vapor pressure relative to the pressure at saturation.
  • \( C_{pd} \) is the specific heat of dry air at constant pressure.
  • \( \epsilon \) is the ratio of the gas constants for dry air and water vapor.

The constants used in the calculation are defined externally:

  • \( g \): Acceleration due to gravity (constant).
  • \( R_a \): Gas constant for dry air.
  • \( L_v \): Latent heat of vaporization.
  • \( C_{pd} \): Specific heat of dry air at constant pressure.
  • \( \epsilon \): Ratio of the gas constants for dry air and water vapor.
See also
Wikipedia - Lapse rate
Author
Lars Hoffmann

Definition at line 3324 of file mptrac.c.

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

◆ level_definitions()

void level_definitions ( ctl_t ctl)

Defines pressure levels for meteorological data.

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

Parameters
ctlControl structure containing information about pressure level definitions.

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

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

Definition at line 3342 of file mptrac.c.

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

◆ locate_irr()

int locate_irr ( const double *  xx,
const int  n,
const double  x 
)

Locate the index of the interval containing a given value in a sorted array.

This function locates the index of the interval containing a given value in a sorted array. It uses a binary search algorithm to efficiently find the interval.

Parameters
xxPointer to the sorted array.
nSize of the array.
xValue to be located.
Returns
Index of the interval containing the value x.

The function assumes that the array xx is sorted in ascending order. It returns the index of the interval where the value x is located. If the value x is outside the range of the array, the function returns the index of the closest interval.

Author
Lars Hoffmann

Definition at line 3495 of file mptrac.c.

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

◆ locate_irr_float()

int locate_irr_float ( const float *  xx,
const int  n,
const double  x,
const int  ig 
)

Locate the index of the interval containing a given value in an irregularly spaced array.

This function performs a binary search to locate the interval in the array xx such that xx[ig] <= x < xx[ig + 1]. If the value x lies within the interval specified by the initial guess index ig, the function returns ig. Otherwise, it searches the array to find the correct interval.

Parameters
xxPointer to the array of floats representing the irregularly spaced intervals. The array must be of size n.
nThe number of elements in the array xx.
xThe value to locate within the intervals of the array xx.
igThe initial guess index. If the interval [xx[ig], xx[ig+1]) contains x, the function returns ig directly.
Returns
The index i such that xx[i] <= x < xx[i + 1]. If x is out of bounds, it returns the index of the closest interval.
Note
The function assumes that the array xx contains at least two elements.
The function can handle both increasing and decreasing sequences in the array xx.
Warning
The behavior is undefined if the array xx is not sorted in either increasing or decreasing order, or if it contains less than two elements.
Author
Lars Hoffmann

Definition at line 3525 of file mptrac.c.

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

◆ locate_reg()

int locate_reg ( const double *  xx,
const int  n,
const double  x 
)

Locate the index of the interval containing a given value in a regular grid.

This function locates the index of the interval containing a given value in a regular grid. It calculates the index based on the spacing between grid points and the value to be located.

Parameters
xxPointer to the array representing the regular grid.
nSize of the grid (number of grid points).
xValue to be located.
Returns
Index of the interval containing the value x.

The function assumes that the array xx represents a regular grid with equally spaced points. It calculates the index of the interval where the value x is located based on the spacing between grid points. If the value x is outside the range of the grid, the function returns the index of the closest interval.

Author
Lars Hoffmann

Definition at line 3559 of file mptrac.c.

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

◆ locate_vert()

void locate_vert ( float  profiles[EX][EY][EP],
const int  np,
const int  lon_ap_ind,
const int  lat_ap_ind,
const double  alt_ap,
int *  ind 
)

Locate the four vertical indizes of a box for a given height value.

This function locates the vertical indices corresponding to a given height in a 3D irregular grid. It calculates the indices based on the specified longitude and latitude indices of the grid.

Parameters
profiles3D array representing the irregular grid.
npSize of the profile (number of data points).
lon_ap_indIndex of the longitude.
lat_ap_indIndex of the latitude.
alt_apHeight value.
indPointer to an array to store the resulting indices.

The function calculates the indices corresponding to the specified height in the 3D irregular grid. It stores the resulting indices in the array pointed to by ind. The indices are calculated based on the specified longitude and latitude indices of the grid.

Author
Lars Hoffmann

Definition at line 3578 of file mptrac.c.

3584 {
3585
3586 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
3587 np, height_ap, 0);
3588 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
3589 np, height_ap, ind[0]);
3590 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
3591 np, height_ap, ind[1]);
3592 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
3593 np, height_ap, ind[2]);
3594}
int locate_irr_float(const float *xx, const int n, const double x, const int ig)
Locate the index of the interval containing a given value in an irregularly spaced array.
Definition: mptrac.c:3525
Here is the call graph for this function:

◆ module_advect()

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

Advances particle positions using different advection schemes.

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

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

Definition at line 3598 of file mptrac.c.

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

◆ module_advect_init()

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

Initializes the advection module by setting up pressure fields.

This function initializes the advection module, setting up the air parcel pressure to be consistent with the given zeta vertical coordinate. It utilizes meteorological data from two time steps and interpolates the pressure values accordingly.

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

The function performs the following operations:

  • Sets up a timer labeled "MODULE_ADVECT_INIT" within the "PHYSICS" category.
  • If the zeta vertical coordinate system is specified (ctl->vert_coord_ap == 1), it initializes the pressure fields to be consistent with the zeta coordinate using 4D interpolation.
Author
Jan Clemens

Definition at line 3762 of file mptrac.c.

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

◆ module_bound_cond()

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

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

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

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

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

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

Definition at line 3789 of file mptrac.c.

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

◆ module_chem_grid()

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

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

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

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

Parallelization is supported via OpenMP or OpenACC.

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

Definition at line 3885 of file mptrac.c.

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

◆ module_chem_init()

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

Initializes the chemistry modules by setting atmospheric composition.

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

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

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

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

Definition at line 4065 of file mptrac.c.

4071 {
4072
4073 /* Set timer... */
4074 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS");
4075
4076 /* Loop over particles... */
4077 PARTICLE_LOOP(0, atm->np, 0,
4078 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4079
4080 /* Set H2O and O3 using meteo data... */
4082 if (ctl->qnt_Ch2o >= 0) {
4083 double h2o;
4084 INTPOL_3D(h2o, 1);
4085 SET_ATM(qnt_Ch2o, h2o);
4086 }
4087 if (ctl->qnt_Co3 >= 0) {
4088 double o3;
4089 INTPOL_3D(o3, 1);
4090 SET_ATM(qnt_Co3, o3);
4091 }
4092
4093 /* Set radical species... */
4094 const double lat_ref =
4095 ctl->met_coord_type == 0 ? atm->lat[ip] : ctl->met_utm_ref_lat;
4096 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
4097 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4098 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
4099 lat_ref, atm->p[ip]));
4100 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
4101 lat_ref, atm->p[ip]));
4102 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
4103 lat_ref, atm->p[ip]));
4104 }
4105}
double clim_oh(const ctl_t *ctl, const clim_t *clim, const double t, const double lon, const double lat, const double p)
Calculates the hydroxyl radical (OH) concentration from climatology data, with an optional diurnal co...
Definition: mptrac.c:89
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1990
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3834
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3837
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3831
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2766
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2769
Here is the call graph for this function:

◆ module_convection()

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

Performs convective mixing of atmospheric particles.

This function adjusts the pressure of atmospheric particles based on boundary layer (PBL) mixing and convective conditions driven by CAPE (Convective Available Potential Energy) and CIN (Convective Inhibition). It uses meteorological data and random numbers for vertical mixing calculations.

Parameters
[in]ctlPointer to the control structure with simulation settings.
[in,out]cachePointer to the cache structure for temporary data and random numbers.
[in,out]met0Pointer to the meteorological data at the initial timestep.
[in,out]met1Pointer to the meteorological data at the subsequent timestep.
[in,out]atmPointer to the atmospheric data structure with particle properties.
Note
  • This function modifies the atm structure in place.
  • Interpolates CAPE, CIN, and other meteorological parameters.
  • Determines the pressure range for PBL and convective mixing.
  • Updates the pressure of particles based on calculated mixing.
Author
Lars Hoffmann

Definition at line 4109 of file mptrac.c.

4114 {
4115
4116 /* Set timer... */
4117 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS");
4118
4119 /* Create random numbers... */
4120 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
4121
4122 /* Loop over particles... */
4123 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4124
4125 /* Interpolate surface pressure... */
4126 double ps;
4128 INTPOL_2D(ps, 1);
4129
4130 /* Initialize pressure range for vertical mixing... */
4131 double pbot = ps, ptop = ps;
4132
4133 /* Mixing in the PBL... */
4134 if (ctl->conv_mix_pbl) {
4135
4136 /* Interpolate PBL... */
4137 double pbl;
4138 INTPOL_2D(pbl, 0);
4139
4140 /* Set pressure range... */
4141 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
4142 }
4143
4144 /* Convective mixing... */
4145 if (ctl->conv_cape >= 0) {
4146
4147 /* Interpolate CAPE, CIN, and equilibrium level... */
4148 double cape, cin, pel;
4149 INTPOL_2D(cape, 0);
4150 INTPOL_2D(cin, 0);
4151 INTPOL_2D(pel, 0);
4152
4153 /* Set pressure range... */
4154 if (isfinite(cape) && cape >= ctl->conv_cape
4155 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
4156 ptop = MIN(ptop, pel);
4157 }
4158
4159 /* Apply vertical mixing... */
4160 if (ptop != pbot && atm->p[ip] >= ptop) {
4161
4162 /* Get density range... */
4163 double tbot, ttop;
4164 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
4165 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
4166 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
4167 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
4168 const double rhobot = pbot / tbot;
4169 const double rhotop = ptop / ttop;
4170
4171 /* Get new density... */
4172 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
4173
4174 /* Get pressure... */
4175 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
4176 }
4177 }
4178}
void module_rng(const ctl_t *ctl, double *rs, const size_t n, const int method)
Generate random numbers using various methods and distributions.
Definition: mptrac.c:5794
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3655
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:3085
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL pressure thickness).
Definition: mptrac.h:3082
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:3079
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:3088
Here is the call graph for this function:

◆ module_dd()

void module_dd ( double  t,
const ctl_t ctl,
cache_t cache,
dd_t dd,
atm_t atm,
met_t **  met 
)

Perform domain decomposition and exchange particles between MPI ranks.

This routine redistributes atmospheric particles across MPI processes according to the current spatial domain decomposition so that each process owns the particles located inside its subdomain.

The routine performs the following steps:

  1. Determine the destination subdomain for each particle.
  2. Sort particles so that locally retained particles appear first and particles that must be exported appear afterward.
  3. Convert particle data from the atmospheric structure-of-arrays representation into a temporary particle buffer (array-of-structures).
  4. Exchange particles between MPI ranks according to their destination rank.
  5. Convert the received particle data back into the atmospheric structure-of-arrays representation.

A temporary particle buffer is maintained locally and resized dynamically when necessary to hold outgoing or incoming particles. After the communication step, the atmospheric particle arrays are updated to contain only the particles owned by the current MPI rank.

Parameters
[in]tCurrent simulation time in seconds since 2000-01-01.
[in]ctlControl structure containing simulation settings and quantity indices.
[in,out]cacheCache structure used for temporary particle data during data layout transformations.
[in,out]ddDomain decomposition structure containing grid metadata and auxiliary buffers.
[in,out]atmAtmospheric particle state. Particle ownership and particle arrays are updated in place.
[in]metPointer to the meteorological data used for subdomain assignment and sorting.
Note
  • This routine is available only when MPTRAC is compiled with domain decomposition support (DD) and MPI enabled.
  • Particle exchange is performed using MPI collective communication.
Author
Jan Clemens
Lars Hoffmann

◆ module_decay()

void module_decay ( const ctl_t ctl,
const cache_t cache,
const clim_t clim,
atm_t atm 
)

Simulate exponential decay processes for atmospheric particles.

This function simulates decay processes for atmospheric particles based on their mass or volume mixing ratio. It loops over each particle and calculates the decay rate using weighting factors for tropospheric and stratospheric lifetimes. Exponential decay is then calculated, and the mass or volume mixing ratio of particles is updated accordingly. Loss rates can also be calculated and updated based on the decay process.

The function checks for quantity flags to ensure that mass or volume mixing ratio data is available. It then calculates the weighting factor based on the particle's location in the atmosphere and sets the lifetime accordingly. Exponential decay is calculated using the time step and the lifetime, and the particle's mass or volume mixing ratio is updated. Loss rates can also be updated based on the decay process.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climate data structure containing atmospheric data.
atmPointer to the atmospheric data structure containing particle information.
Author
Lars Hoffmann

Definition at line 4234 of file mptrac.c.

4238 {
4239
4240 /* Set timer... */
4241 SELECT_TIMER("MODULE_DECAY", "PHYSICS");
4242
4243 /* Check quantity flags... */
4244 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4245 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4246
4247 /* Loop over particles... */
4248 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
4249
4250 /* Get weighting factor... */
4251 const double w = tropo_weight(ctl, clim, atm, ip);
4252
4253 /* Set lifetime... */
4254 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
4255
4256 /* Calculate exponential decay... */
4257 const double aux = exp(-cache->dt[ip] / tdec);
4258 if (ctl->qnt_m >= 0) {
4259 if (ctl->qnt_mloss_decay >= 0)
4260 atm->q[ctl->qnt_mloss_decay][ip]
4261 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4262 atm->q[ctl->qnt_m][ip] *= aux;
4263 if (ctl->qnt_loss_rate >= 0)
4264 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
4265 }
4266 if (ctl->qnt_vmr >= 0)
4267 atm->q[ctl->qnt_vmr][ip] *= aux;
4268 }
4269}
double tropo_weight(const ctl_t *ctl, const clim_t *clim, const atm_t *atm, const int ip)
Computes a weighting factor based on tropopause pressure.
Definition: mptrac.c:12831
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2694
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2691
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:3139
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:3136
Here is the call graph for this function:

◆ module_diff_meso()

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

Simulate mesoscale diffusion for atmospheric particles.

This function simulates mesoscale diffusion for atmospheric particles, including horizontal and vertical wind fluctuations. It calculates standard deviations of local wind data and temporal correlations for mesoscale fluctuations. Mesoscale wind fluctuations are then calculated based on the provided random numbers and turbulence parameters. The particle positions are updated accordingly.

The function loops over each particle and calculates indices for interpolation of wind data. It then computes standard deviations of local wind data and temporal correlations for mesoscale fluctuations. Based on the turbulence parameters and provided random numbers, it calculates horizontal and vertical mesoscale wind fluctuations. Finally, it updates the particle positions based on the calculated wind fluctuations.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the meteorological data structure at the current time step.
met1Pointer to the meteorological data structure at the next time step.
atmPointer to the atmospheric data structure containing particle information.
Note
Control parameters TURB_MESOX and TURB_MESOZ define the subgrid-scale variability as a fraction of the grid-scale variance. Stohl et al. (2005) recommend a default value of 0.16 for both parameters, providing a standard approach for turbulence representation. However, recent findings by Bakels et al. (2024) suggest disabling this approach to improve model accuracy under certain conditions. It is advised to evaluate the applicability of these recommendations based on the specific simulation context and objectives.
Author
Lars Hoffmann

Definition at line 4273 of file mptrac.c.

4278 {
4279
4280 /* Set timer... */
4281 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS");
4282
4283 /* Create random numbers... */
4284 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4285
4286 /* Loop over particles... */
4287 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4288
4289 /* Get indices... */
4290 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
4291 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
4292 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
4293
4294 /* Get standard deviations of local wind data... */
4295 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
4296 for (int i = 0; i < 2; i++)
4297 for (int j = 0; j < 2; j++)
4298 for (int k = 0; k < 2; k++) {
4299 umean += met0->u[ix + i][iy + j][iz + k];
4300 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
4301 vmean += met0->v[ix + i][iy + j][iz + k];
4302 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
4303 wmean += met0->w[ix + i][iy + j][iz + k];
4304 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
4305
4306 umean += met1->u[ix + i][iy + j][iz + k];
4307 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
4308 vmean += met1->v[ix + i][iy + j][iz + k];
4309 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
4310 wmean += met1->w[ix + i][iy + j][iz + k];
4311 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
4312 }
4313 usig = usig / 16.f - SQR(umean / 16.f);
4314 usig = (usig > 0 ? sqrtf(usig) : 0);
4315 vsig = vsig / 16.f - SQR(vmean / 16.f);
4316 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
4317 wsig = wsig / 16.f - SQR(wmean / 16.f);
4318 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
4319
4320 /* Set temporal correlations for mesoscale fluctuations... */
4321 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
4322 const double r2 = sqrt(1 - r * r);
4323
4324 /* Calculate horizontal mesoscale wind fluctuations... */
4325 if (ctl->turb_mesox > 0) {
4326 cache->uvwp[ip][0] =
4327 (float) (r * cache->uvwp[ip][0] +
4328 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
4329 atm->lon[ip] +=
4330 DX2COORD(met0, cache->uvwp[ip][0] * cache->dt[ip], atm->lat[ip]);
4331
4332 cache->uvwp[ip][1] =
4333 (float) (r * cache->uvwp[ip][1] +
4334 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
4335 atm->lat[ip] += DY2COORD(met0, cache->uvwp[ip][1] * cache->dt[ip]);
4336 }
4337
4338 /* Calculate vertical mesoscale wind fluctuations... */
4339 if (ctl->turb_mesoz > 0) {
4340 cache->uvwp[ip][2] =
4341 (float) (r * cache->uvwp[ip][2] +
4342 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
4343 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
4344 }
4345 }
4346}
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3652
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:3073
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2854
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:3070
Here is the call graph for this function:

◆ module_diff_pbl()

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

Computes particle diffusion within the planetary boundary layer (PBL).

This function handles the effects of turbulence on particles within the PBL. It calculates turbulent velocity variances, Lagrangian timescales, and updates particle positions and perturbations based on random fluctuations and boundary layer physics. This module adapts the approach of Ryall and Maryon (1998) and Stohl et al. (2005).

Parameters
ctlPointer to the control structure containing model settings.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the meteorological data structure for the current timestep.
met1Pointer to the meteorological data structure for the next timestep.
atmPointer to the atmospheric data structure containing particle states.

The function:

  • Allocates memory for random numbers and generates them using module_rng.
  • Loops over all particles to compute their behavior within the boundary layer.
  • Handles both stable/neutral and unstable conditions based on the surface sensible heat flux.
  • Calculates turbulent velocity variances (sig_u, sig_w), their vertical derivatives, and Lagrangian timescales (tau_u, tau_w).
  • Updates particle velocity perturbations and positions using turbulent diffusion equations.

The function uses OpenACC directives for GPU acceleration.

Note
The function handles edge cases like zero diffusivity and imposes minimum limits on calculated values to ensure stability.
Warning
Ensure that all input pointers are properly initialized and accessible before calling this function.
Author
Lars Hoffmann

Definition at line 4350 of file mptrac.c.

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

◆ module_diff_turb()

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

Applies turbulent diffusion processes to atmospheric particles.

This function calculates and applies turbulent diffusion effects, including horizontal and vertical diffusion, as well as vertical mixing in the planetary boundary layer (PBL), to a set of atmospheric particles based on input parameters and environmental conditions.

Parameters
[in]ctlPointer to the control structure containing simulation parameters.
[in,out]cachePointer to the cache structure for temporary data and random numbers.
[in]climPointer to the climate structure containing climatological data.
[in,out]met0Pointer to the meteorological data structure for the initial timestep.
[in,out]met1Pointer to the meteorological data structure for the next timestep.
[in,out]atmPointer to the atmospheric structure containing particle data.

The function performs the following operations:

  • Allocates temporary arrays for random number generation.
  • Generates random numbers for simulating diffusion effects.
  • Loops over atmospheric particles to compute and apply:
    • Horizontal turbulent diffusion, based on prescribed diffusivity values.
    • Vertical turbulent diffusion, using vertical diffusivity values.
  • Cleans up allocated resources after processing.

Turbulent diffusivity parameters are derived from control inputs and weighted based on atmospheric layer influences (PBL, troposphere, stratosphere).

Note
  • Control parameters TURB_DX_PBL, TURB_DX_TROP, TURB_DX_STRAT, TURB_DZ_PBL, TURB_DZ_TROP, and TURB_DZ_STRAT define horizontal and vertical diffusivities (in units of m**2 s**-1) in the PBL, troposphere, and stratosphere, respectively.
  • Control parameter TURB_PBL_SCHEME activates an optional PBL-specific closure scheme. If a PBL scheme is active, the fixed-K module is only applied outside the PBL.
  • Apply the following settings to reproduce Stohl et al. (2005): TURB_DX_PBL = 50 TURB_DX_TROP = 50 TURB_DX_STRAT = 0 TURB_DZ_PBL = 0 TURB_DZ_TROP = 0 TURB_DZ_STRAT = 0.1 TURB_MESOX = 0.16 TURB_MESOZ = 0.16 TURB_PBL_SCHEME = 0
  • Apply the following setting to reproduce Maryon et al. (1991) and Ryall et al. (1998): TURB_DX_PBL = 5300 TURB_DX_TROP = 1325 TURB_DX_STRAT = 1325 TURB_DZ_PBL = 0 TURB_DZ_TROP = 1.5 TURB_DZ_STRAT = 1.5 TURB_MESOX = 0 TURB_MESOZ = 0 TURB_PBL_SCHEME = 1
Author
Lars Hoffmann

Definition at line 4595 of file mptrac.c.

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

◆ module_dry_depo()

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

Simulate dry deposition of atmospheric particles.

This function simulates the dry deposition of atmospheric particles, including both particulate matter and gases. It calculates the sedimentation velocity for particles based on the atmospheric properties and applies it to determine the loss of mass or volume mixing ratio due to deposition. The function loops over each particle and calculates the loss of mass or volume mixing ratio based on the deposition velocity and time step.

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

Definition at line 4745 of file mptrac.c.

4750 {
4751
4752 /* Set timer... */
4753 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS");
4754
4755 /* Check quantity flags... */
4756 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4757 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4758
4759 /* Loop over particles... */
4760 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4761
4762 /* Get surface pressure... */
4763 double ps;
4765 INTPOL_2D(ps, 1);
4766
4767 /* Check whether particle is above the surface layer... */
4768 if (atm->p[ip] < ps - ctl->dry_depo_dp)
4769 continue;
4770
4771 /* Set depth of surface layer... */
4772 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
4773
4774 /* Calculate sedimentation velocity for particles... */
4775 double v_dep;
4776 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
4777
4778 /* Get temperature... */
4779 double t;
4780 INTPOL_3D(t, 1);
4781
4782 /* Set deposition velocity... */
4783 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4784 atm->q[ctl->qnt_rhop][ip]);
4785 }
4786
4787 /* Use explicit sedimentation velocity for gases... */
4788 else
4789 v_dep = ctl->dry_depo_vdep;
4790
4791 /* Calculate loss of mass based on deposition velocity... */
4792 const double aux = exp(-cache->dt[ip] * v_dep / dz);
4793 if (ctl->qnt_m >= 0) {
4794 if (ctl->qnt_mloss_dry >= 0)
4795 atm->q[ctl->qnt_mloss_dry][ip]
4796 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4797 atm->q[ctl->qnt_m][ip] *= aux;
4798 if (ctl->qnt_loss_rate >= 0)
4799 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
4800 }
4801 if (ctl->qnt_vmr >= 0)
4802 atm->q[ctl->qnt_vmr][ip] *= aux;
4803 }
4804}
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:12589
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2544
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2541
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:3298
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2688
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:3301
Here is the call graph for this function:

◆ module_h2o2_chem()

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

Perform chemical reactions involving H2O2 within cloud particles.

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

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

Definition at line 4808 of file mptrac.c.

4814 {
4815
4816 if (ctl->met_coord_type != 0)
4817 ERRMSG("Only lat/lon grid supported");
4818
4819 /* Set timer... */
4820 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS");
4821
4822 /* Check quantity flags... */
4823 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4824 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4825
4826 /* Parameter of SO2 correction... */
4827 const double low = pow(1. / SO2_CORR_A, 1. / SO2_CORR_B);
4828
4829 /* Loop over particles... */
4830 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4831
4832 /* Check whether particle is inside cloud... */
4833 double lwc, rwc;
4835 INTPOL_3D(lwc, 1);
4836 INTPOL_3D(rwc, 0);
4837 if (!(lwc > 0 || rwc > 0))
4838 continue;
4839
4840 /* Get temperature... */
4841 double t;
4842 INTPOL_3D(t, 0);
4843
4844 /* Get molecular density... */
4845 const double M = MOLEC_DENS(atm->p[ip], t);
4846
4847 /* Reaction rate (Berglen et al., 2004)... */
4848 const double k = H2O2_SO2_RATE_REF * exp(-H2O2_SO2_RATE_TEMP / RI * (1. / t - 1. / CHEM_REF_TEMP)); /* Maass (1999), M^(-2) */
4849
4850 /* Henry constant of SO2... */
4851 const double H_SO2 =
4853 * (1. / t - 1. / CHEM_REF_TEMP)) * RI * t;
4854 const double K_1S = SO2_DISS_K1_REF * exp(SO2_DISS_K1_TEMP * (1. / t - 1. / CHEM_REF_TEMP)); /* unit: mol/L */
4855
4856 /* Henry constant of H2O2... */
4857 const double H_h2o2 =
4859 * (1. / t - 1. / CHEM_REF_TEMP)) * RI * t;
4860
4861 /* Correction factor for high SO2 concentration
4862 (if qnt_Cx is defined, the correction is switched on)... */
4863 double cor = 1.0;
4864 if (ctl->qnt_Cx >= 0)
4865 cor = atm->q[ctl->qnt_Cx][ip] >
4866 low ? SO2_CORR_A * pow(atm->q[ctl->qnt_Cx][ip], SO2_CORR_B) : 1;
4867
4868 const double h2o2 = H_h2o2
4869 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
4870 * M * cor * 1000. / AVO; /* unit: mol/L */
4871
4872 /* Volume water content in cloud [m^3 m^(-3)]... */
4873 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
4874 const double CWC = (lwc + rwc) * rho_air / 1e3;
4875
4876 /* Calculate exponential decay (Rolph et al., 1992)... */
4877 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
4878 const double aux = exp(-cache->dt[ip] * rate_coef);
4879 if (ctl->qnt_m >= 0) {
4880 if (ctl->qnt_mloss_h2o2 >= 0)
4881 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
4882 atm->q[ctl->qnt_m][ip] *= aux;
4883 if (ctl->qnt_loss_rate >= 0)
4884 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4885 }
4886 if (ctl->qnt_vmr >= 0)
4887 atm->q[ctl->qnt_vmr][ip] *= aux;
4888 }
4889}
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:249
#define SO2_CORR_B
Exponent of the high-SO2 correction [1].
Definition: mptrac.h:384
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1493
#define SO2_DISS_K1_REF
First SO2 dissociation constant at CHEM_REF_TEMP [mol/L].
Definition: mptrac.h:429
#define SO2_DISS_K1_TEMP
Temperature dependence of the first SO2 dissociation constant [K].
Definition: mptrac.h:434
#define H2O2_HENRY_TEMP
Temperature dependence of the H2O2 Henry constant [K].
Definition: mptrac.h:374
#define SO2_CORR_A
Scale factor of the high-SO2 correction [1].
Definition: mptrac.h:379
#define H2O2_SO2_RATE_REF
Reference rate for aqueous H2O2-SO2 chemistry [L^2/(mol^2 s)].
Definition: mptrac.h:349
#define H2O2_SO2_RATE_TEMP
Temperature parameter for the aqueous H2O2-SO2 rate [K].
Definition: mptrac.h:354
#define H2O2_HENRY_REF
Henry constant of H2O2 at CHEM_REF_TEMP [mol/(L atm)].
Definition: mptrac.h:369
#define CHEM_REF_TEMP
Reference temperature for chemical equilibrium constants [K].
Definition: mptrac.h:344
#define SO2_HENRY_REF
Henry constant of SO2 at CHEM_REF_TEMP [mol/(L atm)].
Definition: mptrac.h:359
#define SO2_HENRY_TEMP
Temperature dependence of the SO2 Henry constant [K].
Definition: mptrac.h:364
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2679
Here is the call graph for this function:

◆ module_isosurf_init()

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

Initialize the isosurface module based on atmospheric data.

This function initializes the isosurface module based on the atmospheric data provided. It calculates the necessary variables required for generating the isosurface, such as pressure, density, or potential temperature. Additionally, it can read balloon pressure data from a file if specified in the control structure. The initialized data is stored in the cache for later use.

Parameters
ctlPointer to the control structure containing simulation parameters.
met0Pointer to the meteorological data structure at the current time step.
met1Pointer to the meteorological data structure at the next time step.
atmPointer to the atmospheric data structure containing particle information.
cachePointer to the cache structure for storing initialized data.
Author
Lars Hoffmann

Definition at line 4893 of file mptrac.c.

4898 {
4899
4900 double t;
4901
4902 /* Set timer... */
4903 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS");
4904
4905 /* Save pressure... */
4906 if (ctl->isosurf == 1) {
4907 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
4908 cache->iso_var[ip] = atm->p[ip];
4909 }
4910 }
4911
4912 /* Save density... */
4913 else if (ctl->isosurf == 2) {
4914 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4916 INTPOL_3D(t, 1);
4917 cache->iso_var[ip] = atm->p[ip] / t;
4918 }
4919 }
4920
4921 /* Save potential temperature... */
4922 else if (ctl->isosurf == 3) {
4923 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4925 INTPOL_3D(t, 1);
4926 cache->iso_var[ip] = THETA(atm->p[ip], t);
4927 }
4928 }
4929
4930 /* Read balloon pressure data... */
4931 else if (ctl->isosurf == 4) {
4932
4933 /* Write info... */
4934 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
4935
4936 /* Open file... */
4937 FILE *in;
4938 if (!(in = fopen(ctl->balloon, "r")))
4939 ERRMSG("Cannot open file!");
4940
4941 /* Read pressure time series... */
4942 char line[LEN];
4943 while (fgets(line, LEN, in))
4944 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
4945 &(cache->iso_ps[cache->iso_n])) == 2)
4946 if ((++cache->iso_n) > NP)
4947 ERRMSG("Too many data points!");
4948
4949 /* Check number of points... */
4950 if (cache->iso_n < 1)
4951 ERRMSG("Could not read any data!");
4952
4953 /* Close file... */
4954 fclose(in);
4955
4956 /* Update of cache data on device... */
4957 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
4958 }
4959}
void mptrac_update_device(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
Updates device memory for specified data structures.
Definition: mptrac.c:8065
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:568
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3646
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3649
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3643
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3640
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:3033
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:3030
Here is the call graph for this function:

◆ module_isosurf()

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

Apply the isosurface module to adjust atmospheric properties.

This function applies the isosurface module to adjust atmospheric properties based on the initialized data stored in the cache. It interpolates and restores atmospheric pressure, density, or potential temperature according to the specified isosurface mode in the control structure.

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

Definition at line 4963 of file mptrac.c.

4968 {
4969
4970 /* Set timer... */
4971 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS");
4972
4973 /* Loop over particles... */
4974 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
4975
4976 /* Init... */
4977 double t;
4979
4980 /* Restore pressure... */
4981 if (ctl->isosurf == 1)
4982 atm->p[ip] = cache->iso_var[ip];
4983
4984 /* Restore density... */
4985 else if (ctl->isosurf == 2) {
4986 INTPOL_3D(t, 1);
4987 atm->p[ip] = cache->iso_var[ip] * t;
4988 }
4989
4990 /* Restore potential temperature... */
4991 else if (ctl->isosurf == 3) {
4992 INTPOL_3D(t, 1);
4993 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / KAPPA);
4994 }
4995
4996 /* Interpolate pressure... */
4997 else if (ctl->isosurf == 4) {
4998 if (atm->time[ip] <= cache->iso_ts[0])
4999 atm->p[ip] = cache->iso_ps[0];
5000 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
5001 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
5002 else {
5003 const int idx =
5004 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
5005 atm->p[ip] =
5006 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
5007 cache->iso_ps[idx + 1], atm->time[ip]);
5008 }
5009 }
5010 }
5011}
#define KAPPA
Exponent used for potential-temperature calculations [1].
Definition: mptrac.h:324
Here is the call graph for this function:

◆ module_kpp_chem()

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

KPP chemistry module.

Simulate chemical reactions using the Kinetic PreProcessor (KPP) integration scheme.

This function simulates chemical reactions using the Kinetic PreProcessor (KPP) integration scheme for atmospheric particles. It loops over each particle in the atmospheric data structure and integrates chemical reactions over a specified time step using the KPP algorithm.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
climPointer to the climatological data structure.
met0Pointer to the first meteorological data structure.
met1Pointer to the second meteorological data structure.
atmPointer to the atmospheric data structure containing particle information.
Note
The function initializes a timer to measure the execution time of the chemical simulation.
Chemical integration using KPP is performed for particles with a positive time step (dt > 0).
For each particle, the function allocates memory for variable (VAR) and fixed (FIX) arrays, sets the range of time steps (STEPMIN and STEPMAX), and defines relative and absolute tolerances.
The chemical system is initialized for each particle using the kpp_chem_initialize function.
Chemical integration is performed over a specified time step (ctl->dt_kpp) using the INTEGRATE macro, which is part of the KPP integration scheme.
The function outputs the integrated chemical concentrations back to the atmospheric data structure using the kpp_chem_output2atm function.
Memory allocated for the variable (VAR) and fixed (FIX) arrays is freed after the integration is completed for each particle.
Author
Mingzhao Liu

◆ module_meteo()

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

Update atmospheric properties using meteorological data.

This function updates atmospheric properties based on meteorological data interpolated between two time steps. It calculates various atmospheric quantities such as pressure, temperature, wind speed, humidity, etc., and updates the corresponding fields in the atmospheric data structure.

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

Definition at line 5069 of file mptrac.c.

5075 {
5076
5077 /* Set timer... */
5078 SELECT_TIMER("MODULE_METEO", "PHYSICS");
5079
5080 /* Check quantity flags... */
5081 if (ctl->qnt_tsts >= 0)
5082 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
5083 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
5084
5085 /* Loop over particles... */
5086 PARTICLE_LOOP(0, atm->np, 0,
5087 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5088
5089 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
5090 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
5091 o3, lwc, rwc, iwc, swc, cc, z, zt, eta_d = 0, wdot = 0;
5092
5093 /* Interpolate meteo data... */
5095 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
5096
5097 /* Diagnose eta coordinate on native model levels... */
5098 if (ctl->qnt_eta_d >= 0)
5099 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
5100 met1, met1->pl, met1->zetal,
5101 atm->time[ip], atm->p[ip], atm->lon[ip],
5102 atm->lat[ip], &eta_d, ci, cw, 1);
5103
5104 /* Interpolate vertical velocity on native model levels... */
5105 if ((ctl->advect_vert_coord == 1 && ctl->qnt_zeta_dot >= 0)
5106 || (ctl->advect_vert_coord == 3 && ctl->qnt_eta_dot >= 0))
5107 intpol_met_4d_zeta(met0, met0->pl, met0->zeta_dotl,
5108 met1, met1->pl, met1->zeta_dotl,
5109 atm->time[ip], atm->p[ip], atm->lon[ip],
5110 atm->lat[ip], &wdot, ci, cw, 1);
5111
5112 /* Set quantities... */
5113 SET_ATM(qnt_ps, ps);
5114 SET_ATM(qnt_ts, ts);
5115 SET_ATM(qnt_zs, zs);
5116 SET_ATM(qnt_us, us);
5117 SET_ATM(qnt_vs, vs);
5118 SET_ATM(qnt_ess, ess);
5119 SET_ATM(qnt_nss, nss);
5120 SET_ATM(qnt_shf, shf);
5121 SET_ATM(qnt_lsm, lsm);
5122 SET_ATM(qnt_sst, sst);
5123 SET_ATM(qnt_pbl, pbl);
5124 SET_ATM(qnt_pt, pt);
5125 SET_ATM(qnt_tt, tt);
5126 SET_ATM(qnt_zt, zt);
5127 SET_ATM(qnt_h2ot, h2ot);
5128 SET_ATM(qnt_zg, z);
5129 SET_ATM(qnt_p, atm->p[ip]);
5130 SET_ATM(qnt_t, t);
5131 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
5132 SET_ATM(qnt_u, u);
5133 SET_ATM(qnt_v, v);
5134 SET_ATM(qnt_w, w);
5135 SET_ATM(qnt_h2o, h2o);
5136 SET_ATM(qnt_o3, o3);
5137 SET_ATM(qnt_lwc, lwc);
5138 SET_ATM(qnt_rwc, rwc);
5139 SET_ATM(qnt_iwc, iwc);
5140 SET_ATM(qnt_swc, swc);
5141 SET_ATM(qnt_cc, cc);
5142 SET_ATM(qnt_pct, pct);
5143 SET_ATM(qnt_pcb, pcb);
5144 SET_ATM(qnt_cl, cl);
5145 SET_ATM(qnt_plcl, plcl);
5146 SET_ATM(qnt_plfc, plfc);
5147 SET_ATM(qnt_pel, pel);
5148 SET_ATM(qnt_cape, cape);
5149 SET_ATM(qnt_cin, cin);
5150 SET_ATM(qnt_o3c, o3c);
5151 const double lat_ref =
5152 ctl->met_coord_type == 0 ? atm->lat[ip] : ctl->met_utm_ref_lat;
5153 SET_ATM(qnt_hno3,
5154 clim_zm(&clim->hno3, atm->time[ip], lat_ref, atm->p[ip]));
5155 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
5156 atm->lon[ip], atm->lat[ip], atm->p[ip]));
5157 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
5158 lat_ref, atm->p[ip]));
5159 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip], lat_ref, atm->p[ip]));
5160 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip], lat_ref, atm->p[ip]));
5161 SET_ATM(qnt_vh, sqrt(u * u + v * v));
5162 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
5163 SET_ATM(qnt_psat, PSAT(t));
5164 SET_ATM(qnt_psice, PSICE(t));
5165 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
5166 SET_ATM(qnt_sh, SH(h2o));
5167 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
5168 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
5169 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
5170 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
5171 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
5172 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
5173 SET_ATM(qnt_eta_d, eta_d);
5174 if (ctl->advect_vert_coord == 1) {
5175 SET_ATM(qnt_zeta_dot, wdot);
5176 } else if (ctl->advect_vert_coord == 3) {
5177 SET_ATM(qnt_eta_dot, wdot);
5178 }
5179 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
5180 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
5181 SET_ATM(qnt_pv, pv);
5182 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
5183 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
5184 SET_ATM(qnt_tnat,
5185 nat_temperature(atm->p[ip], h2o,
5186 clim_zm(&clim->hno3, atm->time[ip],
5187 atm->lat[ip], atm->p[ip])));
5188 SET_ATM(qnt_tsts,
5189 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
5190 }
5191}
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:8403
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:3324
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1842
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:2110
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1946
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:1277
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1916
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:2085
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1818
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3825
int qnt_eta_d
Quantity array index for diagnosed eta vertical coordinate.
Definition: mptrac.h:2730
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2760
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2733
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2754
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2724
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2757
Here is the call graph for this function:

◆ module_mixing()

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

Update atmospheric properties through interparcel mixing.

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

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

Definition at line 5195 of file mptrac.c.

5199 {
5200
5201 /* Set timer... */
5202 SELECT_TIMER("MODULE_MIXING", "PHYSICS");
5203
5204 /* Allocate... */
5205 const int np = atm->np;
5206 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
5207 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
5208 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
5209 double *restrict const mixparam =
5210 (double *) malloc((size_t) np * sizeof(double));
5211 if (ixs == NULL || iys == NULL || izs == NULL || mixparam == NULL)
5212 ERRMSG("Out of memory!");
5213
5214 /* Set grid box size... */
5215 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
5216 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
5217 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
5218
5219 /* Set time interval... */
5220 const double t0 = t - 0.5 * ctl->dt_mod;
5221 const double t1 = t + 0.5 * ctl->dt_mod;
5222 const double dt_mix = ctl->mixing_dt > 0 ? ctl->mixing_dt : ctl->dt_mod;
5223
5224 /* Get indices... */
5225#ifdef _OPENACC
5226#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np],mixparam[0:np])
5227#pragma acc data present(ctl,clim,atm,ixs,iys,izs,mixparam)
5228#pragma acc parallel loop independent gang vector
5229#else
5230#pragma omp parallel for default(shared)
5231#endif
5232 for (int ip = 0; ip < np; ip++) {
5233 const double zpart = Z(atm->p[ip]);
5234 if (atm->time[ip] < t0 || atm->time[ip] > t1
5235 || atm->lon[ip] < ctl->mixing_lon0
5236 || atm->lon[ip] >= ctl->mixing_lon1
5237 || atm->lat[ip] < ctl->mixing_lat0
5238 || atm->lat[ip] >= ctl->mixing_lat1
5239 || zpart < ctl->mixing_z0 || zpart >= ctl->mixing_z1) {
5240 izs[ip] = -1;
5241 continue;
5242 }
5243 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
5244 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
5245 izs[ip] = (int) ((zpart - ctl->mixing_z0) / dz);
5246 if (ixs[ip] >= ctl->mixing_nx || iys[ip] >= ctl->mixing_ny
5247 || izs[ip] >= ctl->mixing_nz) {
5248 izs[ip] = -1;
5249 continue;
5250 }
5251 const double w = tropo_weight(ctl, clim, atm, ip);
5252 const double rate =
5253 w / ctl->mixing_tau_trop + (1.0 - w) / ctl->mixing_tau_strat;
5254 mixparam[ip] = -expm1(-dt_mix * rate);
5255 }
5256
5257 /* Calculate interparcel mixing... */
5258 const int use_ensemble = (ctl->nens > 0);
5259
5260 const int quantities[] = {
5261 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
5262 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
5263 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
5264 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
5265 ctl->qnt_Csf6, ctl->qnt_aoa, ctl->qnt_Arn222, ctl->qnt_Apb210,
5266 ctl->qnt_Abe7, ctl->qnt_Acs137, ctl->qnt_Ai131, ctl->qnt_Axe133
5267 };
5268 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
5269
5270 for (int i = 0; i < n_qnt; i++)
5271 if (quantities[i] >= 0)
5272 module_mixing_help(ctl, atm, ixs, iys, izs, mixparam, quantities[i],
5273 use_ensemble);
5274
5275 /* Free... */
5276#ifdef _OPENACC
5277#pragma acc exit data delete(ixs,iys,izs,mixparam)
5278#endif
5279 free(ixs);
5280 free(iys);
5281 free(izs);
5282 free(mixparam);
5283}
void module_mixing_help(const ctl_t *ctl, atm_t *atm, const int *ixs, const int *iys, const int *izs, const double *mixparam, const int qnt_idx, const int use_ensemble)
Perform subgrid-scale interparcel mixing of a given quantity.
Definition: mptrac.c:5287
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2775
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:3196
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:3193
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2787
int qnt_Acs137
Quantity array index for radioactive activity of Cs-137.
Definition: mptrac.h:2820
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:3190
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2772
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:3205
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2778
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:3208
int qnt_Ai131
Quantity array index for radioactive activity of I-131.
Definition: mptrac.h:2823
double mixing_tau_trop
E-folding time for interparcel mixing in the troposphere [s].
Definition: mptrac.h:3181
int qnt_Apb210
Quantity array index for radioactive activity of Pb-210.
Definition: mptrac.h:2814
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2781
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:3187
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:3199
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:3211
int qnt_Axe133
Quantity array index for radioactive activity of Xe-133.
Definition: mptrac.h:2826
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2790
int qnt_Abe7
Quantity array index for radioactive activity of Be-7.
Definition: mptrac.h:2817
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:3178
double mixing_tau_strat
E-folding time for interparcel mixing in the stratosphere [s].
Definition: mptrac.h:3184
int qnt_Arn222
Quantity array index for radioactive activity of Rn-222.
Definition: mptrac.h:2811
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2784
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:3202
Here is the call graph for this function:

◆ module_mixing_help()

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

Perform subgrid-scale interparcel mixing of a given quantity.

This function computes the mixing-parameter-weighted mean of a specified quantity within each subgrid box (and optionally for each ensemble member) and applies a mixing adjustment to particle values based on the computed local mean. The weighted mean conserves the sum of the quantity when the mixing parameter varies between particles.

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

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

Definition at line 5287 of file mptrac.c.

5295 {
5296
5297 const int np = atm->np;
5298 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
5299 const int nens = use_ensemble ? ctl->nens : 1;
5300 const int total_grid = ngrid * nens;
5301
5302 double *restrict const cmean =
5303 (double *) malloc((size_t) total_grid * sizeof(double));
5304 double *restrict const cweight =
5305 (double *) malloc((size_t) total_grid * sizeof(double));
5306 if (cmean == NULL || cweight == NULL)
5307 ERRMSG("Out of memory!");
5308
5309 /* Init... */
5310#ifdef _OPENACC
5311#pragma acc enter data create(cmean[0:total_grid],cweight[0:total_grid])
5312#pragma acc data present(ctl,atm,ixs,iys,izs,mixparam,cmean,cweight)
5313#pragma acc parallel loop independent gang vector
5314#else
5315#ifdef __NVCOMPILER
5316#pragma novector
5317#endif
5318#pragma omp parallel for
5319#endif
5320 for (int i = 0; i < total_grid; i++) {
5321 cmean[i] = 0.0;
5322 cweight[i] = 0.0;
5323 }
5324
5325 /* Loop over particles... */
5326#ifdef _OPENACC
5327#pragma acc parallel loop independent gang vector
5328#endif
5329 for (int ip = 0; ip < np; ip++)
5330 if (izs[ip] >= 0) {
5331 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
5332 if (ens < 0 || ens >= nens)
5333 continue;
5334 const int idx =
5335 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
5336 ctl->mixing_nz);
5337#ifdef _OPENACC
5338#pragma acc atomic update
5339#endif
5340 cmean[idx] += mixparam[ip] * atm->q[qnt_idx][ip];
5341#ifdef _OPENACC
5342#pragma acc atomic update
5343#endif
5344 cweight[idx] += mixparam[ip];
5345 }
5346
5347 /* Compute means... */
5348#ifdef _OPENACC
5349#pragma acc parallel loop independent gang vector
5350#else
5351#ifdef __NVCOMPILER
5352#pragma novector
5353#endif
5354#pragma omp parallel for
5355#endif
5356 for (int i = 0; i < total_grid; i++)
5357 if (cweight[i] > 0)
5358 cmean[i] /= cweight[i];
5359
5360 /* Interparcel mixing... */
5361#ifdef _OPENACC
5362#pragma acc parallel loop independent gang vector
5363#else
5364#pragma omp parallel for
5365#endif
5366 for (int ip = 0; ip < np; ip++) {
5367 if (izs[ip] >= 0) {
5368 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
5369
5370 if (ens < 0 || ens >= nens)
5371 continue;
5372 const int idx =
5373 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
5374 ctl->mixing_nz);
5375 atm->q[qnt_idx][ip] +=
5376 (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam[ip];
5377 }
5378 }
5379
5380 /* Free... */
5381#ifdef _OPENACC
5382#pragma acc exit data delete(cmean,cweight)
5383#endif
5384 free(cmean);
5385 free(cweight);
5386}

◆ module_oh_chem()

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

Perform hydroxyl chemistry calculations for atmospheric particles.

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

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

Definition at line 5390 of file mptrac.c.

5396 {
5397
5398 /* Set timer... */
5399 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS");
5400
5401 /* Check quantity flags... */
5402 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5403 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5404
5405 /* Parameter of SO2 correction... */
5406 const double a = 4.71572206e-08;
5407 const double b = -8.28782867e-01;
5408 const double low = pow(1. / a, 1. / b);
5409
5410 /* Loop over particles... */
5411 PARTICLE_LOOP(0, atm->np, 1,
5412 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5413
5414 /* Get temperature... */
5415 double t;
5417 INTPOL_3D(t, 1);
5418
5419 /* Calculate molecular density... */
5420 const double M = MOLEC_DENS(atm->p[ip], t);
5421
5422 /* Use constant reaction rate... */
5423 double k = NAN;
5424 if (ctl->oh_chem_reaction == 1)
5425 k = ctl->oh_chem[0];
5426
5427 /* Calculate bimolecular reaction rate... */
5428 else if (ctl->oh_chem_reaction == 2)
5429 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
5430
5431 /* Calculate termolecular reaction rate... */
5432 if (ctl->oh_chem_reaction == 3) {
5433
5434 /* Calculate rate coefficient for X + OH + M -> XOH + M
5435 (JPL Publication 19-05) ... */
5436 const double k0 =
5437 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
5438 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
5439 const double ki =
5440 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
5441 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
5442 const double c = log10(k0 * M / ki);
5443 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
5444 }
5445
5446 /* Correction factor for high SO2 concentration
5447 (if qnt_Cx is defined, the correction is switched on)... */
5448 double cor = 1;
5449 if (ctl->qnt_Cx >= 0)
5450 cor =
5451 atm->q[ctl->qnt_Cx][ip] >
5452 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
5453
5454 /* Calculate exponential decay... */
5455 const double rate_coef =
5456 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
5457 atm->lat[ip], atm->p[ip]) * M * cor;
5458 const double aux = exp(-cache->dt[ip] * rate_coef);
5459 if (ctl->qnt_m >= 0) {
5460 if (ctl->qnt_mloss_oh >= 0)
5461 atm->q[ctl->qnt_mloss_oh][ip]
5462 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5463 atm->q[ctl->qnt_m][ip] *= aux;
5464 if (ctl->qnt_loss_rate >= 0)
5465 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
5466 }
5467 if (ctl->qnt_vmr >= 0)
5468 atm->q[ctl->qnt_vmr][ip] *= aux;
5469 }
5470}
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:3244
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:3241
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2676
Here is the call graph for this function:

◆ module_position()

void module_position ( const cache_t cache,
met_t met0,
met_t met1,
atm_t atm,
const int  reflect 
)

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.
  • Clamps or reflects pressure at the model top and local surface, as selected by reflect.
Parameters
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the first meteorological data structure.
met1Pointer to the second meteorological data structure.
atmPointer to the atmospheric data structure containing particle information.
reflectSelect reflection (1) or clamping (0) at vertical boundaries.
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.
Author
Lars Hoffmann

Definition at line 5474 of file mptrac.c.

5479 {
5480
5481 /* Set timer... */
5482 SELECT_TIMER("MODULE_POSITION", "PHYSICS");
5483
5484 /* Loop over particles... */
5485 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
5486
5487 /* Init... */
5488 double ps;
5490
5491 if (met0->coord_type == 0) {
5492 /* Calculate modulo... */
5493 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
5494 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
5495
5496 /* Check latitude... */
5497 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
5498 if (atm->lat[ip] > 90) {
5499 atm->lat[ip] = 180 - atm->lat[ip];
5500 atm->lon[ip] += 180;
5501 }
5502 if (atm->lat[ip] < -90) {
5503 atm->lat[ip] = -180 - atm->lat[ip];
5504 atm->lon[ip] += 180;
5505 }
5506 }
5507
5508 /* Check longitude... */
5509 while (atm->lon[ip] < -180)
5510 atm->lon[ip] += 360;
5511 while (atm->lon[ip] >= 180)
5512 atm->lon[ip] -= 360;
5513 } else {
5514 intpol_check_cartesian(met0->lon, met0->nx, met0->lat, met0->ny,
5515 atm->lon[ip], atm->lat[ip], &atm->lon[ip],
5516 &atm->lat[ip]);
5517 }
5518
5519 /* Check pressure... */
5520 const double ptop = met0->p[met0->np - 1];
5521 if (atm->p[ip] < ptop) {
5522 atm->p[ip] = reflect ? ptop * ptop / atm->p[ip] : ptop;
5523 } else if (atm->p[ip] > 300.) {
5524 INTPOL_2D(ps, 1);
5525 if (atm->p[ip] > ps)
5526 atm->p[ip] = reflect ? ps * ps / atm->p[ip] : ps;
5527 }
5528 }
5529}
Here is the call graph for this function:

◆ module_rng_init()

void module_rng_init ( const int  ntask)

Initialize random number generators for parallel tasks.

This function initializes random number generators for parallel tasks using both GSL (GNU Scientific Library) and cuRAND (NVIDIA CUDA Random Number Generation Library) if available. It sets up GSL random number generators for each OpenMP thread and initializes them with unique seeds. For cuRAND, it creates a pseudo-random number generator and sets its seed. The initialization ensures that each task or thread has its own independent random number generator to prevent interference between parallel executions.

Parameters
ntaskThe number of tasks or parallel threads for which random number generators are initialized.
Note
This function must be called before using any random number generation functions to ensure proper initialization of random number generators.
GSL random number generators are initialized for each OpenMP thread, while cuRAND is initialized for the entire task set.
If cuRAND is not available (CURAND macro not defined), the cuRAND initialization section is skipped.
Random number generators are allocated and seeded uniquely for each task or thread to ensure independence and avoid interference between parallel executions.
Author
Lars Hoffmann

Definition at line 5763 of file mptrac.c.

5764 {
5765
5766 /* Initialize GSL random number generators... */
5767 gsl_rng_env_setup();
5768 if (omp_get_max_threads() > NTHREADS)
5769 ERRMSG("Too many threads!");
5770 for (int i = 0; i < NTHREADS; i++) {
5771 rng[i] = gsl_rng_alloc(gsl_rng_default);
5772 gsl_rng_set(rng[i], gsl_rng_default_seed
5773 + (long unsigned) (ntask * NTHREADS + i));
5774 }
5775
5776 /* Initialize cuRAND random number generators... */
5777#ifdef CURAND
5778 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
5779 CURAND_STATUS_SUCCESS)
5780 ERRMSG("Cannot create random number generator!");
5781 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
5782 CURAND_STATUS_SUCCESS)
5783 ERRMSG("Cannot set seed for random number generator!");
5784 if (curandSetStream
5785 (rng_curand,
5786 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
5787 CURAND_STATUS_SUCCESS)
5788 ERRMSG("Cannot set stream for random number generator!");
5789#endif
5790}
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:593

◆ module_rng()

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

Generate random numbers using various methods and distributions.

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

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

Definition at line 5794 of file mptrac.c.

5798 {
5799
5800 /* Use GSL random number generators... */
5801 if (ctl->rng_type == 0) {
5802
5803 /* Uniform distribution... */
5804 if (method == 0) {
5805#pragma omp parallel for default(shared)
5806 for (size_t i = 0; i < n; ++i)
5807 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
5808 }
5809
5810 /* Normal distribution... */
5811 else if (method == 1) {
5812#pragma omp parallel for default(shared)
5813 for (size_t i = 0; i < n; ++i)
5814 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
5815 }
5816
5817 /* Update of random numbers on device... */
5818#ifdef _OPENACC
5819 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
5820#pragma acc update device(rs[:n])
5821#endif
5822 }
5823
5824 /* Use Squares random number generator (Widynski, 2022)... */
5825 else if (ctl->rng_type == 1) {
5826
5827 /* Set key (don't change this!)... */
5828 const uint64_t key = 0xc8e4fd154ce32f6d;
5829
5830 /* Uniform distribution... */
5831#ifdef _OPENACC
5832#pragma acc data present(rs)
5833#pragma acc parallel loop independent gang vector
5834#else
5835#pragma omp parallel for default(shared)
5836#endif
5837 for (size_t i = 0; i < n + 1; ++i) {
5838 uint64_t r, t, x, y, z;
5839 y = x = (rng_ctr + i) * key;
5840 z = y + key;
5841 x = x * x + y;
5842 x = (x >> 32) | (x << 32);
5843 x = x * x + z;
5844 x = (x >> 32) | (x << 32);
5845 x = x * x + y;
5846 x = (x >> 32) | (x << 32);
5847 t = x = x * x + z;
5848 x = (x >> 32) | (x << 32);
5849 r = t ^ ((x * x + y) >> 32);
5850 rs[i] = (double) r / (double) UINT64_MAX;
5851 }
5852 rng_ctr += n + 1;
5853
5854 /* Normal distribution... */
5855 if (method == 1) {
5856#ifdef _OPENACC
5857#pragma acc parallel loop independent gang vector
5858#else
5859#pragma omp parallel for default(shared)
5860#endif
5861 for (size_t i = 0; i < n; i += 2) {
5862 const double r = sqrt(-2.0 * log(rs[i]));
5863 const double phi = 2.0 * M_PI * rs[i + 1];
5864 rs[i] = r * cosf((float) phi);
5865 rs[i + 1] = r * sinf((float) phi);
5866 }
5867 }
5868 }
5869
5870 /* Use cuRAND random number generators... */
5871 else if (ctl->rng_type == 2) {
5872#ifdef CURAND
5873#pragma acc host_data use_device(rs)
5874 {
5875
5876 /* Uniform distribution... */
5877 if (method == 0) {
5878 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
5879 CURAND_STATUS_SUCCESS)
5880 ERRMSG("Cannot create random numbers!");
5881 }
5882
5883 /* Normal distribution... */
5884 else if (method == 1) {
5885 if (curandGenerateNormalDouble
5886 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
5887 1.0) != CURAND_STATUS_SUCCESS)
5888 ERRMSG("Cannot create random numbers!");
5889 }
5890 }
5891#else
5892 ERRMSG("MPTRAC was compiled without cuRAND!");
5893#endif
5894 }
5895}
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:3043

◆ module_radio_decay()

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

Apply radioactive decay to atmospheric tracer species.

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

Implemented isotopes:

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

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

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

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

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

Definition at line 5533 of file mptrac.c.

5536 {
5537
5538 /* Set timer... */
5539 SELECT_TIMER("MODULE_RADIO_DECAY", "PHYSICS");
5540
5541 /* Set decay constants of radioactive species [s^-1]... */
5542 const double lambda_rn222 = log(2.0) / RADIO_HALF_LIFE_RN222;
5543 const double lambda_pb210 = log(2.0) / RADIO_HALF_LIFE_PB210;
5544 const double lambda_be7 = log(2.0) / RADIO_HALF_LIFE_BE7;
5545 const double lambda_cs137 = log(2.0) / RADIO_HALF_LIFE_CS137;
5546 const double lambda_i131 = log(2.0) / RADIO_HALF_LIFE_I131;
5547 const double lambda_xe133 = log(2.0) / RADIO_HALF_LIFE_XE133;
5548
5549 /* Loop over particles... */
5550 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,atm)") {
5551
5552 /* Set timestep... */
5553 const double dt = cache->dt[ip];
5554
5555 /* Loss for Pb-210... */
5556 if (ctl->qnt_Apb210 >= 0)
5557 atm->q[ctl->qnt_Apb210][ip] *= exp(-dt * lambda_pb210);
5558
5559 /* Loss for Rn-222... */
5560 if (ctl->qnt_Arn222 >= 0) {
5561 const double old = atm->q[ctl->qnt_Arn222][ip];
5562 const double aux = exp(-dt * lambda_rn222);
5563 const double lost = old * (1.0 - aux);
5564 atm->q[ctl->qnt_Arn222][ip] = old * aux;
5565
5566 /* Parent-daughter process for Pb-210... */
5567 if (ctl->qnt_Apb210 >= 0)
5568 atm->q[ctl->qnt_Apb210][ip] += lost * lambda_pb210 / lambda_rn222;
5569 }
5570
5571 /* Loss for Be-7... */
5572 if (ctl->qnt_Abe7 >= 0)
5573 atm->q[ctl->qnt_Abe7][ip] *= exp(-dt * lambda_be7);
5574
5575 /* Loss for Cs-137... */
5576 if (ctl->qnt_Acs137 >= 0)
5577 atm->q[ctl->qnt_Acs137][ip] *= exp(-dt * lambda_cs137);
5578
5579 /* Loss for I-131... */
5580 if (ctl->qnt_Ai131 >= 0)
5581 atm->q[ctl->qnt_Ai131][ip] *= exp(-dt * lambda_i131);
5582
5583 /* Loss for Xe-133... */
5584 if (ctl->qnt_Axe133 >= 0)
5585 atm->q[ctl->qnt_Axe133][ip] *= exp(-dt * lambda_xe133);
5586 }
5587}
#define RADIO_HALF_LIFE_CS137
Half-life of Cs-137 [s].
Definition: mptrac.h:479
#define RADIO_HALF_LIFE_I131
Half-life of I-131 [s].
Definition: mptrac.h:484
#define RADIO_HALF_LIFE_BE7
Half-life of Be-7 [s].
Definition: mptrac.h:474
#define RADIO_HALF_LIFE_RN222
Half-life of Rn-222 [s].
Definition: mptrac.h:464
#define RADIO_HALF_LIFE_PB210
Half-life of Pb-210 [s].
Definition: mptrac.h:469
#define RADIO_HALF_LIFE_XE133
Half-life of Xe-133 [s].
Definition: mptrac.h:489

◆ module_radio_depo()

void module_radio_depo ( const ctl_t ctl,
const cache_t cache,
met_t met0,
met_t met1,
atm_t atm,
depo_t depo 
)

Deposit supported radionuclides from air parcels onto the ground grid.

Applies fixed dry-deposition velocities in the surface layer and precipitation-dependent wet scavenging to Apb210, Abe7, Acs137, and Ai131. Air-parcel activities are reduced exponentially and the removed activity is accumulated in depo. When RADIO_DECAY is enabled, ground inventories are referenced to the simulation start for decay-correct output. Backward or zero-length particle timesteps are ignored.

Note
This module requires a latitude/longitude meteorological grid and is not currently supported with domain decomposition (DD).
Parameters
[in]ctlControl parameters, quantity indices, and deposition grid.
[in]cachePer-particle model timesteps.
[in]met0Meteorological field at the earlier bracketing time.
[in]met1Meteorological field at the later bracketing time.
[in,out]atmAir-parcel positions and activities [Bq].
[in,out]depoCumulative ground inventories [Bq per grid cell].

Definition at line 5591 of file mptrac.c.

5597 {
5598
5599 /* Set timer... */
5600 SELECT_TIMER("MODULE_RADIO_DEPO", "PHYSICS");
5601
5602 /* Decay constants of deposited radionuclides [s^-1]... */
5603 const double lambda_pb210 = log(2.0) / RADIO_HALF_LIFE_PB210;
5604 const double lambda_be7 = log(2.0) / RADIO_HALF_LIFE_BE7;
5605 const double lambda_cs137 = log(2.0) / RADIO_HALF_LIFE_CS137;
5606 const double lambda_i131 = log(2.0) / RADIO_HALF_LIFE_I131;
5607
5608 /* Set horizontal grid increments... */
5609 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
5610 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
5611
5612 /* Loop over particles... */
5613 PARTICLE_LOOP(0, atm->np, 1,
5614 "acc data present(ctl,cache,met0,met1,atm,depo)") {
5615
5616 /* Deposition is only defined for forward integration... */
5617 const double dt = cache->dt[ip];
5618 if (dt <= 0)
5619 continue;
5620
5621 /* Get surface pressure... */
5622 double ps;
5624 INTPOL_2D(ps, 1);
5625
5626 /* Calculate dry deposition rate [s^-1]... */
5627 double dry_pb210 = 0, dry_be7 = 0, dry_cs137 = 0, dry_i131 = 0;
5628 if (atm->p[ip] >= ps - ctl->dry_depo_dp) {
5629 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
5630 if (dz > 0) {
5631 dry_pb210 = RADIO_DRY_VDEP_PB210 / dz;
5632 dry_be7 = RADIO_DRY_VDEP_BE7 / dz;
5633 dry_cs137 = RADIO_DRY_VDEP_CS137 / dz;
5634 dry_i131 = RADIO_DRY_VDEP_I131 / dz;
5635 }
5636 }
5637
5638 /* Calculate wet deposition rate [s^-1]... */
5639 double wet_pb210 = 0, wet_be7 = 0, wet_cs137 = 0, wet_i131 = 0;
5640 double pct;
5641 INTPOL_2D(pct, 1);
5642 if (isfinite(pct) && atm->p[ip] > pct) {
5643 double cl;
5644 INTPOL_2D(cl, 0);
5645 if (cl > 0) {
5646 const double Is =
5647 pow(cl / ctl->wet_depo_pre[0], 1. / ctl->wet_depo_pre[1]);
5648 if (Is >= 0.01) {
5649 double lwc, rwc, iwc, swc, t;
5650 INTPOL_3D(lwc, 1);
5651 INTPOL_3D(rwc, 0);
5652 INTPOL_3D(iwc, 0);
5653 INTPOL_3D(swc, 0);
5654 INTPOL_3D(t, 0);
5655 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
5656 double eta;
5657 if (inside) {
5658 if (t > WET_DEPO_T_LIQUID)
5659 eta = 1;
5660 else if (t <= WET_DEPO_T_ICE)
5661 eta = ctl->wet_depo_ic_ret_ratio;
5662 else
5664 ctl->wet_depo_ic_ret_ratio, t);
5665 } else
5666 eta = (t > WET_DEPO_T_LIQUID_BC ? 1 : ctl->wet_depo_bc_ret_ratio);
5667 wet_pb210 = RADIO_WET_COEFF_PB210 * Is * eta;
5668 wet_be7 = RADIO_WET_COEFF_BE7 * Is * eta;
5669 wet_cs137 = RADIO_WET_COEFF_CS137 * Is * eta;
5670 wet_i131 = RADIO_WET_COEFF_I131 * Is * eta;
5671 }
5672 }
5673 }
5674
5675 /* Get deposition grid index... */
5676 const int ingrid =
5677 (atm->lon[ip] >= ctl->grid_lon0
5678 && atm->lon[ip] < ctl->grid_lon1
5679 && atm->lat[ip] >= ctl->grid_lat0 && atm->lat[ip] < ctl->grid_lat1);
5680 const int ix = ingrid
5681 ? (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon) : 0;
5682 const int iy = ingrid
5683 ? (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat) : 0;
5684 const int idx = (ingrid ? ARRAY_2D(ix, iy, ctl->grid_ny) : 0);
5685 const double tref = atm->time[ip] - ctl->t_start;
5686
5687 /* Deposit Pb-210... */
5688 if (ctl->qnt_Apb210 >= 0) {
5689 const double old = atm->q[ctl->qnt_Apb210][ip];
5690 const double aux = exp(-dt * (dry_pb210 + wet_pb210));
5691 const double lost = old * (1. - aux);
5692 const double deposited = lost
5693 * (ctl->radio_decay ? exp(lambda_pb210 * tref) : 1.0);
5694 atm->q[ctl->qnt_Apb210][ip] = old * aux;
5695 if (ingrid && lost > 0) {
5696#ifdef _OPENACC
5697#pragma acc atomic update
5698#else
5699#pragma omp atomic update
5700#endif
5701 depo->Apb210[idx] += deposited;
5702 }
5703 }
5704
5705 /* Deposit Be-7... */
5706 if (ctl->qnt_Abe7 >= 0) {
5707 const double old = atm->q[ctl->qnt_Abe7][ip];
5708 const double aux = exp(-dt * (dry_be7 + wet_be7));
5709 const double lost = old * (1. - aux);
5710 const double deposited = lost
5711 * (ctl->radio_decay ? exp(lambda_be7 * tref) : 1.0);
5712 atm->q[ctl->qnt_Abe7][ip] = old * aux;
5713 if (ingrid && lost > 0) {
5714#ifdef _OPENACC
5715#pragma acc atomic update
5716#else
5717#pragma omp atomic update
5718#endif
5719 depo->Abe7[idx] += deposited;
5720 }
5721 }
5722
5723 /* Deposit Cs-137... */
5724 if (ctl->qnt_Acs137 >= 0) {
5725 const double old = atm->q[ctl->qnt_Acs137][ip];
5726 const double aux = exp(-dt * (dry_cs137 + wet_cs137));
5727 const double lost = old * (1. - aux);
5728 const double deposited = lost
5729 * (ctl->radio_decay ? exp(lambda_cs137 * tref) : 1.0);
5730 atm->q[ctl->qnt_Acs137][ip] = old * aux;
5731 if (ingrid && lost > 0) {
5732#ifdef _OPENACC
5733#pragma acc atomic update
5734#else
5735#pragma omp atomic update
5736#endif
5737 depo->Acs137[idx] += deposited;
5738 }
5739 }
5740
5741 /* Deposit aerosol-bound I-131... */
5742 if (ctl->qnt_Ai131 >= 0) {
5743 const double old = atm->q[ctl->qnt_Ai131][ip];
5744 const double aux = exp(-dt * (dry_i131 + wet_i131));
5745 const double lost = old * (1. - aux);
5746 const double deposited = lost
5747 * (ctl->radio_decay ? exp(lambda_i131 * tref) : 1.0);
5748 atm->q[ctl->qnt_Ai131][ip] = old * aux;
5749 if (ingrid && lost > 0) {
5750#ifdef _OPENACC
5751#pragma acc atomic update
5752#else
5753#pragma omp atomic update
5754#endif
5755 depo->Ai131[idx] += deposited;
5756 }
5757 }
5758 }
5759}
#define RADIO_DRY_VDEP_I131
Dry deposition velocity of aerosol-bound I-131 [m/s].
Definition: mptrac.h:509
#define RADIO_DRY_VDEP_CS137
Dry deposition velocity of Cs-137 [m/s].
Definition: mptrac.h:504
#define RADIO_DRY_VDEP_PB210
Dry deposition velocity of Pb-210 [m/s].
Definition: mptrac.h:494
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:689
#define WET_DEPO_T_ICE
Lower temperature of the ice-cloud retention transition [K].
Definition: mptrac.h:454
#define RADIO_WET_COEFF_BE7
Wet deposition coefficient of Be-7 [s^-1].
Definition: mptrac.h:519
#define RADIO_WET_COEFF_CS137
Wet deposition coefficient of Cs-137 [s^-1].
Definition: mptrac.h:524
#define RADIO_WET_COEFF_I131
Wet deposition coefficient of aerosol-bound I-131 [s^-1].
Definition: mptrac.h:529
#define RADIO_DRY_VDEP_BE7
Dry deposition velocity of Be-7 [m/s].
Definition: mptrac.h:499
#define WET_DEPO_T_LIQUID
Upper temperature of the ice-cloud retention transition [K].
Definition: mptrac.h:449
#define WET_DEPO_T_LIQUID_BC
Temperature threshold for below-cloud retention [K].
Definition: mptrac.h:459
#define RADIO_WET_COEFF_PB210
Wet deposition coefficient of Pb-210 [s^-1].
Definition: mptrac.h:514
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3449
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3461
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3452
int radio_decay
RADIO_DECAY switch for airborne and deposited activity (0=off, 1=on, default: 0).
Definition: mptrac.h:3262
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3455
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:3268
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3458
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:3295
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:3292
double t_start
Start time of simulation [s].
Definition: mptrac.h:2838
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3464
double Ai131[EX *EY]
Deposited I-131 activity [Bq].
Definition: mptrac.h:3685
double Abe7[EX *EY]
Deposited Be-7 activity [Bq].
Definition: mptrac.h:3679
double Acs137[EX *EY]
Deposited Cs-137 activity [Bq].
Definition: mptrac.h:3682
double Apb210[EX *EY]
Deposited Pb-210 activity [Bq].
Definition: mptrac.h:3676

◆ module_sedi()

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

Simulate sedimentation of particles in the atmosphere.

This function calculates the sedimentation velocity of particles based on atmospheric pressure, temperature, and particle properties such as radius and density. It then updates the pressure of each particle based on the sedimentation velocity and the specified time step.

Parameters
ctlPointer to the control structure containing parameters and settings.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the meteorological data at the current time step.
met1Pointer to the meteorological data at the next time step.
atmPointer to the atmospheric data containing particle information.
Note
The sedimentation velocity is calculated using the sedi function, which takes atmospheric pressure, temperature, particle radius, and particle density as inputs.
The pressure change for each particle is calculated based on the sedimentation velocity and the specified time step using the DZ2DP function.
Author
Lars Hoffmann

Definition at line 5899 of file mptrac.c.

5904 {
5905
5906 /* Set timer... */
5907 SELECT_TIMER("MODULE_SEDI", "PHYSICS")
5908 /* Loop over particles... */
5909 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5910
5911 /* Get temperature... */
5912 double t;
5914 INTPOL_3D(t, 1);
5915
5916 /* Sedimentation velocity... */
5917 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
5918 atm->q[ctl->qnt_rhop][ip]);
5919
5920 /* Calculate pressure change... */
5921 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
5922 }
5923}
Here is the call graph for this function:

◆ module_sort()

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

Sort particles according to box index.

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

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

Definition at line 5927 of file mptrac.c.

5930 {
5931
5932 /* Set timer... */
5933 SELECT_TIMER("MODULE_SORT", "PHYSICS");
5934
5935 /* Allocate... */
5936 const int np = atm->np;
5937 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
5938 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
5939 if (a == NULL || p == NULL)
5940 ERRMSG("Out of memory!");
5941
5942#ifdef _OPENACC
5943#pragma acc enter data create(a[0:np],p[0:np])
5944#pragma acc data present(ctl,met0,atm,a,p)
5945#endif
5946
5947 /* Get box index... */
5948#ifdef _OPENACC
5949#pragma acc parallel loop independent gang vector
5950#else
5951#pragma omp parallel for default(shared)
5952#endif
5953 for (int ip = 0; ip < np; ip++) {
5954 a[ip] =
5955 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
5956 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
5957 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
5958 p[ip] = ip;
5959 }
5960
5961 /* Sorting... */
5962#ifdef THRUST
5963#ifdef _OPENACC
5964#pragma acc host_data use_device(a,p)
5965#endif
5966 thrustSortWrapper(a, np, p);
5967#else
5968 size_t *perm_sz = (size_t *) malloc((size_t) np * sizeof(size_t));
5969 if (perm_sz == NULL)
5970 ERRMSG("Out of memory!");
5971#ifdef _OPENACC
5972#pragma acc update self(a[0:np])
5973#endif
5974 gsl_sort_index(perm_sz, a, 1, (size_t) np);
5975 for (int ip = 0; ip < np; ++ip)
5976 p[ip] = (int) perm_sz[ip];
5977 free(perm_sz);
5978#ifdef _OPENACC
5979#pragma acc update device(p[0:np])
5980#endif
5981#endif
5982
5983 /* Sort data... */
5984 module_sort_help(atm->time, p, np);
5985 module_sort_help(atm->p, p, np);
5986 module_sort_help(atm->lon, p, np);
5987 module_sort_help(atm->lat, p, np);
5988 for (int iq = 0; iq < ctl->nq; iq++)
5989 module_sort_help(atm->q[iq], p, np);
5990
5991 /* Free... */
5992#ifdef _OPENACC
5993#pragma acc exit data delete(a,p)
5994#endif
5995 free(a);
5996 free(p);
5997}
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:6001
int nq
Number of quantities.
Definition: mptrac.h:2511
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 6001 of file mptrac.c.

6004 {
6005
6006 /* Allocate... */
6007 double *restrict const help =
6008 (double *) malloc((size_t) np * sizeof(double));
6009 if (help == NULL)
6010 ERRMSG("Out of memory!");
6011
6012 /* Reordering of array... */
6013#ifdef _OPENACC
6014#pragma acc enter data create(help[0:np])
6015#pragma acc data present(a,p,help)
6016#pragma acc parallel loop independent gang vector
6017#else
6018#pragma omp parallel for default(shared)
6019#endif
6020 for (int ip = 0; ip < np; ip++)
6021 help[ip] = a[p[ip]];
6022#ifdef _OPENACC
6023#pragma acc parallel loop independent gang vector
6024#else
6025#pragma omp parallel for default(shared)
6026#endif
6027 for (int ip = 0; ip < np; ip++)
6028 a[ip] = help[ip];
6029
6030 /* Free... */
6031#ifdef _OPENACC
6032#pragma acc exit data delete(help)
6033#endif
6034 free(help);
6035}

◆ module_timesteps()

void module_timesteps ( const ctl_t ctl,
cache_t cache,
const met_t met0,
atm_t atm,
const double  t 
)

Calculate time steps for air parcels based on specified conditions.

This function calculates the time steps for air parcels based on specified conditions, including the direction of simulation, start and stop times, and a given target time. It adjusts the time step for each air parcel accordingly and checks for horizontal boundary conditions of local meteorological data.

Parameters
ctlPointer to the control structure containing simulation parameters.
cachePointer to the cache structure for temporary data and random numbers.
met0Pointer to the initial meteorological data structure.
atmPointer to the atmospheric data structure containing air parcel information.
tThe target time for which time steps are calculated.
Note
The function sets the time step for each air parcel based on its current time relative to the start and stop times of the simulation, as well as the specified target time t.
It also checks for horizontal boundaries of local meteorological data and adjusts the time step accordingly if necessary.
Author
Lars Hoffmann

Definition at line 6039 of file mptrac.c.

6044 {
6045
6046 /* Set timer... */
6047 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS");
6048
6049 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
6050 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
6051
6052 const int local =
6053 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
6054
6055 /* Loop over particles... */
6056 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
6057
6058 /* Set time step for each air parcel... */
6059 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
6060 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
6061 && ctl->direction * (atm->time[ip] - t) < 0))
6062 cache->dt[ip] = t - atm->time[ip];
6063 else
6064 cache->dt[ip] = 0.0;
6065
6066 /* Check horizontal boundaries of local meteo data... */
6067#ifndef DD
6068 int dd = 1;
6069#else
6070 int dd = 0;
6071#endif
6072 if (dd) {
6073 if (local && (atm->lon[ip] <= met0->lon[0]
6074 || atm->lon[ip] >= met0->lon[met0->nx - 1]
6075 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
6076 cache->dt[ip] = 0.0;
6077 } else {
6078 if ((int) atm->q[ctl->qnt_current_subdomain][ip] == -1)
6079 cache->dt[ip] = 0;
6080 }
6081 }
6082}
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2835
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2841
int qnt_current_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2829

◆ module_timesteps_init()

void module_timesteps_init ( ctl_t ctl,
const atm_t atm 
)

Initialize start time and time interval for time-stepping.

This function initializes the start time and time interval for time-stepping based on the direction of simulation and the provided atmospheric data. It sets the start time according to the minimum or maximum time in the atmospheric data, depending on the simulation direction. Additionally, it checks the time interval and adjusts the start time accordingly for rounding purposes.

Parameters
ctlPointer to the control structure containing simulation parameters.
atmPointer to the atmospheric data structure containing air parcel information.
Note
The function sets the start time based on the direction of simulation and the minimum or maximum time in the atmospheric data.
It checks the time interval to ensure that there is a valid time range for simulation and adjusts the start time for rounding purposes.
Author
Lars Hoffmann

Definition at line 6086 of file mptrac.c.

6088 {
6089
6090 /* Set timer... */
6091 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS");
6092
6093 /* Set start time... */
6094 if (ctl->direction == 1) {
6095 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
6096 if (ctl->t_stop > 1e99)
6097 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
6098 } else {
6099 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
6100 if (ctl->t_stop > 1e99)
6101 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
6102 }
6103
6104 /* Check time interval... */
6105 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
6106 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
6107
6108 /* Round start time... */
6109 if (ctl->direction == 1)
6110 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
6111 else
6112 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
6113}

◆ module_tracer_chem()

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

Simulate chemical reactions involving long-lived atmospheric tracers.

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

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

Definition at line 6117 of file mptrac.c.

6123 {
6124
6125 if (ctl->met_coord_type != 0)
6126 ERRMSG("Only lat/lon grid supported");
6127
6128 /* Set timer... */
6129 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS");
6130
6131 /* Loop over particles... */
6132 PARTICLE_LOOP(0, atm->np, 1,
6133 "acc data present(ctl,cache,clim,met0,met1,atm)") {
6134
6135 /* Get temperature... */
6136 double t;
6138 INTPOL_3D(t, 1);
6139
6140 /* Get molecular density... */
6141 const double M = MOLEC_DENS(atm->p[ip], t);
6142
6143 /* Get total column ozone... */
6144 double o3c;
6145 INTPOL_2D(o3c, 1);
6146
6147 /* Get solar zenith angle... */
6148 const double sza =
6149 acos(cos_sza(atm->time[ip], atm->lon[ip], atm->lat[ip]));
6150
6151 /* Get O(1D) volume mixing ratio... */
6152 const double o1d =
6153 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
6154
6155 /* Reactions for CFC-10... */
6156 if (ctl->qnt_Cccl4 >= 0) {
6157 const double K_o1d =
6159 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
6160 atm->p[ip], sza, o3c);
6161 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6162 }
6163
6164 /* Reactions for CFC-11... */
6165 if (ctl->qnt_Cccl3f >= 0) {
6166 const double K_o1d =
6168 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
6169 atm->p[ip], sza, o3c);
6170 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6171 }
6172
6173 /* Reactions for CFC-12... */
6174 if (ctl->qnt_Cccl2f2 >= 0) {
6175 const double K_o1d =
6177 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
6178 atm->p[ip], sza, o3c);
6179 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6180 }
6181
6182 /* Reactions for N2O... */
6183 if (ctl->qnt_Cn2o >= 0) {
6184 const double K_o1d =
6186 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
6187 atm->p[ip], sza, o3c);
6188 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6189 }
6190 }
6191}
double clim_photo(const double rate[CP][CSZA][CO3], const clim_photo_t *photo, const double p, const double sza, const double o3c)
Calculates the photolysis rate for a given set of atmospheric conditions.
Definition: mptrac.c:156
#define O1D_RATE_CFC12_B
O(1D) reaction temperature parameter for CFC-12 [K].
Definition: mptrac.h:414
#define O1D_RATE_N2O_A
O(1D) reaction pre-factor for N2O [cm^3/s].
Definition: mptrac.h:419
#define O1D_RATE_CFC12_A
O(1D) reaction pre-factor for CFC-12 [cm^3/s].
Definition: mptrac.h:409
#define O1D_RATE_N2O_B
O(1D) reaction temperature parameter for N2O [K].
Definition: mptrac.h:424
#define O1D_RATE_CCL4_B
O(1D) reaction temperature parameter for CCl4 [K].
Definition: mptrac.h:394
#define O1D_RATE_CFC11_A
O(1D) reaction pre-factor for CFC-11 [cm^3/s].
Definition: mptrac.h:399
#define O1D_RATE_CCL4_A
O(1D) reaction pre-factor for CCl4 [cm^3/s].
Definition: mptrac.h:389
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:733
#define O1D_RATE_CFC11_B
O(1D) reaction temperature parameter for CFC-11 [K].
Definition: mptrac.h:404
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3726
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3723
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3717
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3720
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3822
Here is the call graph for this function:

◆ module_wet_depo()

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

Perform wet deposition calculations for air parcels.

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

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

Definition at line 6195 of file mptrac.c.

6200 {
6201
6202 /* Set timer... */
6203 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS");
6204
6205 /* Check quantity flags... */
6206 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
6207 ERRMSG("Module needs quantity mass or volume mixing ratio!");
6208
6209 /* Loop over particles... */
6210 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
6211
6212 /* Check whether particle is below cloud top... */
6213 double pct;
6215 INTPOL_2D(pct, 1);
6216 if (!isfinite(pct) || atm->p[ip] <= pct)
6217 continue;
6218
6219 /* Get cloud bottom pressure... */
6220 double pcb;
6221 INTPOL_2D(pcb, 0);
6222
6223 /* Estimate precipitation rate (Pisso et al., 2019)... */
6224 double cl;
6225 INTPOL_2D(cl, 0);
6226 const double Is =
6227 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
6228 if (Is < 0.01)
6229 continue;
6230
6231 /* Check whether particle is inside or below cloud... */
6232 double lwc, rwc, iwc, swc;
6233 INTPOL_3D(lwc, 1);
6234 INTPOL_3D(rwc, 0);
6235 INTPOL_3D(iwc, 0);
6236 INTPOL_3D(swc, 0);
6237 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
6238
6239 /* Get temperature... */
6240 double t;
6241 INTPOL_3D(t, 0);
6242
6243 /* Calculate in-cloud scavenging coefficient... */
6244 double lambda = 0;
6245 if (inside) {
6246
6247 /* Calculate retention factor... */
6248 double eta;
6249 if (t > WET_DEPO_T_LIQUID)
6250 eta = 1;
6251 else if (t <= WET_DEPO_T_ICE)
6252 eta = ctl->wet_depo_ic_ret_ratio;
6253 else
6254 eta =
6256 ctl->wet_depo_ic_ret_ratio, t);
6257
6258 /* Use exponential dependency for particles (Bakels et al., 2024)... */
6259 if (ctl->wet_depo_ic_a > 0)
6260 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
6261
6262 /* Use Henry's law for gases... */
6263 else if (ctl->wet_depo_ic_h[0] > 0) {
6264
6265 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
6266 double h = ctl->wet_depo_ic_h[0]
6267 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / CHEM_REF_TEMP));
6268
6269 /* Use effective Henry's constant for SO2
6270 (Berglen, 2004; Simpson, 2012)... */
6271 if (ctl->wet_depo_so2_ph > 0) {
6272 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
6273 const double K_1 = SO2_DISS_K1_REF
6274 * exp(SO2_DISS_K1_TEMP * (1. / t - 1. / CHEM_REF_TEMP));
6275 const double K_2 = SO2_DISS_K2_REF
6276 * exp(SO2_DISS_K2_TEMP * (1. / t - 1. / CHEM_REF_TEMP));
6277 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
6278 }
6279
6280 /* Estimate depth of cloud layer... */
6281 const double dz = 1e3 * (Z(pct) - Z(pcb));
6282
6283 /* Calculate scavenging coefficient... */
6284 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
6285 }
6286 }
6287
6288 /* Calculate below-cloud scavenging coefficient... */
6289 else {
6290
6291 /* Calculate retention factor... */
6292 double eta;
6293 if (t > WET_DEPO_T_LIQUID_BC)
6294 eta = 1;
6295 else
6296 eta = ctl->wet_depo_bc_ret_ratio;
6297
6298 /* Use exponential dependency for particles (Bakels et al., 2024)... */
6299 if (ctl->wet_depo_bc_a > 0)
6300 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
6301
6302 /* Use Henry's law for gases... */
6303 else if (ctl->wet_depo_bc_h[0] > 0) {
6304
6305 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
6306 const double h = ctl->wet_depo_bc_h[0]
6307 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / CHEM_REF_TEMP));
6308
6309 /* Estimate depth of cloud layer... */
6310 const double dz = 1e3 * (Z(pct) - Z(pcb));
6311
6312 /* Calculate scavenging coefficient... */
6313 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
6314 }
6315 }
6316
6317 /* Calculate exponential decay of mass... */
6318 const double aux = exp(-cache->dt[ip] * lambda);
6319 if (ctl->qnt_m >= 0) {
6320 if (ctl->qnt_mloss_wet >= 0)
6321 atm->q[ctl->qnt_mloss_wet][ip]
6322 += atm->q[ctl->qnt_m][ip] * (1 - aux);
6323 atm->q[ctl->qnt_m][ip] *= aux;
6324 if (ctl->qnt_loss_rate >= 0)
6325 atm->q[ctl->qnt_loss_rate][ip] += lambda;
6326 }
6327 if (ctl->qnt_vmr >= 0)
6328 atm->q[ctl->qnt_vmr][ip] *= aux;
6329 }
6330}
#define SO2_DISS_K2_TEMP
Temperature dependence of the second SO2 dissociation constant [K].
Definition: mptrac.h:444
#define SO2_DISS_K2_REF
Second SO2 dissociation constant at CHEM_REF_TEMP [mol/L].
Definition: mptrac.h:439
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:3277
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:3271
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2685
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:3289
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3286
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3283
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:3280
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:3274

◆ mptrac_alloc()

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

Allocates and initializes memory resources for MPTRAC.

This function handles memory allocation for various data structures and sets up GPU resources if available. It also creates the necessary data regions on GPUs for OpenACC-enabled execution. Each output parameter is optional; pass NULL for structures that are not needed.

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

Definition at line 6334 of file mptrac.c.

6342 {
6343
6344 /* Initialize GPU... */
6345#ifdef _OPENACC
6346 if (ctl != NULL || cache != NULL || clim != NULL || met0 != NULL
6347 || met1 != NULL || atm != NULL || depo != NULL || dd != NULL) {
6348 SELECT_TIMER("ACC_INIT", "INIT");
6349 if (acc_get_num_devices(acc_device_nvidia) <= 0)
6350 ERRMSG("Not running on a GPU device!");
6351 acc_device_t device_type = acc_get_device_type();
6352 acc_init(device_type);
6353 }
6354#endif
6355
6356 /* Allocate... */
6357 SELECT_TIMER("ALLOC", "MEMORY");
6358 if (ctl != NULL)
6359 ALLOC(*ctl, ctl_t, 1);
6360 if (cache != NULL)
6361 ALLOC(*cache, cache_t, 1);
6362 if (clim != NULL)
6363 ALLOC(*clim, clim_t, 1);
6364 if (met0 != NULL)
6365 ALLOC(*met0, met_t, 1);
6366 if (met1 != NULL)
6367 ALLOC(*met1, met_t, 1);
6368 if (atm != NULL)
6369 ALLOC(*atm, atm_t, 1);
6370 if (depo != NULL)
6371 ALLOC(*depo, depo_t, 1);
6372 if (dd != NULL)
6373 ALLOC(*dd, dd_t, 1);
6374
6375 /* Create data region on GPU... */
6376#ifdef _OPENACC
6377 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY");
6378 if (ctl != NULL) {
6379 ctl_t *ctlup = *ctl;
6380#pragma acc enter data create(ctlup[:1])
6381 }
6382 if (cache != NULL) {
6383 cache_t *cacheup = *cache;
6384#pragma acc enter data create(cacheup[:1])
6385 }
6386 if (clim != NULL) {
6387 clim_t *climup = *clim;
6388#pragma acc enter data create(climup[:1])
6389 }
6390 if (met0 != NULL) {
6391 met_t *met0up = *met0;
6392#pragma acc enter data create(met0up[:1])
6393 }
6394 if (met1 != NULL) {
6395 met_t *met1up = *met1;
6396#pragma acc enter data create(met1up[:1])
6397 }
6398 if (atm != NULL) {
6399 atm_t *atmup = *atm;
6400#pragma acc enter data create(atmup[:1])
6401 }
6402 if (depo != NULL) {
6403 depo_t *depoup = *depo;
6404#pragma acc enter data create(depoup[:1])
6405 }
6406#ifdef DD
6407 if (dd != NULL) {
6408 dd_t *ddup = *dd;
6409#pragma acc enter data create(ddup[:1])
6410 }
6411#endif
6412#endif
6413}
Air parcel data.
Definition: mptrac.h:3582
Cache data structure.
Definition: mptrac.h:3637
Climatological data.
Definition: mptrac.h:3804
Control parameters.
Definition: mptrac.h:2504
Domain decomposition data structure.
Definition: mptrac.h:4040
Ground inventories of deposited radionuclides.
Definition: mptrac.h:3673
Meteo data structure.
Definition: mptrac.h:3863

◆ mptrac_free()

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

Frees memory resources allocated for MPTRAC.

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

Parameters
[in]ctlPointer to the control structure (ctl_t) to be freed.
[in]cachePointer to the cache structure (cache_t) to be freed.
[in]climPointer to the climatology structure (clim_t) to be freed.
[in]met0Pointer to the first meteorology structure (met_t) to be freed.
[in]met1Pointer to the second meteorology structure (met_t) to be freed.
[in]atmPointer to the atmospheric structure (atm_t) to be freed.
[in]depoPointer to the radionuclide ground-inventory structure (depo_t) to be freed.
[in]ddPointer to an dd_t structure containing MPI information, including rank and neighbours.
Note
This function uses OpenACC for GPU memory management. If OpenACC is not enabled, the GPU-specific code is ignored.
Precondition
Non-NULL input pointers must have been returned through the corresponding argument of mptrac_alloc().
Postcondition
All input pointers are freed, and the associated data regions on GPUs are deleted if OpenACC is enabled.
Warning
Ensure that the input pointers are not used after calling this function as they will be invalidated.
Author
Lars Hoffmann

Definition at line 6417 of file mptrac.c.

6425 {
6426
6427 /* Delete data region on GPU... */
6428#ifdef _OPENACC
6429 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY");
6430 if (ctl != NULL) {
6431#pragma acc exit data delete(ctl[:1])
6432 }
6433 if (cache != NULL) {
6434#pragma acc exit data delete(cache[:1])
6435 }
6436 if (clim != NULL) {
6437#pragma acc exit data delete(clim[:1])
6438 }
6439 if (met0 != NULL) {
6440#pragma acc exit data delete(met0[:1])
6441 }
6442 if (met1 != NULL) {
6443#pragma acc exit data delete(met1[:1])
6444 }
6445 if (atm != NULL) {
6446#pragma acc exit data delete(atm[:1])
6447 }
6448 if (depo != NULL) {
6449#pragma acc exit data delete(depo[:1])
6450 }
6451#ifdef DD
6452 if (dd != NULL) {
6453#pragma acc exit data delete(dd[:1])
6454 }
6455#endif
6456#endif
6457
6458 /* Free... */
6459 SELECT_TIMER("FREE", "MEMORY");
6460 free(atm);
6461 free(depo);
6462 free(ctl);
6463 free(cache);
6464 free(clim);
6465 free(met0);
6466 free(met1);
6467
6468 /* Free MPI datatype... */
6469#ifdef DD
6470 if (dd != NULL)
6471 MPI_Type_free(&dd->MPI_Particle);
6472#endif
6473 free(dd);
6474}

◆ mptrac_get_met()

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

Retrieves meteorological data for the specified time.

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

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

The function performs the following steps:

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

Definition at line 6478 of file mptrac.c.

6484 {
6485
6486 static int init;
6487
6488 met_t *mets;
6489
6490 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
6491
6492 /* Set timer... */
6493 SELECT_TIMER("GET_MET", "INPUT");
6494
6495 /* Init... */
6496 if (t == ctl->t_start || !init) {
6497 init = 1;
6498
6499 /* Read meteo data... */
6500 get_met_filename(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
6501 ctl->metbase, ctl->dt_met, filename);
6502 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
6503 ERRMSG("Cannot open file!");
6504
6505 get_met_filename(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
6506 ctl->metbase, ctl->dt_met, filename);
6507 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
6508 ERRMSG("Cannot open file!");
6509
6510 /* Update GPU... */
6511 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
6512 SELECT_TIMER("GET_MET", "INPUT");
6513
6514 /* Caching... */
6515 if (ctl->met_cache && t != ctl->t_stop) {
6516 get_met_filename(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
6517 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
6518 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6519 LOG(1, "Caching: %s", cachefile);
6520 if (system(cmd) != 0)
6521 WARN("Caching command failed!");
6522 }
6523 }
6524
6525 /* Read new data for forward trajectories... */
6526 if (t > (*met1)->time) {
6527
6528 /* Pointer swap... */
6529 mets = *met1;
6530 *met1 = *met0;
6531 *met0 = mets;
6532
6533 /* Read new meteo data... */
6534 get_met_filename(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
6535 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
6536 ERRMSG("Cannot open file!");
6537
6538 /* Update GPU... */
6539 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
6540 SELECT_TIMER("GET_MET", "INPUT");
6541
6542 /* Caching... */
6543 if (ctl->met_cache && t != ctl->t_stop) {
6544 get_met_filename(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
6545 cachefile);
6546 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6547 LOG(1, "Caching: %s", cachefile);
6548 if (system(cmd) != 0)
6549 WARN("Caching command failed!");
6550 }
6551 }
6552
6553 /* Read new data for backward trajectories... */
6554 if (t < (*met0)->time) {
6555
6556 /* Pointer swap... */
6557 mets = *met1;
6558 *met1 = *met0;
6559 *met0 = mets;
6560
6561 /* Read new meteo data... */
6562 get_met_filename(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
6563 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
6564 ERRMSG("Cannot open file!");
6565
6566 /* Update GPU... */
6567 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
6568 SELECT_TIMER("GET_MET", "INPUT");
6569
6570 /* Caching... */
6571 if (ctl->met_cache && t != ctl->t_stop) {
6572 get_met_filename(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
6573 cachefile);
6574 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6575 LOG(1, "Caching: %s", cachefile);
6576 if (system(cmd) != 0)
6577 WARN("Caching command failed!");
6578 }
6579 }
6580
6581 if ((*met0)->coord_type != (*met1)->coord_type)
6582 ERRMSG("Coordinate types do not match!");
6583
6584 /* Check that grids are consistent... */
6585 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
6586 if ((*met0)->nx != (*met1)->nx
6587 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
6588 ERRMSG("Meteo grid dimensions do not match!");
6589 for (int ix = 0; ix < (*met0)->nx; ix++)
6590 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
6591 ERRMSG("Meteo grid longitudes do not match!");
6592 for (int iy = 0; iy < (*met0)->ny; iy++)
6593 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
6594 ERRMSG("Meteo grid latitudes do not match!");
6595 for (int ip = 0; ip < (*met0)->np; ip++)
6596 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
6597 ERRMSG("Meteo grid pressure levels do not match!");
6598 }
6599}
void get_met_filename(const ctl_t *ctl, const double t, const int direct, const char *metbase, const double dt_met, char *filename)
Generates a formatted filename for meteorological data files based on the input parameters.
Definition: mptrac.c:2619
int mptrac_read_met(const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met, dd_t *dd)
Reads meteorological data from a file, supporting multiple formats and MPI broadcasting.
Definition: mptrac.c:7802
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:3016
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2851
Here is the call graph for this function:

◆ mptrac_init()

void mptrac_init ( ctl_t ctl,
cache_t cache,
clim_t clim,
atm_t atm,
depo_t depo,
const int  ntask 
)

Initializes the MPTRAC model and its associated components.

This function sets up the necessary components and subsystems for the MPTRAC module, including timesteps, random number generation, and GPU memory updates.

Parameters
ctlPointer to the control structure containing configuration and state information.
cachePointer to the cache structure used for data storage and retrieval.
climPointer to the climatology structure containing climate-related data.
atmPointer to the atmospheric structure containing atmospheric state data.
depoPointer to inventories allocated and zero-initialized by mptrac_alloc().
ntaskNumber of tasks or threads to initialize for the random number generator.

The function performs the following operations:

  • Initializes the timesteps using the module_timesteps_init function.
  • Initializes the random number generator using the module_rng_init function.
  • Updates GPU memory using the mptrac_update_device function.
Author
Lars Hoffmann

Definition at line 6603 of file mptrac.c.

6609 {
6610
6611 /* Initialize timesteps... */
6612 module_timesteps_init(ctl, atm);
6613
6614 /* Initialize random number generator... */
6615 module_rng_init(ntask);
6616
6617 /* Update GPU memory... */
6618 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
6619#ifdef _OPENACC
6620#pragma acc update device(depo[:1])
6621#else
6622 (void) depo;
6623#endif
6624}
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:6086
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:5763
Here is the call graph for this function:

◆ mptrac_read_atm()

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

Reads air parcel data from a specified file into the given atmospheric structure.

This function reads air parcel data from a file and populates the provided atm_t structure based on the type of data specified in the ctl_t control structure. It supports various data formats including ASCII, binary, netCDF, and CLaMS.

Parameters
filenameThe name of the file containing the atmospheric data.
ctlA pointer to the control structure (ctl_t) that specifies the type of data.
atmA pointer to the atmospheric structure (atm_t) that will be populated with the data.
Returns
Returns 1 on success, and 0 on failure.

This function performs the following steps:

  • Sets a timer for performance measurement.
  • Initializes the atmospheric structure.
  • Logs the file being read.
  • Reads data from the file based on the specified type (ctl->atm_type):
    • 0 for ASCII data
    • 1 for binary data
    • 2 for netCDF data
    • 3 or 4 for CLaMS data
  • Handles errors if the data type is not supported.
  • Checks the result of the data reading function and ensures data was read successfully.
  • Logs information about the number of air parcels and the ranges of various parameters (time, altitude, pressure, longitude, latitude, and other quantities).

The function utilizes several helper functions and macros:

  • SELECT_TIMER for setting the timer.
  • LOG for logging information.
  • ERRMSG for handling error messages.
  • gsl_stats_minmax for calculating minimum and maximum values.
  • Z for converting altitude.
Author
Lars Hoffmann

Definition at line 6628 of file mptrac.c.

6631 {
6632
6633 int result;
6634
6635 /* Set timer... */
6636 SELECT_TIMER("READ_ATM", "INPUT");
6637
6638 /* Init... */
6639 atm->np = 0;
6640
6641 /* Write info... */
6642 LOG(1, "Read atmospheric data: %s", filename);
6643
6644 /* Read ASCII data... */
6645 if (ctl->atm_type == 0)
6646 result = read_atm_asc(filename, ctl, atm);
6647
6648 /* Read binary data... */
6649 else if (ctl->atm_type == 1)
6650 result = read_atm_bin(filename, ctl, atm);
6651
6652 /* Read netCDF data... */
6653 else if (ctl->atm_type == 2)
6654 result = read_atm_nc(filename, ctl, atm);
6655
6656 /* Read CLaMS data... */
6657 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
6658 result = read_atm_clams(filename, ctl, atm);
6659
6660 /* Error... */
6661 else
6662 ERRMSG("Atmospheric data type not supported!");
6663
6664 /* Check result... */
6665 if (result != 1)
6666 return 0;
6667
6668 /* Check number of air parcels... */
6669 if (atm->np < 1)
6670 ERRMSG("Can not read any data!");
6671
6672 /* Write info... */
6673 double mini, maxi;
6674 LOG(2, "Number of particles: %d", atm->np);
6675 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6676 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6677 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6678 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6679 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6680 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6681 LOG(2, "%s range: %g ... %g %s",
6682 ctl->met_coord_type == 0 ? "Longitude" : "X coordinate", mini, maxi,
6683 ctl->met_coord_type == 0 ? "deg" : "m");
6684 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6685 LOG(2, "%s range: %g ... %g %s",
6686 ctl->met_coord_type == 0 ? "Latitude" : "Y coordinate", mini, maxi,
6687 ctl->met_coord_type == 0 ? "deg" : "m");
6688 for (int iq = 0; iq < ctl->nq; iq++) {
6689 char msg[5 * LEN];
6690 sprintf(msg, "Quantity %s range: %s ... %s %s",
6691 ctl->qnt_name[iq], ctl->qnt_format[iq],
6692 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6693 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6694 LOG(2, msg, mini, maxi);
6695 }
6696
6697 /* Return success... */
6698 return 1;
6699}
int read_atm_nc(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a generic netCDF file and populates the given atmospheric structure.
Definition: mptrac.c:8610
int read_atm_bin(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a binary file and populates the given atmospheric structure.
Definition: mptrac.c:8491
int read_atm_clams(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads atmospheric data from a CLAMS NetCDF file.
Definition: mptrac.c:8547
int read_atm_asc(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from an ASCII file and populates the given atmospheric structure.
Definition: mptrac.c:8449
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2523
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3339
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2520
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2514
Here is the call graph for this function:

◆ mptrac_read_clim()

void mptrac_read_clim ( const ctl_t ctl,
clim_t clim 
)

Reads various climatological data and populates the given climatology structure.

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

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

This function performs the following steps:

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

The function utilizes several helper functions:

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

Definition at line 6703 of file mptrac.c.

6705 {
6706
6707 /* Set timer... */
6708 SELECT_TIMER("READ_CLIM", "INPUT");
6709
6710 /* Init tropopause climatology... */
6711 clim_tropo_init(clim);
6712
6713 /* Read photolysis rates... */
6714 if (ctl->clim_photo[0] != '-')
6715 read_clim_photo(ctl->clim_photo, &clim->photo);
6716
6717 /* Read HNO3 climatology... */
6718 if (ctl->clim_hno3_filename[0] != '-')
6719 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
6720
6721 /* Read OH climatology... */
6722 if (ctl->clim_oh_filename[0] != '-') {
6723 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
6724 if (ctl->oh_chem_beta > 0)
6725 clim_oh_diurnal_correction(ctl, clim);
6726 }
6727
6728 /* Read H2O2 climatology... */
6729 if (ctl->clim_h2o2_filename[0] != '-')
6730 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
6731
6732 /* Read HO2 climatology... */
6733 if (ctl->clim_ho2_filename[0] != '-')
6734 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
6735
6736 /* Read O(1D) climatology... */
6737 if (ctl->clim_o1d_filename[0] != '-')
6738 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
6739
6740 /* Read CFC-10 time series... */
6741 if (ctl->clim_ccl4_timeseries[0] != '-')
6743
6744 /* Read CFC-11 time series... */
6745 if (ctl->clim_ccl3f_timeseries[0] != '-')
6747
6748 /* Read CFC-12 time series... */
6749 if (ctl->clim_ccl2f2_timeseries[0] != '-')
6751
6752 /* Read N2O time series... */
6753 if (ctl->clim_n2o_timeseries[0] != '-')
6754 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
6755
6756 /* Read SF6 time series... */
6757 if (ctl->clim_sf6_timeseries[0] != '-')
6758 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
6759}
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:8643
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:8762
void read_clim_zm(const char *filename, const char *varname, clim_zm_t *zm)
Reads zonally averaged climatological data from a netCDF file and populates the given structure.
Definition: mptrac.c:8816
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:241
void clim_oh_diurnal_correction(const ctl_t *ctl, clim_t *clim)
Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data.
Definition: mptrac.c:124
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:3154
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:3157
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:3142
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:3151
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:3148
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:3145
Here is the call graph for this function:

◆ mptrac_read_ctl()

void mptrac_read_ctl ( const char *  filename,
int  argc,
char *  argv[],
ctl_t ctl 
)

Reads control parameters from a configuration file and populates the given structure.

This function reads control parameters from a specified configuration file and command line arguments, populating the provided ctl_t structure with the parsed data. It handles a wide range of parameters, performing necessary checks and providing default values where applicable.

Parameters
filenameA string containing the path to the configuration file.
argcAn integer representing the number of command line arguments.
argvAn array of strings containing the command line arguments.
ctlA pointer to the structure (ctl_t) that will be populated with the control parameters.

The function performs the following steps:

  • Sets a timer for reading the control file.
  • Logs information about the MPTRAC executable version and compilation details.
  • Initializes quantity indices.
  • Reads and sets various control parameters such as quantities, vertical coordinates, time steps, meteorological data, sorting options, isosurface parameters, random number generator type, advection parameters, diffusion parameters, convection parameters, boundary conditions, species parameters, molar mass, OH chemistry parameters, H2O2 chemistry parameters, KPP chemistry parameters, first order tracer chemistry parameters, wet deposition parameters, dry deposition parameters, climatological data paths, mixing parameters, chemistry grid parameters, exponential decay parameters, PSC analysis parameters, output parameters for atmospheric data, CSI data, ensemble data, grid data, profile data, sample data, station data, and VTK data.
Author
Lars Hoffmann

Definition at line 6763 of file mptrac.c.

6767 {
6768
6769 /* Set timer... */
6770 SELECT_TIMER("READ_CTL", "INPUT");
6771
6772 /* Write info... */
6773 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
6774 "(executable: %s | version: %s | compiled: %s, %s)\n",
6775 argv[0], VERSION, __DATE__, __TIME__);
6776
6777 /* Initialize quantity indices... */
6778 ctl->qnt_idx = -1;
6779 ctl->qnt_ens = -1;
6780 ctl->qnt_stat = -1;
6781 ctl->qnt_m = -1;
6782 ctl->qnt_vmr = -1;
6783 ctl->qnt_rp = -1;
6784 ctl->qnt_rhop = -1;
6785 ctl->qnt_ps = -1;
6786 ctl->qnt_ts = -1;
6787 ctl->qnt_zs = -1;
6788 ctl->qnt_us = -1;
6789 ctl->qnt_vs = -1;
6790 ctl->qnt_ess = -1;
6791 ctl->qnt_nss = -1;
6792 ctl->qnt_shf = -1;
6793 ctl->qnt_lsm = -1;
6794 ctl->qnt_sst = -1;
6795 ctl->qnt_pbl = -1;
6796 ctl->qnt_pt = -1;
6797 ctl->qnt_tt = -1;
6798 ctl->qnt_zt = -1;
6799 ctl->qnt_h2ot = -1;
6800 ctl->qnt_zg = -1;
6801 ctl->qnt_p = -1;
6802 ctl->qnt_t = -1;
6803 ctl->qnt_rho = -1;
6804 ctl->qnt_u = -1;
6805 ctl->qnt_v = -1;
6806 ctl->qnt_w = -1;
6807 ctl->qnt_h2o = -1;
6808 ctl->qnt_o3 = -1;
6809 ctl->qnt_lwc = -1;
6810 ctl->qnt_rwc = -1;
6811 ctl->qnt_iwc = -1;
6812 ctl->qnt_swc = -1;
6813 ctl->qnt_cc = -1;
6814 ctl->qnt_pct = -1;
6815 ctl->qnt_pcb = -1;
6816 ctl->qnt_cl = -1;
6817 ctl->qnt_plcl = -1;
6818 ctl->qnt_plfc = -1;
6819 ctl->qnt_pel = -1;
6820 ctl->qnt_cape = -1;
6821 ctl->qnt_cin = -1;
6822 ctl->qnt_o3c = -1;
6823 ctl->qnt_hno3 = -1;
6824 ctl->qnt_oh = -1;
6825 ctl->qnt_h2o2 = -1;
6826 ctl->qnt_ho2 = -1;
6827 ctl->qnt_o1d = -1;
6828 ctl->qnt_mloss_oh = -1;
6829 ctl->qnt_mloss_h2o2 = -1;
6830 ctl->qnt_mloss_kpp = -1;
6831 ctl->qnt_mloss_wet = -1;
6832 ctl->qnt_mloss_dry = -1;
6833 ctl->qnt_mloss_decay = -1;
6834 ctl->qnt_loss_rate = -1;
6835 ctl->qnt_psat = -1;
6836 ctl->qnt_psice = -1;
6837 ctl->qnt_pw = -1;
6838 ctl->qnt_sh = -1;
6839 ctl->qnt_rh = -1;
6840 ctl->qnt_rhice = -1;
6841 ctl->qnt_theta = -1;
6842 ctl->qnt_zeta = -1;
6843 ctl->qnt_zeta_d = -1;
6844 ctl->qnt_zeta_dot = -1;
6845 ctl->qnt_eta = -1;
6846 ctl->qnt_eta_d = -1;
6847 ctl->qnt_eta_dot = -1;
6848 ctl->qnt_tvirt = -1;
6849 ctl->qnt_lapse = -1;
6850 ctl->qnt_vh = -1;
6851 ctl->qnt_vz = -1;
6852 ctl->qnt_pv = -1;
6853 ctl->qnt_tdew = -1;
6854 ctl->qnt_tice = -1;
6855 ctl->qnt_tsts = -1;
6856 ctl->qnt_tnat = -1;
6857 ctl->qnt_Cx = -1;
6858 ctl->qnt_Ch2o = -1;
6859 ctl->qnt_Co3 = -1;
6860 ctl->qnt_Cco = -1;
6861 ctl->qnt_Coh = -1;
6862 ctl->qnt_Ch = -1;
6863 ctl->qnt_Cho2 = -1;
6864 ctl->qnt_Ch2o2 = -1;
6865 ctl->qnt_Co1d = -1;
6866 ctl->qnt_Co3p = -1;
6867 ctl->qnt_Cccl4 = -1;
6868 ctl->qnt_Cccl3f = -1;
6869 ctl->qnt_Cccl2f2 = -1;
6870 ctl->qnt_Cn2o = -1;
6871 ctl->qnt_Csf6 = -1;
6872 ctl->qnt_aoa = -1;
6873 ctl->qnt_Arn222 = -1;
6874 ctl->qnt_Apb210 = -1;
6875 ctl->qnt_Abe7 = -1;
6876 ctl->qnt_Acs137 = -1;
6877 ctl->qnt_Ai131 = -1;
6878 ctl->qnt_Axe133 = -1;
6879 ctl->qnt_current_subdomain = -1;
6880 ctl->qnt_target_subdomain = -1;
6881
6882 /* Read quantities... */
6883 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
6884 if (ctl->nq > NQ)
6885 ERRMSG("Too many quantities!");
6886 for (int iq = 0; iq < ctl->nq; iq++) {
6887
6888 /* Read quantity name and format... */
6889 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
6890 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
6891 ctl->qnt_longname[iq]);
6892 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
6893 ctl->qnt_format[iq]);
6894 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
6895 sprintf(ctl->qnt_format[iq], "%%.2f");
6896
6897 /* Try to identify quantity... */
6898 SET_QNT(qnt_idx, "idx", "particle index", "-")
6899 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
6900 SET_QNT(qnt_stat, "stat", "station flag", "-")
6901 SET_QNT(qnt_m, "m", "mass", "kg")
6902 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
6903 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
6904 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
6905 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
6906 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
6907 SET_QNT(qnt_zs, "zs", "surface height", "km")
6908 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
6909 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
6910 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
6911 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
6912 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
6913 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
6914 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
6915 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
6916 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
6917 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
6918 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
6919 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
6920 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
6921 SET_QNT(qnt_p, "p", "pressure", "hPa")
6922 SET_QNT(qnt_t, "t", "temperature", "K")
6923 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
6924 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
6925 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
6926 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
6927 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
6928 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
6929 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
6930 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
6931 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
6932 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
6933 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
6934 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
6935 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
6936 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
6937 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
6938 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
6939 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
6940 SET_QNT(qnt_cape, "cape", "convective available potential energy",
6941 "J/kg")
6942 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
6943 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
6944 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
6945 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
6946 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
6947 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
6948 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
6949 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
6950 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
6951 "mass loss due to H2O2 chemistry", "kg")
6952 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
6953 "kg")
6954 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
6955 "kg")
6956 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
6957 "kg")
6958 SET_QNT(qnt_mloss_decay, "mloss_decay",
6959 "mass loss due to exponential decay", "kg")
6960 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
6961 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
6962 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
6963 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
6964 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
6965 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
6966 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
6967 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
6968 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
6969 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
6970 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
6971 "K/day")
6972 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
6973 SET_QNT(qnt_eta_d, "eta_d", "diagnosed eta coordinate", "1")
6974 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
6975 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
6976 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
6977 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
6978 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
6979 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
6980 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
6981 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
6982 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
6983 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
6984 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
6985 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
6986 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
6987 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
6988 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
6989 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
6990 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
6991 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
6992 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
6993 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
6994 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
6995 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
6996 "ppv")
6997 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
6998 "ppv")
6999 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
7000 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
7001 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
7002 SET_QNT(qnt_Arn222, "Arn222", "Rn-222 activity", "Bq")
7003 SET_QNT(qnt_Apb210, "Apb210", "Pb-210 activity", "Bq")
7004 SET_QNT(qnt_Abe7, "Abe7", "Be-7 activity", "Bq")
7005 SET_QNT(qnt_Acs137, "Acs137", "Cs-137 activity", "Bq")
7006 SET_QNT(qnt_Ai131, "Ai131", "I-131 activity", "Bq")
7007 SET_QNT(qnt_Axe133, "Axe133", "Xe-133 activity", "Bq")
7008 SET_QNT(qnt_current_subdomain, "current_subdomain",
7009 "current subdomain rank", "-")
7010 SET_QNT(qnt_target_subdomain, "target_subdomain",
7011 "target subdomain rank", "-")
7012 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
7013 }
7014
7015 ctl->met_coord_type =
7016 (int) scan_ctl(filename, argc, argv, "MET_COORD_TYPE", -1, "0", NULL);
7017 if (ctl->met_coord_type < 0 || ctl->met_coord_type > 1)
7018 ERRMSG("MET_COORD_TYPE must be 0 or 1!");
7019 ctl->met_utm_ref_lat = 0.0;
7020 ctl->met_utm_ref_lon = 0.0;
7021 if (ctl->met_coord_type == 1) {
7022 ctl->met_utm_ref_lat =
7023 scan_ctl(filename, argc, argv, "MET_UTM_REF_LAT", -1, "", NULL);
7024 ctl->met_utm_ref_lon =
7025 scan_ctl(filename, argc, argv, "MET_UTM_REF_LON", -1, "", NULL);
7026 }
7027
7028 /* Vertical coordinate and velocity... */
7029 ctl->advect_vert_coord =
7030 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
7031 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
7032 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
7033
7034 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
7035 ERRMSG("Add quantity zeta for diabatic advection!");
7036 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
7037 ERRMSG("Add quantity eta for etadot avection!");
7038
7039 ctl->met_vert_coord =
7040 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
7041 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
7042 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
7043 if (ctl->qnt_eta_d >= 0
7044 && ctl->met_vert_coord != 2 && ctl->met_vert_coord != 3)
7045 ERRMSG("Quantity eta_d requires full-level A and B coefficients!");
7046
7047 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
7048 ERRMSG
7049 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
7050 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
7051 ERRMSG
7052 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
7053
7054 ctl->met_gp2z =
7055 (int) scan_ctl(filename, argc, argv, "MET_GP2Z", -1, "0", NULL);
7056 if (ctl->met_gp2z != 0 && ctl->met_gp2z != 1)
7057 ERRMSG("Set MET_GP2Z to 0 or 1!");
7058
7059 /* Time steps of simulation... */
7060 ctl->direction =
7061 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
7062 if (ctl->direction != -1 && ctl->direction != 1)
7063 ERRMSG("Set DIRECTION to -1 or 1!");
7064 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
7065 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
7066
7067 /* Meteo data... */
7068 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
7069 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
7070 if (ctl->dt_mod > ctl->dt_met)
7071 ERRMSG("DT_MOD must not exceed DT_MET!");
7072 ctl->met_convention =
7073 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
7074 ctl->met_type =
7075 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
7076 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
7077 ERRMSG
7078 ("Please use meteo files in netcdf format for diabatic calculations.");
7079 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
7080 ERRMSG
7081 ("Please use meteo files in netcdf format for etadot calculations.");
7082 ctl->met_clams =
7083 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
7084 ctl->met_nc_scale =
7085 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
7086 ctl->met_nc_level =
7087 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
7088 ctl->met_nc_quant =
7089 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
7090 ctl->met_zstd_level =
7091 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "-3", NULL);
7092 ctl->met_zstd_nworkers =
7093 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_NWORKERS", -1, "4", NULL);
7094 ctl->met_lz4_accel =
7095 (int) scan_ctl(filename, argc, argv, "MET_LZ4_ACCEL", -1, "8", NULL);
7096 ctl->met_pck_zstd =
7097 (int) scan_ctl(filename, argc, argv, "MET_PCK_ZSTD", -1, "0", NULL);
7098 if (ctl->met_pck_zstd != 0 && ctl->met_pck_zstd != 1)
7099 ERRMSG("Set MET_PCK_ZSTD to 0 or 1!");
7100#ifndef ZSTD
7101 if (ctl->met_type == 2 && ctl->met_pck_zstd)
7102 ERRMSG("MET_PCK_ZSTD requires MPTRAC to be compiled with ZSTD support!");
7103#endif
7104 const int def_lossy_scale =
7105 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", -1, "0", NULL);
7106 for (int i = 0; i < METVAR; i++) {
7107 char defprec_zfp[LEN] = "7", deftol_zfp[LEN] = "0.0";
7108 char defprec_sz3[LEN] = "6", deftol_sz3[LEN] = "0.0";
7109 if (i == 0) { /* geopotential height */
7110 sprintf(defprec_zfp, "12");
7111 sprintf(defprec_sz3, "11");
7112 } else if (i == 1) { /* temperature */
7113 sprintf(defprec_zfp, "11");
7114 sprintf(defprec_sz3, "7");
7115 } else if (i == 2 || i == 3) { /* horizontal wind */
7116 sprintf(defprec_zfp, "7");
7117 sprintf(defprec_sz3, "7");
7118 } else if (i == 4) { /* vertical wind */
7119 sprintf(defprec_zfp, "6");
7120 sprintf(defprec_sz3, "13");
7121 } else if (i == 5) { /* potential vorticity */
7122 sprintf(defprec_zfp, "7");
7123 sprintf(defprec_sz3, "20");
7124 } else if (i == 6) { /* water vapor */
7125 sprintf(defprec_zfp, "10");
7126 sprintf(defprec_sz3, "18");
7127 } else if (i == 7) { /* ozone */
7128 sprintf(defprec_zfp, "9");
7129 sprintf(defprec_sz3, "10");
7130 } else if (i >= 8 && i <= 11) { /* cloud water fields */
7131 sprintf(defprec_zfp, "6");
7132 sprintf(defprec_sz3, "13");
7133 } else if (i == 12) { /* cloud cover */
7134 sprintf(defprec_zfp, "9");
7135 sprintf(defprec_sz3, "6");
7136 }
7137 ctl->met_zfp_prec[i] =
7138 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", i, defprec_zfp,
7139 NULL);
7140 ctl->met_zfp_tol[i] =
7141 scan_ctl(filename, argc, argv, "MET_ZFP_TOL", i, deftol_zfp, NULL);
7142 ctl->met_sz3_prec[i] =
7143 (int) scan_ctl(filename, argc, argv, "MET_SZ3_PREC", i, defprec_sz3,
7144 NULL);
7145 ctl->met_sz3_tol[i] =
7146 scan_ctl(filename, argc, argv, "MET_SZ3_TOL", i, deftol_sz3, NULL);
7147 char defscale[LEN];
7148 snprintf(defscale, LEN, "%d", def_lossy_scale);
7149 ctl->met_lossy_scale[i] =
7150 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", i, defscale,
7151 NULL);
7152 if (ctl->met_lossy_scale[i] < 0 || ctl->met_lossy_scale[i] > 1)
7153 ERRMSG("Set MET_LOSSY_SCALE to 0 or 1!");
7154 }
7155
7156 /* Scan compression diagnostics file... */
7157 scan_ctl(filename, argc, argv, "MET_COMP_LOGFILE", -1, "-",
7158 ctl->met_comp_logfile);
7159 ctl->met_cms_batch =
7160 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
7161 ctl->met_cms_zstd =
7162 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
7163 ctl->met_cms_nd0x =
7164 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0X", -1, "48", NULL);
7165 ctl->met_cms_nd0y =
7166 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0Y", -1, "24", NULL);
7167 ctl->met_cms_maxlev =
7168 (int) scan_ctl(filename, argc, argv, "MET_CMS_MAXLEV", -1, "6", NULL);
7169 for (int i = 0; i < METVAR; i++) {
7170 char defeps[LEN] = "1.0";
7171 if (i == 1 || i == 2 || i == 3)
7172 sprintf(defeps, "0.05");
7173 ctl->met_cms_eps[i] =
7174 scan_ctl(filename, argc, argv, "MET_CMS_EPS", i, defeps, NULL);
7175 }
7176 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
7177 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
7178 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
7179 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
7180 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
7181 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
7182 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
7183 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
7184 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
7185 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
7186 ctl->met_detrend =
7187 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
7188 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
7189 if (ctl->met_np > EP)
7190 ERRMSG("Too many pressure levels!");
7191 ctl->met_press_level_def =
7192 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
7193 NULL);
7194 if (ctl->met_press_level_def >= 0) {
7195 level_definitions(ctl);
7196 } else {
7197 if (ctl->met_np > 0) {
7198 for (int ip = 0; ip < ctl->met_np; ip++)
7199 ctl->met_p[ip] =
7200 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
7201 }
7202 }
7203 ctl->met_nlev =
7204 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
7205 if (ctl->met_nlev > EP)
7206 ERRMSG("Too many model levels!");
7207 for (int ip = 0; ip < ctl->met_nlev; ip++)
7208 ctl->met_lev_hyam[ip] =
7209 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
7210 for (int ip = 0; ip < ctl->met_nlev; ip++)
7211 ctl->met_lev_hybm[ip] =
7212 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
7213 ctl->met_geopot_sx =
7214 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
7215 ctl->met_geopot_sy =
7216 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
7217 ctl->met_relhum =
7218 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
7219 ctl->met_cape =
7220 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
7221 if (ctl->met_cape < 0 || ctl->met_cape > 1)
7222 ERRMSG("Set MET_CAPE to 0 or 1!");
7223 ctl->met_pbl =
7224 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
7225 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
7226 ERRMSG("Set MET_PBL to 0 ... 3!");
7227 ctl->met_pbl_min =
7228 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
7229 ctl->met_pbl_max =
7230 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
7231 ctl->met_tropo =
7232 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
7233 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
7234 ERRMSG("Set MET_TROPO to 0 ... 5!");
7235 ctl->met_tropo_pv =
7236 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
7237 ctl->met_tropo_theta =
7238 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
7239 ctl->met_tropo_spline =
7240 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
7241 ctl->met_dt_out =
7242 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
7243 ctl->met_cache =
7244 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
7245 ctl->met_mpi_share =
7246 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
7247
7248 /* Sorting... */
7249 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
7250
7251 /* Isosurface parameters... */
7252 ctl->isosurf =
7253 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
7254 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
7255
7256 /* Random number generator... */
7257 ctl->rng_type =
7258 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
7259 if (ctl->rng_type < 0 || ctl->rng_type > 2)
7260 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
7261
7262 /* Advection parameters... */
7263 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
7264 if (!(ctl->advect == 1 || ctl->advect == 2 || ctl->advect == 4))
7265 ERRMSG("Set ADVECT to 1, 2, or 4!");
7266
7267 /* Diffusion parameters... */
7268 ctl->diffusion
7269 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
7270 if (ctl->diffusion < 0 || ctl->diffusion > 1)
7271 ERRMSG("Set DIFFUSION to 0 or 1!");
7272 ctl->turb_pbl_scheme =
7273 (int) scan_ctl(filename, argc, argv, "TURB_PBL_SCHEME", -1, "0", NULL);
7274 if (ctl->turb_pbl_scheme < 0 || ctl->turb_pbl_scheme > 1)
7275 ERRMSG("Set TURB_PBL_SCHEME to 0 or 1!");
7276 ctl->turb_dx_pbl =
7277 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
7278 ctl->turb_dx_trop =
7279 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
7280 ctl->turb_dx_strat =
7281 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
7282 ctl->turb_dz_pbl =
7283 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
7284 ctl->turb_dz_trop =
7285 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
7286 ctl->turb_dz_strat =
7287 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
7288 ctl->turb_mesox =
7289 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
7290 ctl->turb_mesoz =
7291 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
7292 ctl->turb_pbl_trans =
7293 scan_ctl(filename, argc, argv, "TURB_PBL_TRANS", -1, "0", NULL);
7294 if (ctl->turb_pbl_trans < 0 || ctl->turb_pbl_trans > 1)
7295 ERRMSG("TURB_PBL_TRANS must be in the range [0, 1]!");
7296
7297 /* Convection... */
7298 ctl->conv_mix_pbl
7299 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
7300 ctl->conv_pbl_trans
7301 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
7302 if (ctl->conv_pbl_trans < 0 || ctl->conv_pbl_trans > 1)
7303 ERRMSG("CONV_PBL_TRANS must be in the range [0, 1]!");
7304 ctl->conv_cape
7305 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
7306 ctl->conv_cin
7307 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
7308 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
7309
7310 /* Boundary conditions... */
7311 ctl->bound_mass =
7312 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
7313 ctl->bound_mass_trend =
7314 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
7315 ctl->bound_vmr =
7316 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
7317 ctl->bound_vmr_trend =
7318 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
7319 ctl->bound_lat0 =
7320 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
7321 ctl->bound_lat1 =
7322 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
7323 ctl->bound_p0 =
7324 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
7325 ctl->bound_p1 =
7326 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
7327 ctl->bound_dps =
7328 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
7329 ctl->bound_dzs =
7330 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
7331 ctl->bound_zetas =
7332 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
7333 ctl->bound_pbl =
7334 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
7335
7336 /* Species parameters... */
7337 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
7338 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
7339 ctl->molmass = 120.907;
7340 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
7341 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
7342 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
7343 ctl->molmass = 137.359;
7344 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
7345 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
7346 } else if (strcasecmp(ctl->species, "CH4") == 0) {
7347 ctl->molmass = 16.043;
7348 ctl->oh_chem_reaction = 2;
7349 ctl->oh_chem[0] = 2.45e-12;
7350 ctl->oh_chem[1] = 1775;
7351 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
7352 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
7353 } else if (strcasecmp(ctl->species, "CO") == 0) {
7354 ctl->molmass = 28.01;
7355 ctl->oh_chem_reaction = 3;
7356 ctl->oh_chem[0] = 6.9e-33;
7357 ctl->oh_chem[1] = 2.1;
7358 ctl->oh_chem[2] = 1.1e-12;
7359 ctl->oh_chem[3] = -1.3;
7360 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
7361 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
7362 } else if (strcasecmp(ctl->species, "CO2") == 0) {
7363 ctl->molmass = 44.009;
7364 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
7365 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
7366 } else if (strcasecmp(ctl->species, "H2O") == 0) {
7367 ctl->molmass = 18.01528;
7368 } else if (strcasecmp(ctl->species, "N2O") == 0) {
7369 ctl->molmass = 44.013;
7370 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
7371 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
7372 } else if (strcasecmp(ctl->species, "NH3") == 0) {
7373 ctl->molmass = 17.031;
7374 ctl->oh_chem_reaction = 2;
7375 ctl->oh_chem[0] = 1.7e-12;
7376 ctl->oh_chem[1] = 710;
7377 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
7378 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
7379 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
7380 ctl->molmass = 63.012;
7381 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
7382 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
7383 } else if (strcasecmp(ctl->species, "NO") == 0) {
7384 ctl->molmass = 30.006;
7385 ctl->oh_chem_reaction = 3;
7386 ctl->oh_chem[0] = 7.1e-31;
7387 ctl->oh_chem[1] = 2.6;
7388 ctl->oh_chem[2] = 3.6e-11;
7389 ctl->oh_chem[3] = 0.1;
7390 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
7391 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
7392 } else if (strcasecmp(ctl->species, "NO2") == 0) {
7393 ctl->molmass = 46.005;
7394 ctl->oh_chem_reaction = 3;
7395 ctl->oh_chem[0] = 1.8e-30;
7396 ctl->oh_chem[1] = 3.0;
7397 ctl->oh_chem[2] = 2.8e-11;
7398 ctl->oh_chem[3] = 0.0;
7399 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
7400 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
7401 } else if (strcasecmp(ctl->species, "O3") == 0) {
7402 ctl->molmass = 47.997;
7403 ctl->oh_chem_reaction = 2;
7404 ctl->oh_chem[0] = 1.7e-12;
7405 ctl->oh_chem[1] = 940;
7406 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
7407 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
7408 } else if (strcasecmp(ctl->species, "SF6") == 0) {
7409 ctl->molmass = 146.048;
7410 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
7411 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
7412 } else if (strcasecmp(ctl->species, "SO2") == 0) {
7413 ctl->molmass = 64.066;
7414 ctl->oh_chem_reaction = 3;
7415 ctl->oh_chem[0] = 2.9e-31;
7416 ctl->oh_chem[1] = 4.1;
7417 ctl->oh_chem[2] = 1.7e-12;
7418 ctl->oh_chem[3] = -0.2;
7419 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = SO2_HENRY_REF;
7420 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = SO2_HENRY_TEMP;
7421 }
7422
7423 /* Molar mass... */
7424 char defstr[LEN];
7425 sprintf(defstr, "%g", ctl->molmass);
7426 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
7427
7428 /* OH chemistry... */
7429 sprintf(defstr, "%d", ctl->oh_chem_reaction);
7430 ctl->oh_chem_reaction =
7431 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
7432 NULL);
7433 for (int ip = 0; ip < 4; ip++) {
7434 sprintf(defstr, "%g", ctl->oh_chem[ip]);
7435 ctl->oh_chem[ip] =
7436 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
7437 }
7438 ctl->oh_chem_beta =
7439 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
7440
7441 /* H2O2 chemistry... */
7442 ctl->h2o2_chem_reaction =
7443 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
7444
7445 /* KPP chemistry... */
7446 ctl->kpp_chem =
7447 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
7448 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
7449
7450 /* First order tracer chemistry... */
7451 ctl->tracer_chem =
7452 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
7453
7454 /* Radioactive decay... */
7455 ctl->radio_decay =
7456 (int) scan_ctl(filename, argc, argv, "RADIO_DECAY", -1, "0", NULL);
7457 ctl->radio_depo =
7458 (int) scan_ctl(filename, argc, argv, "RADIO_DEPO", -1, "0", NULL);
7459 if (ctl->radio_depo && ctl->met_coord_type != 0)
7460 ERRMSG("Radioactive deposition requires a lat/lon meteorological grid!");
7461#ifdef DD
7462 if (ctl->radio_depo)
7463 ERRMSG
7464 ("Radioactive deposition is not supported with domain decomposition!");
7465#endif
7466
7467 /* Wet deposition... */
7468 for (int ip = 0; ip < 2; ip++) {
7469 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
7470 ctl->wet_depo_ic_h[ip] =
7471 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
7472 }
7473 for (int ip = 0; ip < 1; ip++) {
7474 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
7475 ctl->wet_depo_bc_h[ip] =
7476 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
7477 }
7478 ctl->wet_depo_so2_ph =
7479 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
7480 ctl->wet_depo_ic_a =
7481 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
7482 ctl->wet_depo_ic_b =
7483 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
7484 ctl->wet_depo_bc_a =
7485 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
7486 ctl->wet_depo_bc_b =
7487 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
7488 ctl->wet_depo_pre[0] =
7489 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
7490 ctl->wet_depo_pre[1] =
7491 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
7493 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
7495 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
7496
7497 /* Dry deposition... */
7498 ctl->dry_depo_vdep =
7499 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
7500 ctl->dry_depo_dp =
7501 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
7502
7503 /* Climatological data... */
7504 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
7505 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
7506 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
7507 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
7508 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
7509 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
7510 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
7511 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
7512 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
7513 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
7514 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
7515 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
7516 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
7517 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
7518 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
7519 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
7520 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
7521 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
7522 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
7523 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
7524 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
7525 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
7526
7527 /* Mixing... */
7528 ctl->mixing_dt =
7529 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
7530 ctl->mixing_tau_trop =
7531 scan_ctl(filename, argc, argv, "MIXING_TAU_TROP", -1, "-999", NULL);
7532 ctl->mixing_tau_strat =
7533 scan_ctl(filename, argc, argv, "MIXING_TAU_STRAT", -1, "-999", NULL);
7534 ctl->mixing_z0 =
7535 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
7536 ctl->mixing_z1 =
7537 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
7538 ctl->mixing_nz =
7539 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
7540 ctl->mixing_lon0 =
7541 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
7542 ctl->mixing_lon1 =
7543 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
7544 ctl->mixing_nx =
7545 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
7546 ctl->mixing_lat0 =
7547 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
7548 ctl->mixing_lat1 =
7549 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
7550 ctl->mixing_ny =
7551 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
7552 if (ctl->mixing_nx < 1 || ctl->mixing_ny < 1 || ctl->mixing_nz < 1
7553 || ctl->mixing_lon0 >= ctl->mixing_lon1
7554 || ctl->mixing_lat0 >= ctl->mixing_lat1
7555 || ctl->mixing_z0 >= ctl->mixing_z1
7556 || ctl->mixing_lat0 < -90 || ctl->mixing_lat1 > 90)
7557 ERRMSG("Invalid mixing grid!");
7558 if ((ctl->mixing_tau_trop > 0) != (ctl->mixing_tau_strat > 0)
7559 || ctl->mixing_tau_trop == 0 || ctl->mixing_tau_strat == 0)
7560 ERRMSG("Mixing times must either both be positive or both be disabled!");
7561
7562 /* Chemistry grid... */
7563 ctl->chemgrid_z0 =
7564 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
7565 ctl->chemgrid_z1 =
7566 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
7567 ctl->chemgrid_nz =
7568 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
7569 ctl->chemgrid_lon0 =
7570 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
7571 ctl->chemgrid_lon1 =
7572 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
7573 ctl->chemgrid_nx =
7574 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
7575 ctl->chemgrid_lat0 =
7576 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
7577 ctl->chemgrid_lat1 =
7578 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
7579 ctl->chemgrid_ny =
7580 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
7581 if (ctl->chemgrid_nx < 1 || ctl->chemgrid_ny < 1 || ctl->chemgrid_nz < 1
7582 || ctl->chemgrid_lon0 >= ctl->chemgrid_lon1
7583 || ctl->chemgrid_lat0 >= ctl->chemgrid_lat1
7584 || ctl->chemgrid_z0 >= ctl->chemgrid_z1
7585 || ctl->chemgrid_lat0 < -90 || ctl->chemgrid_lat1 > 90)
7586 ERRMSG("Invalid chemistry grid!");
7587
7588 /* Exponential decay... */
7589 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
7590 ctl->tdec_strat =
7591 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
7592
7593 /* PSC analysis... */
7594 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
7595 ctl->psc_hno3 =
7596 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
7597
7598 /* Output of atmospheric data... */
7599 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
7600 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
7601 ctl->atm_dt_out =
7602 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
7603 ctl->atm_filter =
7604 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
7605 ctl->atm_stride =
7606 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
7607 ctl->atm_type =
7608 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
7609 ctl->atm_type_out =
7610 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
7611 if (ctl->atm_type_out == -1)
7612 ctl->atm_type_out = ctl->atm_type;
7613 ctl->atm_nc_level =
7614 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
7615 for (int iq = 0; iq < ctl->nq; iq++)
7616 ctl->atm_nc_quant[iq] =
7617 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
7618 ctl->obs_type =
7619 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
7620
7621 /* Output of mass budget data... */
7622 scan_ctl(filename, argc, argv, "BUDGET_BASENAME", -1, "-",
7623 ctl->budget_basename);
7624 ctl->budget_dt_out =
7625 scan_ctl(filename, argc, argv, "BUDGET_DT_OUT", -1, "86400", NULL);
7626 if (ctl->budget_basename[0] != '-' && ctl->budget_dt_out <= 0)
7627 ERRMSG("Invalid mass budget output settings!");
7628
7629 /* Output of radioactive deposition data... */
7630 scan_ctl(filename, argc, argv, "DEPO_BASENAME", -1, "-",
7631 ctl->depo_basename);
7632 ctl->depo_dt_out =
7633 scan_ctl(filename, argc, argv, "DEPO_DT_OUT", -1, "86400", NULL);
7634 ctl->depo_type =
7635 (int) scan_ctl(filename, argc, argv, "DEPO_TYPE", -1, "0", NULL);
7636
7637 /* Output of CSI data... */
7638 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
7639 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
7640 ctl->csi_dt_out =
7641 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
7642 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
7643 ctl->csi_obsmin =
7644 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
7645 ctl->csi_modmin =
7646 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
7647 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
7648 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
7649 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
7650 ctl->csi_lon0 =
7651 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
7652 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
7653 ctl->csi_nx =
7654 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
7655 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
7656 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
7657 ctl->csi_ny =
7658 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
7659 if (ctl->csi_nx < 1 || ctl->csi_ny < 1 || ctl->csi_nz < 1
7660 || ctl->csi_lon0 >= ctl->csi_lon1
7661 || ctl->csi_lat0 >= ctl->csi_lat1 || ctl->csi_z0 >= ctl->csi_z1
7662 || ctl->csi_lat0 < -90 || ctl->csi_lat1 > 90)
7663 ERRMSG("Invalid CSI grid!");
7664
7665 /* Output of ensemble data... */
7666 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
7667 if (ctl->nens < 0)
7668 ERRMSG("NENS must not be negative!");
7669 if (ctl->nens > 0 && ctl->qnt_ens < 0)
7670 ERRMSG("Add quantity ens for ensemble calculations!");
7671 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
7672 ctl->ens_dt_out =
7673 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
7674
7675 /* Output of grid data... */
7676 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
7677 ctl->grid_basename);
7678 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
7679 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
7680 ctl->grid_dt_out =
7681 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
7682 ctl->grid_sparse =
7683 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
7684 ctl->grid_nc_level =
7685 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
7686 for (int iq = 0; iq < ctl->nq; iq++)
7687 ctl->grid_nc_quant[iq] =
7688 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
7689 ctl->grid_stddev =
7690 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
7691 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
7692 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
7693 ctl->grid_nz =
7694 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
7695 ctl->grid_lon0 =
7696 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
7697 ctl->grid_lon1 =
7698 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
7699 ctl->grid_nx =
7700 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
7701 ctl->grid_lat0 =
7702 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
7703 ctl->grid_lat1 =
7704 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
7705 ctl->grid_ny =
7706 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
7707 ctl->grid_type =
7708 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
7709 if (ctl->grid_nx < 1 || ctl->grid_nx > EX
7710 || ctl->grid_ny < 1 || ctl->grid_ny > EY || ctl->grid_nz < 1)
7711 ERRMSG("Invalid output grid dimensions!");
7712 if (ctl->grid_lon0 >= ctl->grid_lon1
7713 || ctl->grid_lat0 >= ctl->grid_lat1 || ctl->grid_z0 >= ctl->grid_z1
7714 || ctl->grid_lat0 < -90 || ctl->grid_lat1 > 90)
7715 ERRMSG("Invalid output grid boundaries!");
7716 if (ctl->depo_basename[0] != '-'
7717 && (ctl->depo_dt_out <= 0 || ctl->depo_type < 0 || ctl->depo_type > 1))
7718 ERRMSG("Invalid radioactive deposition output settings!");
7719
7720 /* Output of profile data... */
7721 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
7722 ctl->prof_basename);
7723 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
7724 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
7725 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
7726 ctl->prof_nz =
7727 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
7728 ctl->prof_lon0 =
7729 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
7730 ctl->prof_lon1 =
7731 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
7732 ctl->prof_nx =
7733 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
7734 ctl->prof_lat0 =
7735 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
7736 ctl->prof_lat1 =
7737 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
7738 ctl->prof_ny =
7739 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
7740 if (ctl->prof_nx < 1 || ctl->prof_ny < 1 || ctl->prof_nz < 1
7741 || ctl->prof_lon0 >= ctl->prof_lon1
7742 || ctl->prof_lat0 >= ctl->prof_lat1 || ctl->prof_z0 >= ctl->prof_z1
7743 || ctl->prof_lat0 < -90 || ctl->prof_lat1 > 90)
7744 ERRMSG("Invalid profile grid!");
7745
7746 /* Output of sample data... */
7747 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
7748 ctl->sample_basename);
7749 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
7750 ctl->sample_kernel);
7751 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
7752 ctl->sample_obsfile);
7753 ctl->sample_dx =
7754 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
7755 ctl->sample_dz =
7756 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
7757
7758 /* Output of station data... */
7759 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
7760 ctl->stat_basename);
7761 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
7762 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
7763 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
7764 ctl->stat_t0 =
7765 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
7766 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
7767
7768 /* Output of VTK data... */
7769 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
7770 ctl->vtk_dt_out =
7771 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
7772 ctl->vtk_stride =
7773 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
7774 ctl->vtk_scale =
7775 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
7776 ctl->vtk_offset =
7777 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
7778 ctl->vtk_sphere =
7779 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
7780
7781 /* Domain decomposition... */
7782#ifdef DD
7783 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "1", NULL);
7784#else
7785 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
7786#endif
7787
7789 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
7790 (ctl->dd == 1) ? "2" : "1", NULL);
7791 ctl->dd_subdomains_zonal =
7792 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
7793 (ctl->dd == 1) ? "2" : "1", NULL);
7794 ctl->dd_halos_size =
7795 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
7796 ctl->dd_sort_dt =
7797 (double) scan_ctl(filename, argc, argv, "DD_SORT_DT", -1, "1800", NULL);
7798}
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:3342
double scan_ctl(const char *filename, int argc, char *argv[], const char *varname, const int arridx, const char *defvalue, char *value)
Scans a control file or command-line arguments for a specified variable.
Definition: mptrac.c:12517
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:563
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:553
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:573
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:2013
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3443
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2616
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3404
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3371
int qnt_target_subdomain
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2832
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2883
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2649
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3380
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2595
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:3326
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2628
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3374
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2637
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3395
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2604
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3521
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:3026
double stat_r
Search radius around station [km].
Definition: mptrac.h:3527
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3398
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3551
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2994
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2625
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2703
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3470
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3446
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2946
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:3013
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2667
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2742
char species[LEN]
Species.
Definition: mptrac.h:3130
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3389
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3401
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2991
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2619
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3431
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2550
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2646
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2673
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:3010
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3506
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2736
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2982
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3422
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2571
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2715
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3533
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3365
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3467
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3392
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2577
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3437
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2700
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2979
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2952
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2547
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3473
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2553
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3476
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3368
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2988
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3377
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2949
double depo_dt_out
DEPO_DT_OUT time interval for radioactive deposition output [s] (default: 86400).
Definition: mptrac.h:3317
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3419
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3479
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2610
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:3004
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3485
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2532
double dd_sort_dt
Sorting time interval for the compactification.
Definition: mptrac.h:3570
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:3019
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2745
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2670
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3386
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3530
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3558
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3344
int met_cms_nd0x
cmultiscale number of cells of coarsest grid in x-direction.
Definition: mptrac.h:2928
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2970
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:3256
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3362
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2568
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2559
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3539
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:3091
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3509
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2661
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3416
char met_comp_logfile[LEN]
Filename for per-level compression diagnostics ("-" disables output).
Definition: mptrac.h:2919
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2589
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2709
int met_gp2z
Convert surface geopotential to geopotential height (0=no, 1=yes).
Definition: mptrac.h:2873
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2997
int met_dx
Stride for longitudes.
Definition: mptrac.h:2940
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2857
char depo_basename[LEN]
DEPO_BASENAME for radioactive deposition files (default: disabled with "-").
Definition: mptrac.h:3314
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2721
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:3259
int diffusion
Diffusion switch (0=off, 1=on).
Definition: mptrac.h:3046
double budget_dt_out
Time step for mass budget output [s].
Definition: mptrac.h:3359
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2592
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3548
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2607
double met_zfp_tol[METVAR]
ZFP compression tolerance.
Definition: mptrac.h:2907
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2664
int met_sz3_prec[METVAR]
SZ3 compression precision.
Definition: mptrac.h:2910
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2613
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3494
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2712
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2601
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3515
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3353
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3434
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2556
int depo_type
DEPO_TYPE of deposition files (0=ASCII, 1=netCDF, default: 0).
Definition: mptrac.h:3320
char budget_basename[LEN]
Basename of mass budget data file.
Definition: mptrac.h:3356
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:3323
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2580
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2640
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3482
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2973
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2598
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3332
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:3253
int met_lz4_accel
LZ4 acceleration factor (>=1, default=8).
Definition: mptrac.h:2898
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3410
int met_vert_coord
Vertical coordinate of input meteo data (0=plev, 1=mlev_p_file, 2=mlev_ab_file, 3=mlev_ab_full,...
Definition: mptrac.h:2870
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3383
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2739
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3524
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2958
double met_cms_eps[METVAR]
cmultiscale compression epsilon.
Definition: mptrac.h:2937
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2652
int met_cms_nd0y
cmultiscale number of cells of coarsest grid in y-direction.
Definition: mptrac.h:2931
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2658
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3440
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2565
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3413
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3503
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3335
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2985
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:3329
int met_lossy_scale[METVAR]
Apply levelwise [0,1] scaling before lossy compression (0=off, 1=on).
Definition: mptrac.h:2916
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3500
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2922
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:3304
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2955
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3488
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2634
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2682
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2697
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2976
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3497
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2655
double turb_pbl_trans
Depth of turbulent PBL transition layer (fraction of PBL pressure thickness).
Definition: mptrac.h:3076
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:3307
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3491
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2889
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:3250
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3350
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2925
int met_cms_maxlev
cmultiscale maximum refinement level.
Definition: mptrac.h:2934
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3428
double met_sz3_tol[METVAR]
SZ3 compression tolerance.
Definition: mptrac.h:2913
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3536
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2583
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2886
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3545
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2748
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2574
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3347
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2706
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2562
int met_dy
Stride for latitudes.
Definition: mptrac.h:2943
int radio_depo
RADIO_DEPO switch for radionuclide deposition (0=off, 1=on, default: 0).
Definition: mptrac.h:3265
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2526
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:3007
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2622
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2517
int met_zfp_prec[METVAR]
ZFP compression precision.
Definition: mptrac.h:2904
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3512
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3542
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3518
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2586
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2631
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2643
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3425
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2751
Here is the call graph for this function:

◆ mptrac_read_met()

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

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

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

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

Definition at line 7802 of file mptrac.c.

7807 {
7808
7809 /* Write info... */
7810 LOG(1, "Read meteo data: %s", filename);
7811
7812 /* Set rank... */
7813 int rank = 0;
7814#ifdef MPI
7815 if (ctl->met_mpi_share)
7816 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
7817#endif
7818
7819 /* Check rank... */
7820 if (!ctl->met_mpi_share || rank == 0) {
7821
7822 /* Read netCDF data... */
7823 if (ctl->met_type == 0) {
7824 if (read_met_nc(filename, ctl, met, dd) != 1)
7825 return 0;
7826 }
7827
7828 /* Read binary data... */
7829 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
7830 || ctl->met_type == 7 || ctl->met_type == 8) {
7831 if (read_met_bin(filename, ctl, met) != 1)
7832 return 0;
7833 }
7834#ifdef ECCODES
7835 /* Read grib data... */
7836 else if (ctl->met_type == 6) {
7837 if (read_met_grib(filename, ctl, met) != 1)
7838 return 0;
7839 }
7840#endif
7841
7842 /* Not implemented... */
7843 else
7844 ERRMSG("MET_TYPE not implemented!");
7845
7846 /* Preprocessing for netCDF and grib files... */
7847 if (ctl->met_type == 0 || ctl->met_type == 6) {
7848
7849 /* Extrapolate data for lower boundary... */
7851
7852 /* Fix polar winds... */
7854
7855 /* Create periodic boundary conditions... */
7856#ifndef DD
7857 read_met_periodic(met);
7858#endif
7859
7860 /* Downsampling... */
7861 read_met_sample(ctl, met);
7862
7863 /* Calculate geopotential heights... */
7864 read_met_geopot(ctl, met);
7865
7866 /* Calculate potential vorticity... */
7867 read_met_pv(met);
7868
7869 /* Calculate boundary layer data... */
7870 read_met_pbl(ctl, met);
7871
7872 /* Calculate tropopause data... */
7873 read_met_tropo(ctl, clim, met);
7874
7875 /* Calculate cloud properties... */
7876 read_met_cloud(met);
7877
7878 /* Calculate convective available potential energy... */
7879 read_met_cape(ctl, clim, met);
7880
7881 /* Calculate total column ozone... */
7882 read_met_ozone(met);
7883
7884 /* Detrending... */
7885 read_met_detrend(ctl, met);
7886
7887 /* Check meteo data and smooth zeta profiles ... */
7888 read_met_monotonize(ctl, met);
7889 }
7890 }
7891
7892 /* Broadcast data via MPI... */
7893#ifdef MPI
7894 if (ctl->met_mpi_share) {
7895
7896 /* Set timer... */
7897 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM");
7898 LOG(2, "Broadcast data on rank %d...", rank);
7899
7900 /* Broadcast... */
7901 broadcast_large_data(met, sizeof(met_t));
7902 }
7903#endif
7904
7905 /* Return success... */
7906 return 1;
7907}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:9579
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:9539
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:12069
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:9375
void read_met_pbl(const ctl_t *ctl, met_t *met)
Computes the planetary boundary layer (PBL) pressure based on meteorological data.
Definition: mptrac.c:11660
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:9432
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:11356
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:11797
int read_met_nc(const char *filename, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads meteorological data from a NetCDF file and processes it.
Definition: mptrac.c:11441
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:12040
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:11920
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:8956
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:11858
void read_met_cape(const ctl_t *ctl, const clim_t *clim, met_t *met)
Calculates Convective Available Potential Energy (CAPE) for each grid point.
Definition: mptrac.c:9255
int read_met_grib(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a grib file and processes it.
void broadcast_large_data(void *data, size_t N)
Broadcasts large data across all processes in an MPI communicator.
Here is the call graph for this function:

◆ mptrac_run_timestep()

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

Executes a single timestep of the MPTRAC model simulation.

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

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

Definition at line 7911 of file mptrac.c.

7920 {
7921
7922 /* Initialize modules... */
7923 if (t == ctl->t_start) {
7924
7925 /* Initialize isosurface data... */
7926 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7927 module_isosurf_init(ctl, cache, *met0, *met1, atm);
7928
7929 /* Initialize advection... */
7930 module_advect_init(ctl, cache, *met0, *met1, atm);
7931
7932 /* Initialize chemistry... */
7933 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
7934 }
7935
7936 /* Set time steps of air parcels... */
7937 module_timesteps(ctl, cache, *met0, atm, t);
7938
7939 /* Sort particles... */
7940 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
7941 module_sort(ctl, *met0, atm);
7942
7943 /* Check positions (initial)... */
7944 module_position(cache, *met0, *met1, atm, 0);
7945
7946 /* Advection... */
7947 if (ctl->advect > 0)
7948 module_advect(ctl, cache, *met0, *met1, atm);
7949
7950 /* Turbulent diffusion... */
7951 if (ctl->diffusion
7952 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
7953 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
7954 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
7955 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
7956
7957 /* Optional PBL-specific diffusion scheme... */
7958 if (ctl->diffusion && ctl->turb_pbl_scheme == 1)
7959 module_diff_pbl(ctl, cache, *met0, *met1, atm);
7960
7961 /* Mesoscale diffusion... */
7962 if (ctl->diffusion && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
7963 module_diff_meso(ctl, cache, *met0, *met1, atm);
7964
7965 /* Convection... */
7966 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
7967 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
7968 module_convection(ctl, cache, *met0, *met1, atm);
7969
7970 /* Sedimentation... */
7971 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
7972 module_sedi(ctl, cache, *met0, *met1, atm);
7973
7974 /* Isosurface... */
7975 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7976 module_isosurf(ctl, cache, *met0, *met1, atm);
7977
7978 /* Check positions (final)... */
7979 module_position(cache, *met0, *met1, atm, 1);
7980
7981 /* Interpolate meteo data... */
7982 if (ctl->met_dt_out > 0
7983 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
7984 module_meteo(ctl, cache, clim, *met0, *met1, atm);
7985
7986 /* Check boundary conditions (initial)... */
7987 if ((ctl->bound_lat0 < ctl->bound_lat1)
7988 && (ctl->bound_p0 > ctl->bound_p1))
7989 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
7990
7991 /* Initialize quantity of total loss rate... */
7992 if (ctl->qnt_loss_rate >= 0) {
7993 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
7994 atm->q[ctl->qnt_loss_rate][ip] = 0;
7995 }
7996 }
7997
7998 /* Decay of particle mass... */
7999 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
8000 module_decay(ctl, cache, clim, atm);
8001
8002 /* Interparcel mixing... */
8003 if (ctl->mixing_tau_trop > 0 && ctl->mixing_tau_strat > 0
8004 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
8005 module_mixing(ctl, clim, atm, t);
8006
8007 /* Calculate the tracer vmr in the chemistry grid... */
8008 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
8009 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
8010 module_chem_grid(ctl, *met0, *met1, atm, t);
8011
8012 /* OH chemistry... */
8013 if (ctl->oh_chem_reaction != 0)
8014 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
8015
8016 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
8017 if (ctl->h2o2_chem_reaction != 0)
8018 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
8019
8020 /* First-order tracer chemistry... */
8021 if (ctl->tracer_chem)
8022 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
8023
8024 /* Radioactive decay... */
8025 if (ctl->radio_decay)
8026 module_radio_decay(ctl, cache, atm);
8027
8028 /* Domain decomposition... */
8029#ifdef DD
8030 module_dd(t, ctl, cache, dd, atm, met0);
8031#else
8032 (void) dd;
8033#endif
8034
8035 /* Radioactive deposition... */
8036 if (ctl->radio_depo)
8037 module_radio_depo(ctl, cache, *met0, *met1, atm, depo);
8038
8039 /* KPP chemistry... */
8040 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
8041#ifdef KPP
8042 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
8043#else
8044 ERRMSG("Code was compiled without KPP!");
8045#endif
8046 }
8047
8048 /* Wet deposition... */
8049 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
8050 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
8051 module_wet_depo(ctl, cache, *met0, *met1, atm);
8052
8053 /* Dry deposition... */
8054 if (ctl->dry_depo_vdep > 0)
8055 module_dry_depo(ctl, cache, *met0, *met1, atm);
8056
8057 /* Check boundary conditions (final)... */
8058 if ((ctl->bound_lat0 < ctl->bound_lat1)
8059 && (ctl->bound_p0 > ctl->bound_p1))
8060 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
8061}
void module_advect(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Advances particle positions using different advection schemes.
Definition: mptrac.c:3598
void module_meteo(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Update atmospheric properties using meteorological data.
Definition: mptrac.c:5069
void module_decay(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, atm_t *atm)
Simulate exponential decay processes for atmospheric particles.
Definition: mptrac.c:4234
void module_chem_init(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Initializes the chemistry modules by setting atmospheric composition.
Definition: mptrac.c:4065
void module_mixing(const ctl_t *ctl, const clim_t *clim, atm_t *atm, const double t)
Update atmospheric properties through interparcel mixing.
Definition: mptrac.c:5195
void module_isosurf_init(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Initialize the isosurface module based on atmospheric data.
Definition: mptrac.c:4893
void module_wet_depo(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Perform wet deposition calculations for air parcels.
Definition: mptrac.c:6195
void module_chem_grid(const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double tt)
Computes gridded chemical tracer concentrations (volume mixing ratio) from individual air parcel mass...
Definition: mptrac.c:3885
void module_sedi(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Simulate sedimentation of particles in the atmosphere.
Definition: mptrac.c:5899
void module_sort(const ctl_t *ctl, const met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:5927
void module_convection(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Performs convective mixing of atmospheric particles.
Definition: mptrac.c:4109
void module_bound_cond(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Apply boundary conditions to particles based on meteorological and climatological data.
Definition: mptrac.c:3789
void module_advect_init(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Initializes the advection module by setting up pressure fields.
Definition: mptrac.c:3762
void module_position(const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm, const int reflect)
Update the positions and pressure levels of atmospheric particles.
Definition: mptrac.c:5474
void module_radio_decay(const ctl_t *ctl, const cache_t *cache, atm_t *atm)
Apply radioactive decay to atmospheric tracer species.
Definition: mptrac.c:5533
void module_diff_meso(const ctl_t *ctl, cache_t *cache, const met_t *met0, const met_t *met1, atm_t *atm)
Simulate mesoscale diffusion for atmospheric particles.
Definition: mptrac.c:4273
void module_diff_turb(const ctl_t *ctl, cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Applies turbulent diffusion processes to atmospheric particles.
Definition: mptrac.c:4595
void module_timesteps(const ctl_t *ctl, cache_t *cache, const met_t *met0, atm_t *atm, const double t)
Calculate time steps for air parcels based on specified conditions.
Definition: mptrac.c:6039
void module_tracer_chem(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Simulate chemical reactions involving long-lived atmospheric tracers.
Definition: mptrac.c:6117
void module_h2o2_chem(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Perform chemical reactions involving H2O2 within cloud particles.
Definition: mptrac.c:4808
void module_diff_pbl(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Computes particle diffusion within the planetary boundary layer (PBL).
Definition: mptrac.c:4350
void module_isosurf(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Apply the isosurface module to adjust atmospheric properties.
Definition: mptrac.c:4963
void module_oh_chem(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Perform hydroxyl chemistry calculations for atmospheric particles.
Definition: mptrac.c:5390
void module_dry_depo(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Simulate dry deposition of atmospheric particles.
Definition: mptrac.c:4745
void module_radio_depo(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm, depo_t *depo)
Deposit supported radionuclides from air parcels onto the ground grid.
Definition: mptrac.c:5591
void module_kpp_chem(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
KPP chemistry module.
void module_dd(double t, const ctl_t *ctl, cache_t *cache, dd_t *dd, atm_t *atm, met_t **met)
Perform domain decomposition and exchange particles between MPI ranks.
Here is the call graph for this function:

◆ mptrac_write_atm()

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

Writes air parcel data to a file in various formats.

The mptrac_write_atm function writes the air parcel data stored in the atm structure to a file specified by filename. The format of the output file is determined by the atm_type_out field in the ctl control structure.

Parameters
filenameA string representing the name of the file to write the data to.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.
tThe current time, used for certain output formats.

The function performs the following steps:

  • Sets a timer for the write operation using the SELECT_TIMER macro.
  • Logs the beginning of the write operation with the specified filename.
  • Depending on the atm_type_out value in the ctl structure, writes the data in one of the following formats:
    • ASCII (atm_type_out == 0): Calls write_atm_asc.
    • Binary (atm_type_out == 1): Calls write_atm_bin.
    • netCDF (atm_type_out == 2): Calls write_atm_nc.
    • CLaMS trajectory data (atm_type_out == 3): Calls write_atm_clams_traj.
    • CLaMS position data (atm_type_out == 4): Calls write_atm_clams.
  • If the atm_type_out value is not supported, triggers an error message.
  • Logs various statistics about the atmospheric data, including the number of particles, time range, altitude range, pressure range, longitude range, and latitude range.
  • Logs the range for each quantity specified in the ctl structure.
Author
Lars Hoffmann

Definition at line 8177 of file mptrac.c.

8181 {
8182
8183 /* Set timer... */
8184 SELECT_TIMER("WRITE_ATM", "OUTPUT");
8185
8186 /* Write info... */
8187 LOG(1, "Write atmospheric data: %s", filename);
8188
8189 /* Write ASCII data... */
8190 if (ctl->atm_type_out == 0)
8191 write_atm_asc(filename, ctl, atm, t);
8192
8193 /* Write binary data... */
8194 else if (ctl->atm_type_out == 1)
8195 write_atm_bin(filename, ctl, atm);
8196
8197 /* Write netCDF data... */
8198 else if (ctl->atm_type_out == 2)
8199 write_atm_nc(filename, ctl, atm);
8200
8201 /* Write CLaMS trajectory data... */
8202 else if (ctl->atm_type_out == 3)
8203 write_atm_clams_traj(filename, ctl, atm, t);
8204
8205 /* Write CLaMS pos data... */
8206 else if (ctl->atm_type_out == 4)
8207 write_atm_clams(filename, ctl, atm);
8208
8209 /* Error... */
8210 else
8211 ERRMSG("Atmospheric data type not supported!");
8212
8213 /* Write info... */
8214 double mini, maxi;
8215 LOG(2, "Number of particles: %d", atm->np);
8216 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
8217 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8218 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
8219 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
8220 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
8221 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
8222 LOG(2, "%s range: %g ... %g %s",
8223 ctl->met_coord_type == 0 ? "Longitude" : "X coordinate", mini, maxi,
8224 ctl->met_coord_type == 0 ? "deg" : "m");
8225 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
8226 LOG(2, "%s range: %g ... %g %s",
8227 ctl->met_coord_type == 0 ? "Latitude" : "Y coordinate", mini, maxi,
8228 ctl->met_coord_type == 0 ? "deg" : "m");
8229 for (int iq = 0; iq < ctl->nq; iq++) {
8230 char msg[5 * LEN];
8231 sprintf(msg, "Quantity %s range: %s ... %s %s",
8232 ctl->qnt_name[iq], ctl->qnt_format[iq],
8233 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
8234 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
8235 LOG(2, msg, mini, maxi);
8236 }
8237}
void write_atm_clams_traj(const char *dirname, const ctl_t *ctl, const atm_t *atm, const double t)
Writes CLaMS trajectory data to a NetCDF file.
Definition: mptrac.c:13061
void write_atm_asc(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes air parcel data to an ASCII file or gnuplot.
Definition: mptrac.c:12857
void write_atm_clams(const char *filename, const ctl_t *ctl, const atm_t *atm)
Writes air parcel data to a NetCDF file in the CLaMS format.
Definition: mptrac.c:13005
void write_atm_bin(const char *filename, const ctl_t *ctl, const atm_t *atm)
Writes air parcel data to a binary file.
Definition: mptrac.c:12955
void write_atm_nc(const char *filename, const ctl_t *ctl, const atm_t *atm)
Writes air parcel data to a NetCDF file.
Definition: mptrac.c:13222
Here is the call graph for this function:

◆ mptrac_write_met()

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

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

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

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

Definition at line 8241 of file mptrac.c.

8244 {
8245
8246 /* Set timer... */
8247 SELECT_TIMER("WRITE_MET", "OUTPUT");
8248
8249 /* Write info... */
8250 LOG(1, "Write meteo data: %s", filename);
8251
8252 /* Check compression flags... */
8253#ifndef ZFP
8254 if (ctl->met_type == 3)
8255 ERRMSG("MPTRAC was compiled without ZFP compression!");
8256#endif
8257#ifndef ZSTD
8258 if (ctl->met_type == 4)
8259 ERRMSG("MPTRAC was compiled without ZSTD compression!");
8260#endif
8261#ifndef LZ4
8262 if (ctl->met_type == 8)
8263 ERRMSG("MPTRAC was compiled without LZ4 compression!");
8264#endif
8265#ifndef CMS
8266 if (ctl->met_type == 5)
8267 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
8268#endif
8269#ifndef SZ3
8270 if (ctl->met_type == 7)
8271 ERRMSG("MPTRAC was compiled without SZ3 compression!");
8272#endif
8273
8274 /* Write netCDF data... */
8275 if (ctl->met_type == 0)
8276 write_met_nc(filename, ctl, met);
8277
8278 /* Write binary data... */
8279 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
8280 || ctl->met_type == 7 || ctl->met_type == 8)
8281 write_met_bin(filename, ctl, met);
8282
8283 /* Not implemented... */
8284 else
8285 ERRMSG("MET_TYPE not implemented!");
8286}
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:14617
void write_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data in binary format to a specified file.
Definition: mptrac.c:14365
Here is the call graph for this function:

◆ mptrac_write_output()

void mptrac_write_output ( const char *  dirname,
const ctl_t ctl,
met_t met0,
met_t met1,
atm_t atm,
depo_t depo,
const double  t 
)

Writes various types of output data to files in a specified directory.

The mptrac_write_output function writes various types of output data to files in the directory specified by the dirname parameter. The function takes control parameters (ctl), two meteorological data structures (met0 and met1), an atmospheric data structure (atm), and a time value (t) as input.

Parameters
dirnameA string representing the directory path where output files will be written.
ctlA pointer to a ctl_t structure containing control parameters.
met0A pointer to a met_t structure representing the first set of meteorological data.
met1A pointer to a met_t structure representing the second set of meteorological data.
atmA pointer to an atm_t structure representing atmospheric data.
depoA pointer to the cumulative radionuclide ground inventories.
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 cumulative radionuclide deposition 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 8290 of file mptrac.c.

8297 {
8298
8299 char ext[10], filename[2 * LEN];
8300
8301 double r;
8302
8303 int year, mon, day, hour, min, sec;
8304
8305 /* Get time... */
8306 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
8307
8308 /* Update host... */
8309 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
8310 || (ctl->budget_basename[0] != '-'
8311 && (fmod(t, ctl->budget_dt_out) == 0 || t == ctl->t_stop))
8312 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
8313 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
8314 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
8315 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
8316 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
8317 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
8318
8319 /* Write atmospheric data... */
8320 if (ctl->atm_basename[0] != '-' &&
8321 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
8322 if (ctl->atm_type_out == 0)
8323 sprintf(ext, "tab");
8324 else if (ctl->atm_type_out == 1)
8325 sprintf(ext, "bin");
8326 else if (ctl->atm_type_out >= 2)
8327 sprintf(ext, "nc");
8328 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
8329 dirname, ctl->atm_basename, year, mon, day, hour, min, sec, ext);
8330 mptrac_write_atm(filename, ctl, atm, t);
8331 }
8332
8333 /* Write gridded data... */
8334 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
8335 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
8336 dirname, ctl->grid_basename, year, mon, day, hour, min, sec,
8337 ctl->grid_type == 0 ? "tab" : "nc");
8338 write_grid(filename, ctl, met0, met1, atm, t);
8339 }
8340
8341 /* Write mass budget data... */
8342 if (ctl->budget_basename[0] != '-'
8343 && (fmod(t, ctl->budget_dt_out) == 0 || t == ctl->t_stop)) {
8344 sprintf(filename, "%s/%s.tab", dirname, ctl->budget_basename);
8345 write_budget(filename, ctl, atm, t);
8346 }
8347
8348 /* Write radioactive deposition data... */
8349 if (ctl->depo_basename[0] != '-'
8350 && (fmod(t, ctl->depo_dt_out) == 0 || t == ctl->t_stop)) {
8351#ifdef _OPENACC
8352#pragma acc update host(depo[:1])
8353#endif
8354 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
8355 dirname, ctl->depo_basename, year, mon, day, hour, min, sec,
8356 ctl->depo_type == 0 ? "tab" : "nc");
8357 write_depo(filename, ctl, depo, t);
8358 }
8359
8360 /* Write CSI data... */
8361 if (ctl->csi_basename[0] != '-') {
8362 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
8363 write_csi(filename, ctl, atm, t);
8364 }
8365
8366 /* Write ensemble data... */
8367 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
8368 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.tab",
8369 dirname, ctl->ens_basename, year, mon, day, hour, min, sec);
8370 write_ens(filename, ctl, atm, t);
8371 }
8372
8373 /* Write profile data... */
8374 if (ctl->prof_basename[0] != '-') {
8375 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
8376 write_prof(filename, ctl, met0, met1, atm, t);
8377 }
8378
8379 /* Write sample data... */
8380 if (ctl->sample_basename[0] != '-') {
8381 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
8382 write_sample(filename, ctl, met0, met1, atm, t);
8383 }
8384
8385 /* Write station data... */
8386 if (ctl->stat_basename[0] != '-') {
8387 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
8388 write_station(filename, ctl, atm, t);
8389 }
8390
8391 /* Write VTK data... */
8392 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
8393 static int nvtk;
8394 if (t == ctl->t_start)
8395 nvtk = 0;
8396 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
8397 write_vtk(filename, ctl, atm, t);
8398 }
8399}
void write_depo(const char *filename, const ctl_t *ctl, const depo_t *depo, const double t)
Convert cumulative ground inventories to Bq m^-2 and write them.
Definition: mptrac.c:13752
void mptrac_write_atm(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes air parcel data to a file in various formats.
Definition: mptrac.c:8177
void write_ens(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes ensemble data to a file.
Definition: mptrac.c:13652
void write_prof(const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
Writes profile data to a specified file.
Definition: mptrac.c:14860
void mptrac_update_host(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
Updates host memory for specified data structures.
Definition: mptrac.c:8121
void write_station(const char *filename, const ctl_t *ctl, atm_t *atm, const double t)
Writes station data to a specified file.
Definition: mptrac.c:15260
void write_budget(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes a time series of the atmospheric tracer mass budget.
Definition: mptrac.c:13271
void write_vtk(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes VTK (Visualization Toolkit) data to a specified file.
Definition: mptrac.c:15349
void write_sample(const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
Writes sample data to a specified file.
Definition: mptrac.c:15095
void write_grid(const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
Writes grid data to a file in ASCII or netCDF format.
Definition: mptrac.c:13929
void write_csi(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes Critical Success Index (CSI) data to a file.
Definition: mptrac.c:13365
Here is the call graph for this function:

◆ mptrac_update_device()

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

Updates device memory for specified data structures.

This function updates the GPU memory with the data from the provided host data structures (ctl, cache, clim, atm) using OpenACC directives. It ensures that the host data is transferred to the device for further computation.

Parameters
[in]ctlPointer to the ctl_t structure. If not NULL, the corresponding device memory for ctl is updated.
[in]cachePointer to the cache_t structure. If not NULL, the corresponding device memory for cache is updated.
[in]climPointer to the clim_t structure. If not NULL, the corresponding device memory for clim is updated.
[in]met0Pointer to the first met_t structure. If not NULL, the corresponding device memory for met0 is updated.
[in]met1Pointer to the second met_t structure. If not NULL, the corresponding device memory for met1 is updated.
[in]atmPointer to the atm_t structure. If not NULL, the corresponding device memory for atm is updated.
Note
The function assumes that OpenACC is enabled and uses the #pragma acc update directive for device memory synchronization. Each update operation is wrapped with a timer labeled as "UPDATE_DEVICE" for performance tracking.
Warning
Ensure that the pointers passed to this function are valid and properly initialized before calling this function. Passing invalid or uninitialized pointers may lead to undefined behavior.
Author
Lars Hoffmann

Definition at line 8065 of file mptrac.c.

8071 {
8072
8073 /* Update GPU... */
8074 if (ctl != NULL) {
8075#ifdef _OPENACC
8076 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8077#pragma acc update device(ctl[:1])
8078#endif
8079 }
8080
8081 if (cache != NULL) {
8082#ifdef _OPENACC
8083 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8084#pragma acc update device(cache[:1])
8085#endif
8086 }
8087
8088 if (clim != NULL) {
8089#ifdef _OPENACC
8090 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8091#pragma acc update device(clim[:1])
8092#endif
8093 }
8094
8095 if (met0 != NULL) {
8096#ifdef _OPENACC
8097 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8098 met_t *met0up = *met0;
8099#pragma acc update device(met0up[:1])
8100#endif
8101 }
8102
8103 if (met1 != NULL) {
8104#ifdef _OPENACC
8105 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8106 met_t *met1up = *met1;
8107#pragma acc update device(met1up[:1])
8108#endif
8109 }
8110
8111 if (atm != NULL) {
8112#ifdef _OPENACC
8113 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8114#pragma acc update device(atm[:1])
8115#endif
8116 }
8117}

◆ mptrac_update_host()

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

Updates host memory for specified data structures.

This function transfers data from the device (GPU) memory back to the host memory for the provided data structures (ctl, cache, clim, atm) using OpenACC directives. It ensures that the latest data from the device is synchronized with the host.

Parameters
[in]ctlPointer to the ctl_t structure. If not NULL, the corresponding host memory for ctl is updated from the device.
[in]cachePointer to the cache_t structure. If not NULL, the corresponding host memory for cache is updated from the device.
[in]climPointer to the clim_t structure. If not NULL, the corresponding host memory for clim is updated from the device.
[in]met0Pointer to the first met_t structure. If not NULL, the corresponding host memory for met0 is updated.
[in]met1Pointer to the second met_t structure. If not NULL, the corresponding host memory for met1 is updated.
[in]atmPointer to the atm_t structure. If not NULL, the corresponding host memory for atm is updated from the device.
Note
The function assumes that OpenACC is enabled and uses the #pragma acc update directive for host memory synchronization. Each update operation is wrapped with a timer labeled as "UPDATE_HOST" for performance tracking.
Warning
Ensure that the pointers passed to this function are valid and properly initialized before calling this function
Author
Lars Hoffmann

Definition at line 8121 of file mptrac.c.

8127 {
8128
8129 /* Update GPU... */
8130 if (ctl != NULL) {
8131#ifdef _OPENACC
8132 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8133#pragma acc update host(ctl[:1])
8134#endif
8135 }
8136
8137 if (cache != NULL) {
8138#ifdef _OPENACC
8139 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8140#pragma acc update host(cache[:1])
8141#endif
8142 }
8143
8144 if (clim != NULL) {
8145#ifdef _OPENACC
8146 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8147#pragma acc update host(clim[:1])
8148#endif
8149 }
8150
8151 if (met0 != NULL) {
8152#ifdef _OPENACC
8153 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8154 met_t *met0up = *met0;
8155#pragma acc update host(met0up[:1])
8156#endif
8157 }
8158
8159 if (met1 != NULL) {
8160#ifdef _OPENACC
8161 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8162 met_t *met1up = *met1;
8163#pragma acc update host(met1up[:1])
8164#endif
8165 }
8166
8167 if (atm != NULL) {
8168#ifdef _OPENACC
8169 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8170#pragma acc update host(atm[:1])
8171#endif
8172 }
8173}

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

8406 {
8407
8408 /* Check water vapor volume mixing ratio... */
8409 const double h2o_help = MAX(h2o, 0.1e-6);
8410
8411 /* Calculate T_NAT... */
8412 const double p_hno3 = hno3 * p / 1.333224;
8413 const double p_h2o = h2o_help * p / 1.333224;
8414 const double a = 0.009179 - 0.00088 * log10(p_h2o);
8415 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
8416 const double c = -11397.0 / a;
8417 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
8418 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
8419 if (x2 > 0)
8420 tnat = x2;
8421
8422 return tnat;
8423}

◆ pbl_weight()

double pbl_weight ( const ctl_t ctl,
const atm_t atm,
const int  ip,
const double  pbl,
const double  ps 
)

Computes a weighting factor based on planetary boundary layer pressure.

This function calculates a weighting factor that determines the contribution of a pressure level to processes within the planetary boundary layer. The factor is based on the relative position of the pressure within a linear transition range defined by pbl, ps, and TURB_PBL_TRANS, expressed as a fraction of the PBL pressure thickness (ps - pbl).

Parameters
ctlPointer to the control structure containing configuration parameters.
atmPointer to the atmospheric data structure containing pressure levels.
ipIndex of the pressure level in the atmospheric data array.
pblPressure at the planetary boundary layer.
psSurface pressure.
Returns
Weighting factor for the specified pressure level:
  • Returns 1.0 if the pressure is above the upper boundary (p0).
  • Returns 0.0 if the pressure is below the lower boundary (p1).
  • Returns a linearly interpolated value between 1.0 and 0.0 for pressures within the transition range.
Author
Lars Hoffmann

Definition at line 8427 of file mptrac.c.

8432 {
8433
8434 /* Get pressure range... */
8435 const double p1 = pbl - ctl->turb_pbl_trans * (ps - pbl);
8436 const double p0 = pbl;
8437
8438 /* Get weighting factor... */
8439 if (atm->p[ip] > p0)
8440 return 1;
8441 else if (atm->p[ip] < p1)
8442 return 0;
8443 else
8444 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
8445}

◆ read_atm_asc()

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

Reads air parcel data from an ASCII file and populates the given atmospheric structure.

This function reads air parcel data from an ASCII file and stores the data in the provided atm_t structure. It reads each line of the file, extracts the necessary data fields, and converts the altitude to pressure.

Parameters
filenameThe name of the ASCII file containing the atmospheric data.
ctlA pointer to the control structure (ctl_t) that specifies the number of quantities.
atmA pointer to the atmospheric structure (atm_t) that will be populated with the data.
Returns
Returns 1 on success, and 0 on failure.

This function performs the following steps:

  • Attempts to open the specified file for reading.
  • Logs a warning and returns 0 if the file cannot be opened.
  • Reads each line of the file and extracts data values for time, altitude, longitude, latitude, and other specified quantities.
  • Converts the altitude to pressure.
  • Increments the data point counter.
  • Checks if the number of data points exceeds the maximum allowed (NP) and logs an error message if so.
  • Closes the file after reading all data.
  • Returns 1 to indicate successful data reading.

The function utilizes several macros and helper functions:

  • WARN for logging warnings.
  • ERRMSG for handling error messages.
  • TOK for tokenizing and reading values from the line.
  • P for converting altitude to pressure.
Author
Lars Hoffmann

Definition at line 8449 of file mptrac.c.

8452 {
8453
8454 /* Open file... */
8455 FILE *in;
8456 if (!(in = fopen(filename, "r"))) {
8457 WARN("Cannot open file!");
8458 return 0;
8459 }
8460
8461 /* Read line... */
8462 char line[LEN];
8463 while (fgets(line, LEN, in)) {
8464
8465 /* Read data... */
8466 char *tok;
8467 TOK(line, tok, "%lg", atm->time[atm->np]);
8468 TOK(NULL, tok, "%lg", atm->p[atm->np]);
8469 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
8470 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
8471 for (int iq = 0; iq < ctl->nq; iq++)
8472 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
8473
8474 /* Convert altitude to pressure... */
8475 atm->p[atm->np] = P(atm->p[atm->np]);
8476
8477 /* Increment data point counter... */
8478 if ((++atm->np) > NP)
8479 ERRMSG("Too many data points!");
8480 }
8481
8482 /* Close file... */
8483 fclose(in);
8484
8485 /* Return success... */
8486 return 1;
8487}
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:2184

◆ read_atm_bin()

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

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

This function reads air parcel data from a binary file and stores the data in the provided atm_t structure. It checks the version of the binary data, reads the data values, and verifies the integrity of the data read.

Parameters
filenameThe name of the binary file containing the atmospheric data.
ctlA pointer to the control structure (ctl_t) that specifies the number of quantities.
atmA pointer to the atmospheric structure (atm_t) that will be populated with the data.
Returns
Returns 1 on success, and 0 on failure.

This function performs the following steps:

  • Attempts to open the specified file for reading.
  • Returns 0 if the file cannot be opened.
  • Checks the version of the binary data and logs an error message if the version is incorrect.
  • Reads the number of data points (np).
  • Reads the data arrays for time, pressure, longitude, latitude, and other specified quantities.
  • Checks a final flag to ensure the data was read correctly.
  • Logs an error message if the final flag is incorrect.
  • Closes the file after reading all data.
  • Returns 1 to indicate successful data reading.

The function utilizes several macros and helper functions:

  • ERRMSG for handling error messages.
  • FREAD for reading data from the binary file.
Author
Lars Hoffmann

Definition at line 8491 of file mptrac.c.

8494 {
8495
8496 /* Open file... */
8497 FILE *in;
8498 if (!(in = fopen(filename, "r")))
8499 return 0;
8500
8501 /* Check version of binary data... */
8502 int version;
8503 FREAD(&version, int,
8504 1,
8505 in);
8506 if (version != 100)
8507 ERRMSG("Wrong version of binary data!");
8508
8509 /* Read data... */
8510 FREAD(&atm->np, int,
8511 1,
8512 in);
8513 FREAD(atm->time, double,
8514 (size_t) atm->np,
8515 in);
8516 FREAD(atm->p, double,
8517 (size_t) atm->np,
8518 in);
8519 FREAD(atm->lon, double,
8520 (size_t) atm->np,
8521 in);
8522 FREAD(atm->lat, double,
8523 (size_t) atm->np,
8524 in);
8525 for (int iq = 0; iq < ctl->nq; iq++)
8526 FREAD(atm->q[iq], double,
8527 (size_t) atm->np,
8528 in);
8529
8530 /* Read final flag... */
8531 int final;
8532 FREAD(&final, int,
8533 1,
8534 in);
8535 if (final != 999)
8536 ERRMSG("Error while reading binary data!");
8537
8538 /* Close file... */
8539 fclose(in);
8540
8541 /* Return success... */
8542 return 1;
8543}

◆ read_atm_clams()

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

Reads atmospheric data from a CLAMS NetCDF file.

This function opens a NetCDF file, reads various atmospheric parameters, and stores them in the provided atm_t structure. It handles both zeta and pressure coordinate systems depending on the control settings.

Parameters
[in]filenamePath to the NetCDF file containing atmospheric data.
[in]ctlPointer to the control structure containing configuration settings.
[out]atmPointer to the atmospheric data structure where the data will be stored.
Returns
Returns 1 on success, 0 on failure.
  • Opens the NetCDF file in read-only mode.
  • Retrieves the number of particles (NPARTS).
  • Reads initial time (TIME_INIT) or falls back to time if unavailable.
  • Depending on ctl->advect_vert_coord, reads ZETA and optionally PRESS, or reads PRESS_INIT with fallback to PRESS.
  • Reads longitude (LON) and latitude (LAT).
  • Closes the NetCDF file before returning.
Author
Jan Clemens

Definition at line 8547 of file mptrac.c.

8550 {
8551
8552 if (ctl->met_coord_type != 0)
8553 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
8554
8555 int ncid, varid;
8556
8557 /* Open file... */
8558 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8559 return 0;
8560
8561 /* Get dimensions... */
8562 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
8563
8564 /* Get time... */
8565 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
8566 NC(nc_get_var_double(ncid, varid, atm->time));
8567 } else {
8568 WARN("TIME_INIT not found use time instead!");
8569 double time_init;
8570 NC_GET_DOUBLE("time", &time_init, 1);
8571 for (int ip = 0; ip < atm->np; ip++) {
8572 atm->time[ip] = time_init;
8573 }
8574 }
8575
8576 /* Read zeta coordinate, pressure is optional... */
8577 if (ctl->advect_vert_coord == 1) {
8578 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
8579 NC_GET_DOUBLE("PRESS", atm->p, 0);
8580 }
8581
8582 /* Read pressure, zeta coordinate is optional... */
8583 else {
8584 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
8585 NC(nc_get_var_double(ncid, varid, atm->p));
8586 } else {
8587 WARN("PRESS_INIT not found use PRESS instead!");
8588 nc_inq_varid(ncid, "PRESS", &varid);
8589 NC(nc_get_var_double(ncid, varid, atm->p));
8590 }
8591 }
8592
8593 /* Read further quantities if requested... */
8594 for (int iq = 0; iq < ctl->nq; iq++)
8595 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8596
8597 /* Read longitude and latitude... */
8598 NC_GET_DOUBLE("LON", atm->lon, 1);
8599 NC_GET_DOUBLE("LAT", atm->lat, 1);
8600
8601 /* Close file... */
8602 NC(nc_close(ncid));
8603
8604 /* Return success... */
8605 return 1;
8606}
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1507

◆ read_atm_nc()

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

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

This function reads air parcel data from a netCDF file and stores the data in the provided atm_t structure. It retrieves the dimensions, geolocations (time, pressure, longitude, latitude), and specified variables from the file.

Parameters
filenameThe name of the netCDF file containing the atmospheric data.
ctlA pointer to the control structure (ctl_t) that specifies the number of quantities and their names.
atmA pointer to the atmospheric structure (atm_t) that will be populated with the data.
Returns
Returns 1 on success, and 0 on failure.

This function performs the following steps:

  • Attempts to open the specified netCDF file for reading.
  • Returns 0 if the file cannot be opened.
  • Retrieves the number of observations (np) from the "obs" dimension.
  • Reads the geolocation data arrays for time, pressure, longitude, and latitude.
  • Reads the specified variables into the corresponding arrays in the atm_t structure.
  • Closes the netCDF file after reading all data.
  • Returns 1 to indicate successful data reading.

The function utilizes several macros and helper functions:

  • NC_INQ_DIM for inquiring about dimensions in the netCDF file.
  • NC_GET_DOUBLE for reading double values from the netCDF file.
  • NC for checking netCDF function return values.
Author
Lars Hoffmann

Definition at line 8610 of file mptrac.c.

8613 {
8614
8615 int ncid, varid;
8616
8617 /* Open file... */
8618 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8619 return 0;
8620
8621 /* Get dimensions... */
8622 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
8623
8624 /* Read geolocations... */
8625 NC_GET_DOUBLE("time", atm->time, 1);
8626 NC_GET_DOUBLE("press", atm->p, 1);
8627 NC_GET_DOUBLE("lon", atm->lon, 1);
8628 NC_GET_DOUBLE("lat", atm->lat, 1);
8629
8630 /* Read variables... */
8631 for (int iq = 0; iq < ctl->nq; iq++)
8632 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8633
8634 /* Close file... */
8635 NC(nc_close(ncid));
8636
8637 /* Return success... */
8638 return 1;
8639}

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

8645 {
8646
8647 int ncid, varid;
8648
8649 /* Write info... */
8650 LOG(1, "Read photolysis rates: %s", filename);
8651
8652 /* Open netCDF file... */
8653 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8654 WARN("Photolysis rate data are missing!");
8655 return;
8656 }
8657
8658 /* Read pressure data... */
8659 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
8660 NC_GET_DOUBLE("press", photo->p, 1);
8661 if (photo->p[0] < photo->p[1])
8662 ERRMSG("Pressure data are not descending!");
8663
8664 /* Read total column ozone data... */
8665 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
8666 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
8667 if (photo->o3c[0] > photo->o3c[1])
8668 ERRMSG("Total column ozone data are not ascending!");
8669
8670 /* Read solar zenith angle data... */
8671 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
8672 NC_GET_DOUBLE("sza", photo->sza, 1);
8673 if (photo->sza[0] > photo->sza[1])
8674 ERRMSG("Solar zenith angle data are not ascending!");
8675
8676 /* Read data... */
8677 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
8678 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
8679 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
8680 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
8681 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
8682 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
8683 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
8684 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
8685 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
8686
8687 /* Close netCDF file... */
8688 NC(nc_close(ncid));
8689
8690 /* Write info... */
8691 LOG(2, "Number of pressure levels: %d", photo->np);
8692 LOG(2, "Altitude levels: %g, %g ... %g km",
8693 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
8694 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8695 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
8696 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
8697 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
8698 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
8699 RAD2DEG(photo->sza[photo->nsza - 1]));
8700 LOG(2, "Number of total column ozone values: %d", photo->no3c);
8701 LOG(2, "Total column ozone: %g, %g ... %g DU",
8702 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
8703 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
8704 photo->n2o[0][0][0], photo->n2o[1][0][0],
8705 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8706 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
8707 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
8708 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8709 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
8710 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
8711 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8712 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
8713 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
8714 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8715 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
8716 photo->o2[0][0][0], photo->o2[1][0][0],
8717 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8718 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
8719 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
8720 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8721 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
8722 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
8723 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8724 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
8725 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
8726 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8727 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
8728 photo->h2o[0][0][0], photo->h2o[1][0][0],
8729 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8730}
void read_clim_photo_help(const int ncid, const char *varname, const clim_photo_t *photo, double var[CP][CSZA][CO3])
Reads a 3D climatological photochemistry variable from a NetCDF file.
Definition: mptrac.c:8734
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:608
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:603
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:613
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3732
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3729
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3738
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3741
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3735
Here is the call graph for this function:

◆ read_clim_photo_help()

void read_clim_photo_help ( const int  ncid,
const char *  varname,
const clim_photo_t photo,
double  var[CP][CSZA][CO3] 
)

Reads a 3D climatological photochemistry variable from a NetCDF file.

This function reads a variable from a NetCDF file into a 3D array based on the dimensions provided by the clim_photo_t structure.

Parameters
[in]ncidNetCDF file ID.
[in]varnameName of the variable to read from the NetCDF file.
[in]photoPointer to a structure defining the data dimensions (np, nsza, no3c).
[out]var3D array to store the read data, with dimensions [CP][CSZA][CO3].
Note
Allocates temporary memory for reading and copies data into the provided array. The memory is freed after the data is copied.
Author
Lars Hoffmann

Definition at line 8734 of file mptrac.c.

8738 {
8739
8740 /* Allocate... */
8741 double *help;
8742 ALLOC(help, double,
8743 photo->np * photo->nsza * photo->no3c);
8744
8745 /* Read variable... */
8746 int varid;
8747 NC_GET_DOUBLE(varname, help, 1);
8748
8749 /* Copy data... */
8750 for (int ip = 0; ip < photo->np; ip++)
8751 for (int is = 0; is < photo->nsza; is++)
8752 for (int io = 0; io < photo->no3c; io++)
8753 var[ip][is][io] =
8754 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
8755
8756 /* Free... */
8757 free(help);
8758}

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

8764 {
8765
8766 /* Write info... */
8767 LOG(1, "Read climatological time series: %s", filename);
8768
8769 /* Open file... */
8770 FILE *in;
8771 if (!(in = fopen(filename, "r"))) {
8772 WARN("Cannot open file!");
8773 return 0;
8774 }
8775
8776 /* Read data... */
8777 char line[LEN];
8778 int nh = 0;
8779 while (fgets(line, LEN, in))
8780 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
8781
8782 /* Convert years to seconds... */
8783 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
8784
8785 /* Check data... */
8786 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
8787 ERRMSG("Time series must be ascending!");
8788
8789 /* Count time steps... */
8790 if ((++nh) >= CTS)
8791 ERRMSG("Too many data points!");
8792 }
8793
8794 /* Close file... */
8795 fclose(in);
8796
8797 /* Check number of data points... */
8798 ts->ntime = nh;
8799 if (nh < 2)
8800 ERRMSG("Not enough data points!");
8801
8802 /* Write info... */
8803 LOG(2, "Number of time steps: %d", ts->ntime);
8804 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
8805 ts->time[nh - 1]);
8806 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
8807 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
8808 (size_t) nh));
8809
8810 /* Exit success... */
8811 return 1;
8812}
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:623

◆ read_clim_zm()

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

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

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

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

The function performs the following steps:

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

Definition at line 8816 of file mptrac.c.

8819 {
8820
8821 int ncid, varid, it, iy, iz, iz2, nt;
8822
8823 double *help, varmin = 1e99, varmax = -1e99;
8824
8825 /* Write info... */
8826 LOG(1, "Read %s data: %s", varname, filename);
8827
8828 /* Open netCDF file... */
8829 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8830 WARN("%s climatology data are missing!", varname);
8831 return;
8832 }
8833
8834 /* Read pressure data... */
8835 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
8836 NC_GET_DOUBLE("press", zm->p, 1);
8837 if (zm->p[0] < zm->p[1])
8838 ERRMSG("Pressure data are not descending!");
8839
8840 /* Read latitudes... */
8841 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
8842 NC_GET_DOUBLE("lat", zm->lat, 1);
8843 if (zm->lat[0] > zm->lat[1])
8844 ERRMSG("Latitude data are not ascending!");
8845
8846 /* Set time data (for monthly means)... */
8847 zm->ntime = 12;
8848 zm->time[0] = 1209600.00;
8849 zm->time[1] = 3888000.00;
8850 zm->time[2] = 6393600.00;
8851 zm->time[3] = 9072000.00;
8852 zm->time[4] = 11664000.00;
8853 zm->time[5] = 14342400.00;
8854 zm->time[6] = 16934400.00;
8855 zm->time[7] = 19612800.00;
8856 zm->time[8] = 22291200.00;
8857 zm->time[9] = 24883200.00;
8858 zm->time[10] = 27561600.00;
8859 zm->time[11] = 30153600.00;
8860
8861 /* Check number of timesteps... */
8862 NC_INQ_DIM("time", &nt, 12, 12, 1);
8863
8864 /* Read data... */
8865 ALLOC(help, double,
8866 zm->nlat * zm->np * zm->ntime);
8867 NC_GET_DOUBLE(varname, help, 1);
8868 for (it = 0; it < zm->ntime; it++)
8869 for (iz = 0; iz < zm->np; iz++)
8870 for (iy = 0; iy < zm->nlat; iy++)
8871 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
8872 free(help);
8873
8874 /* Fix data gaps... */
8875 for (it = 0; it < zm->ntime; it++)
8876 for (iy = 0; iy < zm->nlat; iy++)
8877 for (iz = 0; iz < zm->np; iz++) {
8878 if (zm->vmr[it][iz][iy] < 0) {
8879 for (iz2 = 0; iz2 < zm->np; iz2++)
8880 if (zm->vmr[it][iz2][iy] >= 0) {
8881 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8882 break;
8883 }
8884 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
8885 if (zm->vmr[it][iz2][iy] >= 0) {
8886 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8887 break;
8888 }
8889 }
8890 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
8891 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
8892 }
8893
8894 /* Close netCDF file... */
8895 NC(nc_close(ncid));
8896
8897 /* Write info... */
8898 LOG(2, "Number of time steps: %d", zm->ntime);
8899 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
8900 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
8901 LOG(2, "Number of pressure levels: %d", zm->np);
8902 LOG(2, "Altitude levels: %g, %g ... %g km",
8903 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
8904 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
8905 zm->p[1], zm->p[zm->np - 1]);
8906 LOG(2, "Number of latitudes: %d", zm->nlat);
8907 LOG(2, "Latitudes: %g, %g ... %g deg",
8908 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
8909 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
8910 varmax);
8911}
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:598

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

8919 {
8920
8921 /* Write info... */
8922 LOG(1, "Read kernel function: %s", filename);
8923
8924 /* Open file... */
8925 FILE *in;
8926 if (!(in = fopen(filename, "r")))
8927 ERRMSG("Cannot open file!");
8928
8929 /* Read data... */
8930 char line[LEN];
8931 int n = 0;
8932 while (fgets(line, LEN, in))
8933 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
8934 if (n > 0 && kz[n] < kz[n - 1])
8935 ERRMSG("Height levels must be ascending!");
8936 if ((++n) >= EP)
8937 ERRMSG("Too many height levels!");
8938 }
8939
8940 /* Close file... */
8941 fclose(in);
8942
8943 /* Check number of data points... */
8944 *nk = n;
8945 if (n < 2)
8946 ERRMSG("Not enough height levels!");
8947
8948 /* Normalize kernel function... */
8949 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
8950 for (int iz = 0; iz < n; iz++)
8951 kw[iz] /= kmax;
8952}

◆ read_met_bin()

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

Reads meteorological data from a binary file.

This function reads meteorological data from a binary file and populates the provided met_t structure with the data. It checks the binary file's format version and met_type, ensuring compatibility with the control structure (ctl_t). The function reads time, grid, surface data, and multi-level data, and supports different binary file versions.

Parameters
filenameA constant character pointer representing the name of the binary file to read the meteorological data from.
ctlA pointer to a ctl_t structure that holds control parameters such as the expected met_type and other configuration options.
metA pointer to a met_t structure that will store the meteorological data read from the binary file.
Note
  • The function logs the progress and details of the read operation, such as time, number of longitudes, latitudes, levels, and various meteorological variables.
  • It uses the FREAD macro for safe binary reading operations, which checks the integrity of the read operation.
  • The function reads and verifies the met_type and binary file version to ensure compatibility.
  • Supported binary file versions include 100, 101, and 102, each of which may include additional variables (e.g., LSM, SST, RWC, SWC, and CC).
Warning
  • The function will raise an error if the met_type in the file does not match the ctl->met_type.
  • It will raise an error if the binary file version is not supported.
  • If the dimensions of the data (e.g., number of longitudes, latitudes, or levels) are outside the expected range, an error will be raised.
Author
Lars Hoffmann

Definition at line 8956 of file mptrac.c.

8959 {
8960
8961 FILE *in;
8962
8963 double r;
8964
8965 int year, mon, day, hour, min, sec;
8966
8967 /* Set timer... */
8968 SELECT_TIMER("READ_MET_BIN", "INPUT");
8969
8970 /* Open file... */
8971 if (!(in = fopen(filename, "r"))) {
8972 WARN("Cannot open file!");
8973 return 0;
8974 }
8975
8976 /* Check type of binary data... */
8977 int met_type;
8978 FREAD(&met_type, int,
8979 1,
8980 in);
8981 if (met_type != ctl->met_type)
8982 ERRMSG("Wrong MET_TYPE of binary data!");
8983
8984 /* Check version of binary data... */
8985 int version;
8986 FREAD(&version, int,
8987 1,
8988 in);
8989 if (version != 104)
8990 ERRMSG("Wrong version of binary data!");
8991
8992 /* Read time... */
8993 FREAD(&met->time, double,
8994 1,
8995 in);
8996 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8997 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8998 met->time, year, mon, day, hour, min);
8999 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
9000 || day < 1 || day > 31 || hour < 0 || hour > 23)
9001 ERRMSG("Error while reading time!");
9002
9003 /* Read dimensions... */
9004 met->coord_type = ctl->met_coord_type;
9005
9006 FREAD(&met->nx, int,
9007 1,
9008 in);
9009 LOG(2, "Number of %s: %d",
9010 (met->coord_type == 0) ? "longitudes" : "x coordinates", met->nx);
9011 if (met->nx < 2 || met->nx > EX)
9012 ERRMSG(met->coord_type == 0
9013 ? "Number of longitudes out of range!"
9014 : "Number of x coordinates out of range!");
9015
9016 FREAD(&met->ny, int,
9017 1,
9018 in);
9019 LOG(2, "Number of %s: %d",
9020 (met->coord_type == 0) ? "latitudes" : "y coordinates", met->ny);
9021 if (met->ny < 2 || met->ny > EY)
9022 ERRMSG(met->coord_type == 0
9023 ? "Number of latitudes out of range!"
9024 : "Number of y coordinates out of range!");
9025
9026 FREAD(&met->np, int,
9027 1,
9028 in);
9029 LOG(2, "Number of levels: %d", met->np);
9030 if (met->np < 2 || met->np > EP)
9031 ERRMSG("Number of levels out of range!");
9032
9033 /* Read grid... */
9034 FREAD(met->lon, double,
9035 (size_t) met->nx,
9036 in);
9037 LOG(2, "%s: %g, %g ... %g %s",
9038 met->coord_type == 0 ? "Longitudes" : "X coordinates",
9039 met->lon[0], met->lon[1], met->lon[met->nx - 1],
9040 met->coord_type == 0 ? "deg" : "m");
9041
9042 FREAD(met->lat, double,
9043 (size_t) met->ny,
9044 in);
9045 LOG(2, "%s: %g, %g ... %g %s",
9046 met->coord_type == 0 ? "Latitudes" : "Y coordinates",
9047 met->lat[0], met->lat[1], met->lat[met->ny - 1],
9048 met->coord_type == 0 ? "deg" : "m");
9049
9050 FREAD(met->p, double,
9051 (size_t) met->np,
9052 in);
9053 LOG(2, "Altitude levels: %g, %g ... %g km",
9054 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
9055 LOG(2, "Pressure levels: %g, %g ... %g hPa",
9056 met->p[0], met->p[1], met->p[met->np - 1]);
9057
9058 /* Read surface data... */
9059 read_met_bin_2d(in, met, met->ps, "PS");
9060 read_met_bin_2d(in, met, met->ts, "TS");
9061 read_met_bin_2d(in, met, met->zs, "ZS");
9062 read_met_bin_2d(in, met, met->us, "US");
9063 read_met_bin_2d(in, met, met->vs, "VS");
9064 read_met_bin_2d(in, met, met->ess, "ESS");
9065 read_met_bin_2d(in, met, met->nss, "NSS");
9066 read_met_bin_2d(in, met, met->shf, "SHF");
9067 read_met_bin_2d(in, met, met->lsm, "LSM");
9068 read_met_bin_2d(in, met, met->sst, "SST");
9069 read_met_bin_2d(in, met, met->pbl, "PBL");
9070 read_met_bin_2d(in, met, met->pt, "PT");
9071 read_met_bin_2d(in, met, met->tt, "TT");
9072 read_met_bin_2d(in, met, met->zt, "ZT");
9073 read_met_bin_2d(in, met, met->h2ot, "H2OT");
9074 read_met_bin_2d(in, met, met->pct, "PCT");
9075 read_met_bin_2d(in, met, met->pcb, "PCB");
9076 read_met_bin_2d(in, met, met->cl, "CL");
9077 read_met_bin_2d(in, met, met->plcl, "PLCL");
9078 read_met_bin_2d(in, met, met->plfc, "PLFC");
9079 read_met_bin_2d(in, met, met->pel, "PEL");
9080 read_met_bin_2d(in, met, met->cape, "CAPE");
9081 read_met_bin_2d(in, met, met->cin, "CIN");
9082 read_met_bin_2d(in, met, met->o3c, "O3C");
9083
9084 /* Read level data... */
9085 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
9086 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
9087 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
9088 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
9089 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
9090 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
9091 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
9092 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
9093 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
9094 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
9095 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
9096 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
9097 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
9098
9099 /* Read final flag... */
9100 int final;
9101 FREAD(&final, int,
9102 1,
9103 in);
9104 if (final != 999)
9105 ERRMSG("Error while reading binary data!");
9106
9107 /* Close file... */
9108 fclose(in);
9109
9110 /* Return success... */
9111 return 1;
9112}
void read_met_bin_2d(FILE *in, const met_t *met, float var[EX][EY], const char *varname)
Reads a 2-dimensional meteorological variable from a binary file and stores it in the provided array.
Definition: mptrac.c:9116
void read_met_bin_3d(FILE *in, const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname, const float bound_min, const float bound_max)
Reads 3D meteorological data from a binary file, potentially using different compression methods.
Definition: mptrac.c:9145
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3944
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3932
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:4004
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3974
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3968
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3950
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3926
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:4001
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3914
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:4013
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3908
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3920
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3953
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3965
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3971
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3959
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3941
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3935
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3917
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3929
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:4007
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3947
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3992
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3956
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3923
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3962
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:4010
Here is the call graph for this function:

◆ read_met_bin_2d()

void read_met_bin_2d ( FILE *  in,
const met_t met,
float  var[EX][EY],
const char *  varname 
)

Reads a 2-dimensional meteorological variable from a binary file and stores it in the provided array.

This function reads a 2-dimensional meteorological variable from a binary file, which is assumed to be uncompressed, and stores it in the provided 2-dimensional array var. The variable name is used for logging purposes to identify the data being read.

Parameters
inA pointer to the FILE structure representing the binary file to read from.
metA pointer to a structure containing meteorological data.
varA 2-dimensional array to store the read variable.
varnameA string containing the name of the variable being read.

The function performs the following steps:

  • Allocates memory for a temporary buffer to hold the uncompressed data.
  • Logs information about the variable being read from the file.
  • Reads the uncompressed data from the file into the temporary buffer.
  • Copies the data from the temporary buffer to the provided 2-dimensional array.
  • Frees the memory allocated for the temporary buffer.
Note
The function assumes that the binary file contains uncompressed data and reads the data directly into the provided array without any additional processing.
Author
Lars Hoffmann

Definition at line 9116 of file mptrac.c.

9120 {
9121
9122 float *help;
9123
9124 /* Allocate... */
9125 ALLOC(help, float,
9126 EX * EY);
9127
9128 /* Read uncompressed... */
9129 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
9130 FREAD(help, float,
9131 (size_t) (met->nx * met->ny),
9132 in);
9133
9134 /* Copy data... */
9135 for (int ix = 0; ix < met->nx; ix++)
9136 for (int iy = 0; iy < met->ny; iy++)
9137 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
9138
9139 /* Free... */
9140 free(help);
9141}

◆ read_met_bin_3d()

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

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

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

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

The function supports the following types of data:

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

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

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

Definition at line 9145 of file mptrac.c.

9152 {
9153
9154 float *help;
9155
9156 /* Allocate... */
9157 ALLOC(help, float,
9158 EX * EY * EP);
9159
9160 /* Read uncompressed data... */
9161 if (ctl->met_type == 1) {
9162 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
9163 FREAD(help, float,
9164 (size_t) (met->nx * met->ny * met->np),
9165 in);
9166 }
9167
9168 /* Read packed data... */
9169 else if (ctl->met_type == 2)
9170 compress_pck(ctl, met, varname, help, 1, NULL, in);
9171
9172 /* Read ZFP data... */
9173 else if (ctl->met_type == 3) {
9174#ifdef ZFP
9175 int precision;
9176 FREAD(&precision, int,
9177 1,
9178 in);
9179
9180 double tolerance;
9181 FREAD(&tolerance, double,
9182 1,
9183 in);
9184
9185 compress_zfp(ctl, met, varname, help, 1, NULL, in);
9186#else
9187 ERRMSG("MPTRAC was compiled without ZFP compression!");
9188#endif
9189 }
9190
9191 /* Read zstd data... */
9192 else if (ctl->met_type == 4) {
9193#ifdef ZSTD
9194 compress_zstd(ctl, met, varname, help, 1, NULL, in);
9195#else
9196 ERRMSG("MPTRAC was compiled without ZSTD compression!");
9197#endif
9198 }
9199
9200 /* Read LZ4 data... */
9201 else if (ctl->met_type == 8) {
9202#ifdef LZ4
9203 compress_lz4(ctl, met, varname, help, 1, NULL, in);
9204#else
9205 ERRMSG("MPTRAC was compiled without LZ4 compression!");
9206#endif
9207 }
9208
9209 /* Read cmultiscale data... */
9210 else if (ctl->met_type == 5) {
9211#ifdef CMS
9212 compress_cms(ctl, met, varname, help, 1, NULL, in);
9213#else
9214 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
9215#endif
9216 }
9217
9218 /* Read SZ3 data... */
9219 else if (ctl->met_type == 7) {
9220#ifdef SZ3
9221 int precision;
9222 FREAD(&precision, int,
9223 1,
9224 in);
9225
9226 double tolerance;
9227 FREAD(&tolerance, double,
9228 1,
9229 in);
9230
9231 compress_sz3(ctl, met, varname, help, 1, NULL, in);
9232#else
9233 ERRMSG("MPTRAC was compiled without sz3 compression!");
9234#endif
9235 }
9236
9237 /* Copy data... */
9238#pragma omp parallel for default(shared) collapse(2)
9239 for (int ix = 0; ix < met->nx; ix++)
9240 for (int iy = 0; iy < met->ny; iy++)
9241 for (int ip = 0; ip < met->np; ip++) {
9242 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9243 if (var[ix][iy][ip] < bound_min)
9244 var[ix][iy][ip] = bound_min;
9245 else if (var[ix][iy][ip] > bound_max)
9246 var[ix][iy][ip] = bound_max;
9247 }
9248
9249 /* Free... */
9250 free(help);
9251}
void compress_pck(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3‑D float array using the PCK format.
Definition: mptrac.c:986
void compress_zfp(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3D array of floats using the ZFP library.
void compress_sz3(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3-D float array using the SZ3 library.
void compress_zstd(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a float array using ZSTD.
void compress_cms(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3-D meteorological field using cmultiscale.
void compress_lz4(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a float array using LZ4.
Here is the call graph for this function:

◆ read_met_cape()

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

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

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

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

The function performs the following steps:

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

Definition at line 9255 of file mptrac.c.

9258 {
9259
9260 /* Check parameters... */
9261 if (ctl->met_cape != 1)
9262 return;
9263
9264 if (ctl->met_coord_type != 0)
9265 ERRMSG("Only lat/lon grid supported");
9266
9267 /* Set timer... */
9268 SELECT_TIMER("READ_MET_CAPE", "METPROC");
9269 LOG(2, "Calculate CAPE...");
9270
9271 /* Vertical spacing (about 100 m)... */
9272 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
9273
9274 /* Loop over columns... */
9275#pragma omp parallel for default(shared) collapse(2)
9276 for (int ix = 0; ix < met->nx; ix++)
9277 for (int iy = 0; iy < met->ny; iy++) {
9278
9279 /* Get potential temperature and water vapor at lowest 50 hPa... */
9280 int n = 0;
9281 double h2o = 0, t, theta = 0;
9282 double pbot = MIN(met->ps[ix][iy], met->p[0]);
9283 double ptop = pbot - 50.;
9284 for (int ip = 0; ip < met->np; ip++) {
9285 if (met->p[ip] <= pbot) {
9286 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
9287 h2o += met->h2o[ix][iy][ip];
9288 n++;
9289 }
9290 if (met->p[ip] < ptop && n > 0)
9291 break;
9292 }
9293 theta /= n;
9294 h2o /= n;
9295
9296 /* Cannot compute anything if water vapor is missing... */
9297 met->plcl[ix][iy] = NAN;
9298 met->plfc[ix][iy] = NAN;
9299 met->pel[ix][iy] = NAN;
9300 met->cape[ix][iy] = NAN;
9301 met->cin[ix][iy] = NAN;
9302 if (h2o <= 0)
9303 continue;
9304
9305 /* Find lifted condensation level (LCL)... */
9306 ptop = P(20.);
9307 pbot = met->ps[ix][iy];
9308 do {
9309 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
9310 t = theta / pow(1000. / met->plcl[ix][iy], KAPPA);
9311 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
9312 ptop = met->plcl[ix][iy];
9313 else
9314 pbot = met->plcl[ix][iy];
9315 } while (pbot - ptop > 0.1);
9316
9317 /* Calculate CIN up to LCL... */
9319 double dcape, dz, h2o_env, t_env;
9320 double p = met->ps[ix][iy];
9321 met->cape[ix][iy] = met->cin[ix][iy] = 0;
9322 do {
9323 dz = dz0 * TVIRT(t, h2o);
9324 p /= pfac;
9325 t = theta / pow(1000. / p, KAPPA);
9326 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
9327 &t_env, ci, cw, 1);
9328 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
9329 &h2o_env, ci, cw, 0);
9330 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
9331 TVIRT(t_env, h2o_env) * dz;
9332 if (dcape < 0)
9333 met->cin[ix][iy] += fabsf((float) dcape);
9334 } while (p > met->plcl[ix][iy]);
9335
9336 /* Calculate level of free convection (LFC), equilibrium level (EL),
9337 and convective available potential energy (CAPE)... */
9338 dcape = 0;
9339 p = met->plcl[ix][iy];
9340 t = theta / pow(1000. / p, KAPPA);
9341 ptop = 0.75 * clim_tropo(clim, met->time,
9342 ctl->met_coord_type ==
9343 0 ? met->lat[iy] : ctl->met_utm_ref_lat);
9344 do {
9345 dz = dz0 * TVIRT(t, h2o);
9346 p /= pfac;
9347 t -= lapse_rate(t, h2o) * dz;
9348 double psat = PSAT(t);
9349 h2o = psat / (p - (1. - EPS) * psat);
9350 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
9351 &t_env, ci, cw, 1);
9352 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
9353 &h2o_env, ci, cw, 0);
9354 double dcape_old = dcape;
9355 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
9356 TVIRT(t_env, h2o_env) * dz;
9357 if (dcape > 0) {
9358 met->cape[ix][iy] += (float) dcape;
9359 if (!isfinite(met->plfc[ix][iy]))
9360 met->plfc[ix][iy] = (float) p;
9361 } else if (dcape_old > 0)
9362 met->pel[ix][iy] = (float) p;
9363 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
9364 met->cin[ix][iy] += fabsf((float) dcape);
9365 } while (p > ptop);
9366
9367 /* Check results... */
9368 if (!isfinite(met->plfc[ix][iy]))
9369 met->cin[ix][iy] = NAN;
9370 }
9371}
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:213
Here is the call graph for this function:

◆ read_met_cloud()

void read_met_cloud ( met_t met)

Calculates cloud-related variables for each grid point.

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

Parameters
metA pointer to a structure containing meteorological data.

The function performs the following steps:

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

Definition at line 9375 of file mptrac.c.

9376 {
9377
9378 /* Set timer... */
9379 SELECT_TIMER("READ_MET_CLOUD", "METPROC");
9380 LOG(2, "Calculate cloud data...");
9381
9382 /* Thresholds for cloud detection... */
9383 const double ccmin = 0.01, cwmin = 1e-6;
9384
9385 /* Loop over columns... */
9386#pragma omp parallel for default(shared) collapse(2)
9387 for (int ix = 0; ix < met->nx; ix++)
9388 for (int iy = 0; iy < met->ny; iy++) {
9389
9390 /* Init... */
9391 met->pct[ix][iy] = NAN;
9392 met->pcb[ix][iy] = NAN;
9393 met->cl[ix][iy] = 0;
9394
9395 /* Loop over pressure levels... */
9396 for (int ip = 0; ip < met->np - 1; ip++) {
9397
9398 /* Check pressure... */
9399 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
9400 continue;
9401
9402 /* Check ice water and liquid water content... */
9403 if (met->cc[ix][iy][ip] > ccmin
9404 && (met->lwc[ix][iy][ip] > cwmin
9405 || met->rwc[ix][iy][ip] > cwmin
9406 || met->iwc[ix][iy][ip] > cwmin
9407 || met->swc[ix][iy][ip] > cwmin)) {
9408
9409 /* Get cloud top pressure ... */
9410 met->pct[ix][iy]
9411 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
9412
9413 /* Get cloud bottom pressure ... */
9414 if (!isfinite(met->pcb[ix][iy]))
9415 met->pcb[ix][iy]
9416 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
9417 }
9418
9419 /* Get cloud water... */
9420 met->cl[ix][iy] += (float)
9421 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
9422 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
9423 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
9424 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
9425 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
9426 }
9427 }
9428}

◆ read_met_detrend()

void read_met_detrend ( const ctl_t ctl,
met_t met 
)

Detrends meteorological data.

This function detrends meteorological data by removing spatially varying backgrounds from each grid point. Detrending helps in removing systematic biases and trends from the data, enabling better analysis and modeling.

Parameters
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Checks if detrending is enabled based on the control parameters.
  • Sets up a timer to monitor the detrending time.
  • Allocates memory for a temporary meteorological data structure.
  • Calculates the standard deviation and box size for detrending.
  • Calculates the detrended data by subtracting spatially varying backgrounds.
  • Updates the original meteorological data with the detrended values.
  • Frees the allocated memory.
Note
Detrending is performed by subtracting spatially varying backgrounds calculated from neighboring grid points.
OpenMP is utilized for parallelization to enhance performance by distributing the computation across multiple threads.
Author
Lars Hoffmann

Definition at line 9432 of file mptrac.c.

9434 {
9435
9436 met_t *help;
9437
9438 /* Check parameters... */
9439 if (ctl->met_detrend <= 0)
9440 return;
9441
9442 if (ctl->met_coord_type != 0)
9443 ERRMSG("Only lat/lon grid supported");
9444
9445 /* Set timer... */
9446 SELECT_TIMER("READ_MET_DETREND", "METPROC");
9447 LOG(2, "Detrend meteo data...");
9448
9449 /* Allocate... */
9450 ALLOC(help, met_t, 1);
9451
9452 /* Calculate standard deviation... */
9453 const double sigma = ctl->met_detrend / 2.355;
9454 const double tssq = 2. * SQR(sigma);
9455
9456 /* Calculate box size in latitude... */
9457 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
9458 sy = MIN(MAX(1, sy), met->ny / 2);
9459
9460 /* Calculate background... */
9461#pragma omp parallel for default(shared) collapse(2)
9462 for (int ix = 0; ix < met->nx; ix++) {
9463 for (int iy = 0; iy < met->ny; iy++) {
9464
9465 /* Calculate Cartesian coordinates... */
9466 double x0[3];
9467 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
9468
9469 /* Calculate box size in longitude... */
9470 int sx =
9471 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
9472 fabs(met->lon[1] - met->lon[0]));
9473 sx = MIN(MAX(1, sx), met->nx / 2);
9474
9475 /* Init... */
9476 float wsum = 0;
9477 for (int ip = 0; ip < met->np; ip++) {
9478 help->t[ix][iy][ip] = 0;
9479 help->u[ix][iy][ip] = 0;
9480 help->v[ix][iy][ip] = 0;
9481 help->w[ix][iy][ip] = 0;
9482 }
9483
9484 /* Loop over neighboring grid points... */
9485 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
9486 int ix3 = ix2;
9487 if (ix3 < 0)
9488 ix3 += met->nx;
9489 else if (ix3 >= met->nx)
9490 ix3 -= met->nx;
9491 for (int iy2 = MAX(iy - sy, 0);
9492 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
9493
9494 /* Calculate Cartesian coordinates... */
9495 double x1[3];
9496 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
9497
9498 /* Calculate weighting factor... */
9499 const float w = (float) exp(-DIST2(x0, x1) / tssq);
9500
9501 /* Add data... */
9502 wsum += w;
9503 for (int ip = 0; ip < met->np; ip++) {
9504 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
9505 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
9506 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
9507 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
9508 }
9509 }
9510 }
9511
9512 /* Normalize... */
9513 for (int ip = 0; ip < met->np; ip++) {
9514 help->t[ix][iy][ip] /= wsum;
9515 help->u[ix][iy][ip] /= wsum;
9516 help->v[ix][iy][ip] /= wsum;
9517 help->w[ix][iy][ip] /= wsum;
9518 }
9519 }
9520 }
9521
9522 /* Subtract background... */
9523#pragma omp parallel for default(shared) collapse(3)
9524 for (int ix = 0; ix < met->nx; ix++)
9525 for (int iy = 0; iy < met->ny; iy++)
9526 for (int ip = 0; ip < met->np; ip++) {
9527 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
9528 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
9529 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
9530 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
9531 }
9532
9533 /* Free... */
9534 free(help);
9535}
void geo2cart(const double z, const double lon, const double lat, double *x)
Converts geographic coordinates (longitude, latitude, altitude) to Cartesian coordinates.
Definition: mptrac.c:2601
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:903
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:1019
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:921
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 9539 of file mptrac.c.

9540 {
9541
9542 /* Set timer... */
9543 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC");
9544 LOG(2, "Extrapolate meteo data...");
9545
9546 /* Loop over columns... */
9547#pragma omp parallel for default(shared) collapse(2)
9548 for (int ix = 0; ix < met->nx; ix++)
9549 for (int iy = 0; iy < met->ny; iy++) {
9550
9551 /* Find lowest valid data point... */
9552 int ip0;
9553 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
9554 if (!isfinite(met->t[ix][iy][ip0])
9555 || !isfinite(met->u[ix][iy][ip0])
9556 || !isfinite(met->v[ix][iy][ip0])
9557 || !isfinite(met->w[ix][iy][ip0]))
9558 break;
9559
9560 /* Extrapolate... */
9561 for (int ip = ip0; ip >= 0; ip--) {
9562 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
9563 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
9564 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
9565 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
9566 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
9567 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
9568 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
9569 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
9570 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
9571 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
9572 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
9573 }
9574 }
9575}

◆ read_met_geopot()

void read_met_geopot ( const ctl_t ctl,
met_t met 
)

Calculates geopotential heights from meteorological data.

This function calculates geopotential heights from provided meteorological data using the hydrostatic equation. Geopotential heights are computed column-wise for each grid point based on the temperature, pressure, and surface height information. Optionally, the calculated geopotential heights can be smoothed horizontally using a weighted averaging scheme.

Parameters
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets up a timer to monitor the geopotential height calculation time.
  • Calculates the logarithm of pressure levels for efficient computation.
  • Applies the hydrostatic equation to determine geopotential heights based on temperature, pressure, and height information.
  • Optionally, performs horizontal smoothing on the calculated geopotential heights.
  • Updates the meteorological data structure with the computed geopotential heights.
Note
The hydrostatic equation is utilized to calculate geopotential heights, ensuring consistency with atmospheric conditions. Optionally, horizontal smoothing can be applied to the calculated geopotential heights to reduce spatial variability. OpenMP is utilized for parallelization to enhance performance by distributing the computation across multiple threads.
Author
Lars Hoffmann

Definition at line 9579 of file mptrac.c.

9581 {
9582
9583 float *help;
9584
9585 double logp[EP];
9586
9587 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
9588
9589 /* Set timer... */
9590 SELECT_TIMER("READ_MET_GEOPOT", "METPROC");
9591 LOG(2, "Calculate geopotential heights...");
9592
9593 /* Allocate... */
9594 ALLOC(help, float,
9595 EX * EY * EP);
9596
9597 /* Calculate log pressure... */
9598#pragma omp parallel for default(shared)
9599 for (int ip = 0; ip < met->np; ip++)
9600 logp[ip] = log(met->p[ip]);
9601
9602 /* Apply hydrostatic equation to calculate geopotential heights... */
9603#pragma omp parallel for default(shared) collapse(2)
9604 for (int ix = 0; ix < met->nx; ix++)
9605 for (int iy = 0; iy < met->ny; iy++) {
9606
9607 /* Get surface height and pressure... */
9608 const double zs = met->zs[ix][iy];
9609 const double lnps = log(met->ps[ix][iy]);
9610
9611 /* Get temperature and water vapor at the surface... */
9612 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
9613 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
9614 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
9615 const double h2os =
9616 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
9617 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
9618
9619 /* Upper part of profile... */
9620 met->z[ix][iy][ip0 + 1]
9621 = (float) (zs +
9622 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
9623 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
9624 for (int ip = ip0 + 2; ip < met->np; ip++)
9625 met->z[ix][iy][ip]
9626 = (float) (met->z[ix][iy][ip - 1] +
9627 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
9628 met->h2o[ix][iy][ip - 1], logp[ip],
9629 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
9630
9631 /* Lower part of profile... */
9632 met->z[ix][iy][ip0]
9633 = (float) (zs +
9634 ZDIFF(lnps, ts, h2os, logp[ip0],
9635 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
9636 for (int ip = ip0 - 1; ip >= 0; ip--)
9637 met->z[ix][iy][ip]
9638 = (float) (met->z[ix][iy][ip + 1] +
9639 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
9640 met->h2o[ix][iy][ip + 1], logp[ip],
9641 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
9642 }
9643
9644 /* Check control parameters... */
9645 if (dx == 0 || dy == 0)
9646 return;
9647
9648 /* Default smoothing parameters... */
9649 if (dx < 0 || dy < 0) {
9650 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
9651 dx = 3;
9652 dy = 2;
9653 } else {
9654 dx = 6;
9655 dy = 4;
9656 }
9657 }
9658
9659 /* Calculate weights for smoothing... */
9660 float ws[dx + 1][dy + 1];
9661#pragma omp parallel for default(shared) collapse(2)
9662 for (int ix = 0; ix <= dx; ix++)
9663 for (int iy = 0; iy < dy; iy++)
9664 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
9665 * (1.0f - (float) iy / (float) dy);
9666
9667 /* Copy data... */
9668#pragma omp parallel for default(shared) collapse(3)
9669 for (int ix = 0; ix < met->nx; ix++)
9670 for (int iy = 0; iy < met->ny; iy++)
9671 for (int ip = 0; ip < met->np; ip++)
9672 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
9673
9674 /* Horizontal smoothing... */
9675#pragma omp parallel for default(shared) collapse(3)
9676 for (int ip = 0; ip < met->np; ip++)
9677 for (int ix = 0; ix < met->nx; ix++)
9678 for (int iy = 0; iy < met->ny; iy++) {
9679 float res = 0, wsum = 0;
9680 int iy0 = MAX(iy - dy + 1, 0);
9681 int iy1 = MIN(iy + dy - 1, met->ny - 1);
9682 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
9683 int ix3 = ix2;
9684 if (ix3 < 0)
9685 ix3 += met->nx;
9686 else if (ix3 >= met->nx)
9687 ix3 -= met->nx;
9688 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
9689 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
9690 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
9691 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
9692 wsum += w;
9693 }
9694 }
9695 if (wsum > 0)
9696 met->z[ix][iy][ip] = res / wsum;
9697 else
9698 met->z[ix][iy][ip] = NAN;
9699 }
9700
9701 /* Free... */
9702 free(help);
9703}
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:2284
Here is the call graph for this function:

◆ read_met_grib()

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

Reads meteorological data from a grib file and processes it.

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

Parameters
filenameA constant character pointer representing the name of the grib files to read the meteorological data from. The sf or ml suffixes indicating surface or multi-level data should be replaced with XX.
ctlA pointer to a ctl_t structure, which contains control parameters for reading and processing the meteorological data.
metA pointer to a met_t structure that will store the meteorological data read and processed from the NetCDF file.
Returns
Returns 1 on success, or 0 if the file cannot be opened.
Note
  • The function reads grid data, vertical level data, and surface data from the file, and processes the data to calculate additional meteorological parameters.
  • If the file cannot be opened, the function logs a warning and returns 0.
Author
Nils Nobre Wittwer

◆ read_met_grib_grid()

void read_met_grib_grid ( codes_handle **  handles,
int  count_handles,
met_t met 
)

Reads global meteorological information from a grib file.

This function reads meteorological grid information from a grib file, including time and spatial dimensions. The function computes the latitude and longitude grid based on the provided boundaries and increment values.

Parameters
handlesA pointer to an array of codes_handle pointers representing the grib messages.
count_handlesThe total number of grib messages in the handles array.
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 the data file.
  • Retrieves grid dimensions (longitude, latitude, and vertical levels) from the grib file.
  • Reads longitudes and latitudes boundaries and increments from the grib file and computes the grid.
  • Logs the retrieved grid information for verification and debugging purposes.
Author
Nils Nobre Wittwer

◆ read_met_grib_levels()

void read_met_grib_levels ( codes_handle **  handles,
const int  num_messages,
const ctl_t ctl,
met_t met 
)

Reads meteorological variables at different vertical levels from a grib 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 grib file.

Parameters
handlesA pointer to an array of codes_handle pointers representing the grib messages.
num_messagesThe total number of grib messages in the handles array.
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 grib file.
  • Checks the ordering of pressure levels to ensure they are in descending order.
Author
Nils Nobre Wittwer

◆ read_met_grib_surface()

void read_met_grib_surface ( codes_handle **  handles,
const int  num_messages,
const ctl_t ctl,
met_t met 
)

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

This function reads various surface meteorological variables from a grib 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
handlesA pointer to an array of codes_handle pointers representing the grib messages.
num_messagesThe total number of grib messages in the handles array.
ctlA pointer to a structure containing control parameters.
metA pointer to a structure to store meteorological data.

The function performs the following steps:

  • Sets a timer for performance monitoring.
  • Reads surface meteorological data based on the configuration:
  • Reads surface pressure from "lnsp", "ps", or "sp" variables.
  • Converts surface pressure to Pa.
  • 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.
Author
Nils Nobre Wittwer

◆ read_met_ml2pl()

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

Interpolates meteorological data to specified pressure levels.

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

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

This function performs the following steps:

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

Definition at line 11314 of file mptrac.c.

11318 {
11319
11320 double aux[EP], p[EP];
11321
11322 /* Set timer... */
11323 SELECT_TIMER("READ_MET_ML2PL", "METPROC");
11324 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
11325
11326 /* Loop over columns... */
11327#pragma omp parallel for default(shared) private(aux,p) collapse(2)
11328 for (int ix = 0; ix < met->nx; ix++)
11329 for (int iy = 0; iy < met->ny; iy++) {
11330
11331 /* Copy pressure profile... */
11332 for (int ip = 0; ip < met->np; ip++)
11333 p[ip] = met->pl[ix][iy][ip];
11334
11335 /* Interpolate... */
11336 for (int ip = 0; ip < ctl->met_np; ip++) {
11337 double pt = ctl->met_p[ip];
11338 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
11339 pt = p[0];
11340 else if ((pt > p[met->np - 1] && p[1] > p[0])
11341 || (pt < p[met->np - 1] && p[1] < p[0]))
11342 pt = p[met->np - 1];
11343 const int ip2 = locate_irr(p, met->np, pt);
11344 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
11345 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
11346 }
11347
11348 /* Copy data... */
11349 for (int ip = 0; ip < ctl->met_np; ip++)
11350 var[ix][iy][ip] = (float) aux[ip];
11351 }
11352}
Here is the call graph for this function:

◆ read_met_monotonize()

void read_met_monotonize ( const ctl_t ctl,
met_t met 
)

Makes zeta and pressure profiles monotone.

This function ensures that zeta and pressure profiles are monotone increasing and decreasing with altitude. It iterates over each grid point and each level to identify inversions and linearly interpolate between them to maintain monotonicity. The interpolation is performed for both zeta and pressure profiles.

Parameters
ctlA pointer to a control parameter structure.
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets up a timer to monitor the processing time.
  • Iterates over each grid point in parallel using OpenMP.
  • Identifies inversions in both zeta and pressure profiles and interpolates linearly between them to make the profiles monotone increasing.
Note
This function is crucial for maintaining the physical consistency of meteorological profiles, ensuring accurate atmospheric simulations.
Author
Jan Clemens

Definition at line 11356 of file mptrac.c.

11358 {
11359
11360 /* Check parameters... */
11361 if (ctl->advect_vert_coord != 1)
11362 return;
11363
11364 /* Set timer... */
11365 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC");
11366 LOG(2, "Make zeta profiles monotone...");
11367
11368 /* Create monotone zeta profiles... */
11369#pragma omp parallel for default(shared) collapse(2)
11370 for (int i = 0; i < met->nx; i++)
11371 for (int j = 0; j < met->ny; j++) {
11372 int k = 1;
11373
11374 while (k < met->npl) { /* Check if there is an inversion at level k... */
11375 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
11376 /* Find the upper level k+l over the inversion... */
11377 int l = 0;
11378 do {
11379 l++;
11380 }
11381 while ((met->zetal[i][j][k - 1] >=
11382 met->zetal[i][j][k + l]) & (k + l < met->npl));
11383
11384 /* Interpolate linear between the top and bottom
11385 of the inversion... */
11386 float s =
11387 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
11388 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
11389
11390 for (int m = k; m < k + l; m++) {
11391 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
11392 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
11393 }
11394
11395 /* Search for more inversions above the last inversion ... */
11396 k = k + l;
11397 } else {
11398 k++;
11399 }
11400 }
11401 }
11402
11403 /* Create monotone pressure profiles... */
11404#pragma omp parallel for default(shared) collapse(2)
11405 for (int i = 0; i < met->nx; i++)
11406 for (int j = 0; j < met->ny; j++) {
11407 int k = 1;
11408
11409 while (k < met->npl) { /* Check if there is an inversion at level k... */
11410 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
11411
11412 /* Find the upper level k+l over the inversion... */
11413 int l = 0;
11414 do {
11415 l++;
11416 }
11417 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
11418 met->npl));
11419
11420 /* Interpolate linear between the top and bottom
11421 of the inversion... */
11422 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
11423 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
11424
11425 for (int m = k; m < k + l; m++) {
11426 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
11427 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
11428 }
11429
11430 /* Search for more inversions above the last inversion ... */
11431 k += l;
11432 } else {
11433 k++;
11434 }
11435 }
11436 }
11437}
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3893

◆ read_met_nc()

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

Reads meteorological data from a NetCDF file and processes it.

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

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

Definition at line 11441 of file mptrac.c.

11445 {
11446
11447 int ncid;
11448
11449 /* Open file... */
11450#ifdef DD
11451 if (ctl->dd) {
11452 NC(nc_open_par
11453 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
11454 &ncid))
11455 }
11456#else
11457 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
11458 WARN("Cannot open file!");
11459 return 0;
11460 }
11461#endif
11462
11463 /* Set coordinate system of meteo data... */
11464 met->coord_type = ctl->met_coord_type;
11465
11466 /* Read coordinates of meteo data... */
11467 read_met_nc_grid(filename, ncid, ctl, met, dd);
11468
11469 /* Read surface data... */
11470 read_met_nc_surface(ncid, ctl, met, dd);
11471
11472 /* Read meteo data on vertical levels... */
11473 read_met_nc_levels(ncid, ctl, met, dd);
11474
11475 /* Close file... */
11476 NC(nc_close(ncid));
11477
11478 /* Return success... */
11479 return 1;
11480}
void read_met_nc_levels(const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads and processes meteorological level data from NetCDF files with domain decomposition.
Definition: mptrac.c:10049
void read_met_nc_surface(const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads and processes surface meteorological data from NetCDF files with domain decomposition.
Definition: mptrac.c:9894
void read_met_nc_grid(const char *filename, const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads meteorological grid data from NetCDF files with domain decomposition.
Definition: mptrac.c:9707
Here is the call graph for this function:

◆ read_met_nc_grid()

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

Reads meteorological grid data from NetCDF files with domain decomposition.

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

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

The function performs the following steps:

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

Definition at line 9707 of file mptrac.c.

9712 {
9713
9714 char levname[LEN], tstr[10];
9715
9716 double rtime = 0, r, r2;
9717
9718 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
9719 year, mon, day, hour, min, sec;
9720
9721 size_t dimlen;
9722
9723 /* Set timer... */
9724 SELECT_TIMER("READ_MET_NC_GRID", "INPUT");
9725 LOG(2, "Read meteo grid information...");
9726
9727 /* MPTRAC meteo files... */
9728 if (!ctl->met_clams) {
9729
9730 /* Get time from filename... */
9731 met->time = time_from_filename(filename, 16, 0);
9732
9733 /* Check time information from data file... */
9734 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
9735 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
9736 NC(nc_get_var_double(ncid, varid, &rtime));
9737 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
9738 WARN("Time information in meteo file does not match filename!");
9739 } else
9740 WARN("Time information in meteo file is missing!");
9741 }
9742
9743 /* CLaMS meteo files... */
9744 else {
9745
9746 /* Read time from file... */
9747 NC_GET_DOUBLE("time", &rtime, 0);
9748
9749 /* Get time from filename (considering the century)... */
9750 if (rtime < 0)
9751 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
9752 else
9753 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
9754 year = atoi(tstr);
9755 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
9756 mon = atoi(tstr);
9757 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
9758 day = atoi(tstr);
9759 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
9760 hour = atoi(tstr);
9761 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
9762 }
9763
9764 /* Check time... */
9765 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
9766 || day < 1 || day > 31 || hour < 0 || hour > 23)
9767 ERRMSG("Cannot read time from filename!");
9768 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
9769 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
9770 met->time, year2, mon2, day2, hour2, min2);
9771
9772 /* Get vertical dimension... */
9773 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
9774 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
9775 ERRMSG
9776 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
9777
9778 NC(nc_inq_varndims(ncid, varid, &ndims));
9779 NC(nc_inq_vardimid(ncid, varid, dimids));
9780
9781 if (ndims == 4) {
9782 NC(nc_inq_dim
9783 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
9784 } else if (ndims == 3) {
9785 NC(nc_inq_dim
9786 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
9787 } else
9788 ERRMSG("Cannot determine vertical dimension!")
9789 met->np = (int) dimlen;
9790
9791 LOG(2, "Number of levels: %d", met->np);
9792 if (met->np < 2 || met->np > EP)
9793 ERRMSG("Number of levels out of range!");
9794
9795 if (!ctl->dd) {
9796
9797 /* Get grid dimensions and coordinates... */
9798 if (met->coord_type == 0) {
9799 /* Longitude/latitude grid... */
9800 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
9801 LOG(2, "Number of longitudes: %d", met->nx);
9802
9803 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
9804 LOG(2, "Number of latitudes: %d", met->ny);
9805
9806 NC_GET_DOUBLE("lon", met->lon, 1);
9807 LOG(2, "Longitudes: %g, %g ... %g deg",
9808 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9809 NC_GET_DOUBLE("lat", met->lat, 1);
9810 LOG(2, "Latitudes: %g, %g ... %g deg",
9811 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9812
9813 } else {
9814 /* UTM grid... */
9815 NC_INQ_DIM("x", &met->nx, 2, EX, 1);
9816 LOG(2, "Number of x coordinates: %d", met->nx);
9817
9818 NC_INQ_DIM("y", &met->ny, 2, EY, 1);
9819 LOG(2, "Number of y coordinates: %d", met->ny);
9820
9821 NC_GET_DOUBLE("x", met->lon, 1);
9822 LOG(2, "X coordinates: %g, %g ... %g m",
9823 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9824 NC_GET_DOUBLE("y", met->lat, 1);
9825 LOG(2, "Y coordinates: %g, %g ... %g m",
9826 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9827 }
9828
9829 } else {
9830
9831 if (met->coord_type != 0)
9832 ERRMSG("Domain decomposition is only supported for lat/lon grids!");
9833
9834 /* Use equidistant lat-lon domain decomposition... */
9835 dd_read_met_nc_grid(dd, ctl, met, ncid);
9836
9837 }
9838
9839 /* Read pressure levels... */
9840 if (ctl->met_np <= 0) {
9841 NC_GET_DOUBLE(levname, met->p, 1);
9842 for (int ip = 0; ip < met->np; ip++)
9843 met->p[ip] /= 100.;
9844 LOG(2, "Altitude levels: %g, %g ... %g km",
9845 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
9846 LOG(2, "Pressure levels: %g, %g ... %g hPa",
9847 met->p[0], met->p[1], met->p[met->np - 1]);
9848 }
9849
9850 /* Read hybrid levels... */
9851 if (strcasecmp(levname, "hybrid") == 0)
9852 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
9853
9854 /* Read model level coefficients from file... */
9855 if (ctl->met_vert_coord == 2) {
9856 NC_GET_DOUBLE("hyam", met->hyam, 1);
9857 NC_GET_DOUBLE("hybm", met->hybm, 1);
9858 }
9859
9860 /* Copy model level coefficients from control parameters... */
9861 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
9862 if (ctl->met_nlev <= 0)
9863 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
9864 for (int ip = 0; ip < ctl->met_nlev; ip++) {
9865 met->hyam[ip] = ctl->met_lev_hyam[ip];
9866 met->hybm[ip] = ctl->met_lev_hybm[ip];
9867 }
9868 }
9869
9870 /* Calculate eta levels... */
9871 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
9872 met->eta[k] = met->hyam[k] / (100.0 * P0) + met->hybm[k];
9873 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
9874 ERRMSG("Eta levels must be ascending!");
9875 }
9876
9877 /* Check horizontal grid spacing... */
9878 for (int ix = 2; ix < met->nx; ix++)
9879 if (fabs
9880 (fabs(met->lon[ix] - met->lon[ix - 1]) -
9881 fabs(met->lon[1] - met->lon[0])) > 0.001)
9882 ERRMSG("No regular grid spacing in longitudes!");
9883 for (int iy = 2; iy < met->ny; iy++)
9884 if (fabs
9885 (fabs(met->lat[iy] - met->lat[iy - 1]) -
9886 fabs(met->lat[1] - met->lat[0])) > 0.001) {
9887 WARN("No regular grid spacing in latitudes!");
9888 break;
9889 }
9890}
void dd_read_met_nc_grid(dd_t *dd, const ctl_t *ctl, met_t *met, const int ncid)
Read meteorological grid information and construct the domain-decomposed grid with halo regions.
Definition: mptrac.c:11484
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:12690
double time_from_filename(const char *filename, const int offset, const int with_seconds)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:12789
#define P0
Standard pressure [hPa].
Definition: mptrac.h:304
double eta[EP]
Model level eta values.
Definition: mptrac.h:3902
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3896
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3899
Here is the call graph for this function:

◆ read_met_nc_levels()

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

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

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

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

The function performs the following steps:

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

Definition at line 10049 of file mptrac.c.

10053 {
10054
10055 /* Set timer... */
10056 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT");
10057 LOG(2, "Read level data...");
10058
10059 /* Read temperature... */
10060 if (!read_met_nc_3d
10061 (ncid, (const char *const[]) { "t", "T", "temp", "TEMP" }, 4, ctl, met,
10062 dd, met->t, 1.0))
10063 ERRMSG("Cannot read temperature!");
10064
10065 /* Read horizontal wind and vertical velocity... */
10066 if (!read_met_nc_3d
10067 (ncid, (const char *const[]) { "u", "U" }, 2, ctl, met, dd, met->u,
10068 1.0))
10069 ERRMSG("Cannot read zonal wind!");
10070 if (!read_met_nc_3d
10071 (ncid, (const char *const[]) { "v", "V" }, 2, ctl, met, dd, met->v,
10072 1.0))
10073 ERRMSG("Cannot read meridional wind!");
10074 if (!read_met_nc_3d
10075 (ncid, (const char *const[]) { "w", "W", "omega", "OMEGA" }, 4, ctl,
10076 met, dd, met->w, 0.01f))
10077 WARN("Cannot read vertical velocity!");
10078
10079 /* Read water vapor... */
10080 if (!ctl->met_relhum) {
10081 if (!read_met_nc_3d
10082 (ncid, (const char *const[]) { "q", "Q", "sh", "SH" }, 4, ctl, met,
10083 dd, met->h2o,
10084 (float) (MA / MH2O)))
10085 WARN("Cannot read specific humidity!");
10086 } else {
10087 if (!read_met_nc_3d
10088 (ncid, (const char *const[]) { "rh", "RH" }, 2, ctl, met, dd,
10089 met->h2o, 0.01f))
10090 WARN("Cannot read relative humidity!");
10091#pragma omp parallel for default(shared) collapse(2)
10092 for (int ix = 0; ix < met->nx; ix++)
10093 for (int iy = 0; iy < met->ny; iy++)
10094 for (int ip = 0; ip < met->np; ip++) {
10095 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
10096 met->h2o[ix][iy][ip] =
10097 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
10098 }
10099 }
10100
10101 /* Read ozone... */
10102 if (!read_met_nc_3d
10103 (ncid, (const char *const[]) { "o3", "O3" }, 2, ctl, met, dd, met->o3,
10104 (float) (MA / MO3)))
10105 WARN("Cannot read ozone data!");
10106
10107 /* Read cloud data... */
10108 if (!read_met_nc_3d
10109 (ncid, (const char *const[]) { "clwc", "CLWC" }, 2, ctl, met, dd,
10110 met->lwc, 1.0))
10111 WARN("Cannot read cloud liquid water content!");
10112 if (!read_met_nc_3d
10113 (ncid, (const char *const[]) { "crwc", "CRWC" }, 2, ctl, met, dd,
10114 met->rwc, 1.0))
10115 WARN("Cannot read cloud rain water content!");
10116 if (!read_met_nc_3d
10117 (ncid, (const char *const[]) { "ciwc", "CIWC" }, 2, ctl, met, dd,
10118 met->iwc, 1.0))
10119 WARN("Cannot read cloud ice water content!");
10120 if (!read_met_nc_3d
10121 (ncid, (const char *const[]) { "cswc", "CSWC" }, 2, ctl, met, dd,
10122 met->swc, 1.0))
10123 WARN("Cannot read cloud snow water content!");
10124 if (!read_met_nc_3d
10125 (ncid, (const char *const[]) { "cc", "CC" }, 2, ctl, met, dd, met->cc,
10126 1.0))
10127 WARN("Cannot read cloud cover!");
10128
10129 /* Read zeta and zeta_dot... */
10130 if (ctl->advect_vert_coord == 1) {
10131 if (!read_met_nc_3d
10132 (ncid, (const char *const[]) { "ZETA", "zeta" }, 2, ctl, met, dd,
10133 met->zetal, 1.0))
10134 WARN("Cannot read ZETA!");
10135 if (!read_met_nc_3d
10136 (ncid, (const char *const[]) { "ZETA_DOT_TOT", "ZETA_DOT_clr",
10137 "zeta_dot_clr"
10138 }, 3, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
10139 ERRMSG("Cannot read ZETA_DOT!");
10140 }
10141
10142 /* Set eta coordinate on native model levels... */
10143 if (ctl->advect_vert_coord == 3 || ctl->qnt_eta_d >= 0) {
10144#pragma omp parallel for default(shared)
10145 for (int ix = 0; ix < met->nx; ix++)
10146 for (int iy = 0; iy < met->ny; iy++)
10147 for (int ip = 0; ip < met->np; ip++)
10148 met->zetal[ix][iy][ip] =
10149 (float) (met->hyam[ip] / (100.0 * P0) + met->hybm[ip]);
10150 }
10151
10152 /* Read eta_dot... */
10153 if (ctl->advect_vert_coord == 3)
10154 if (!read_met_nc_3d
10155 (ncid, (const char *const[]) { "etadot", "ETADOT" }, 2, ctl, met, dd,
10156 met->zeta_dotl,
10157 1.0))
10158 ERRMSG("Cannot read eta vertical velocity!");
10159
10160 /* Store velocities on model levels... */
10161 if (ctl->met_vert_coord != 0) {
10162#pragma omp parallel for default(shared)
10163 for (int ix = 0; ix < met->nx; ix++)
10164 for (int iy = 0; iy < met->ny; iy++)
10165 for (int ip = 0; ip < met->np; ip++) {
10166 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
10167 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
10168 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
10169 }
10170
10171 /* Save number of model levels... */
10172 met->npl = met->np;
10173 }
10174
10175 /* Get pressure on model levels... */
10176 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
10177
10178 /* Read 3-D pressure field... */
10179 if (ctl->met_vert_coord == 1) {
10180 if (!read_met_nc_3d
10181 (ncid, (const char *const[]) { "pl", "PL", "pressure", "PRESSURE" },
10182 4, ctl, met, dd, met->pl,
10183 0.01f))
10184 if (!read_met_nc_3d
10185 (ncid, (const char *const[]) { "press", "PRESS" }, 2, ctl, met,
10186 dd, met->pl, 1.0))
10187 ERRMSG("Cannot read pressure on model levels!");
10188 }
10189
10190 /* Use a and b coefficients for full levels (at layer midpoints)... */
10191 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
10192
10193 /* Check number of levels... */
10194 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
10195 ERRMSG("Mismatch in number of model levels!");
10196
10197 /* Calculate pressure... */
10198 for (int ix = 0; ix < met->nx; ix++)
10199 for (int iy = 0; iy < met->ny; iy++)
10200 for (int ip = 0; ip < met->np; ip++)
10201 met->pl[ix][iy][ip] =
10202 (float) (met->hyam[ip] / 100. +
10203 met->hybm[ip] * met->ps[ix][iy]);
10204 }
10205
10206 /* Use a and b coefficients for half levels (at layer interfaces)... */
10207 else if (ctl->met_vert_coord == 4) {
10208
10209 /* Check number of levels... */
10210 if (met->np + 1 != ctl->met_nlev)
10211 ERRMSG("Mismatch in number of model levels!");
10212
10213 /* Calculate pressure... */
10214#pragma omp parallel for default(shared) collapse(2)
10215 for (int ix = 0; ix < met->nx; ix++)
10216 for (int iy = 0; iy < met->ny; iy++)
10217 for (int ip = 0; ip < met->np; ip++) {
10218 const double p0 =
10219 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
10220 const double p1 =
10221 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
10222 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
10223 }
10224 }
10225
10226 /* Check ordering of pressure levels... */
10227 for (int ix = 0; ix < met->nx; ix++)
10228 for (int iy = 0; iy < met->ny; iy++)
10229 for (int ip = 1; ip < met->np; ip++)
10230 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
10231 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
10232 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
10233 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
10234 ERRMSG("Pressure profiles are not monotonic!");
10235 }
10236
10237 /* Interpolate from model levels to pressure levels... */
10238 if (ctl->met_np > 0) {
10239
10240 /* Interpolate variables... */
10241 read_met_ml2pl(ctl, met, met->t, "T");
10242 read_met_ml2pl(ctl, met, met->u, "U");
10243 read_met_ml2pl(ctl, met, met->v, "V");
10244 read_met_ml2pl(ctl, met, met->w, "W");
10245 read_met_ml2pl(ctl, met, met->h2o, "H2O");
10246 read_met_ml2pl(ctl, met, met->o3, "O3");
10247 read_met_ml2pl(ctl, met, met->lwc, "LWC");
10248 read_met_ml2pl(ctl, met, met->rwc, "RWC");
10249 read_met_ml2pl(ctl, met, met->iwc, "IWC");
10250 read_met_ml2pl(ctl, met, met->swc, "SWC");
10251 read_met_ml2pl(ctl, met, met->cc, "CC");
10252
10253 /* Set new pressure levels... */
10254 met->np = ctl->met_np;
10255 for (int ip = 0; ip < met->np; ip++)
10256 met->p[ip] = ctl->met_p[ip];
10257 }
10258
10259 /* Check ordering of pressure levels... */
10260 for (int ip = 1; ip < met->np; ip++)
10261 if (met->p[ip - 1] < met->p[ip])
10262 ERRMSG("Pressure levels must be descending!");
10263}
void read_met_ml2pl(const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname)
Interpolates meteorological data to specified pressure levels.
Definition: mptrac.c:11314
int read_met_nc_3d(const int ncid, const char *const varnames[], const size_t nvarnames, const ctl_t *ctl, const met_t *met, dd_t *dd, float dest[EX][EY][EP], const float scl)
Reads a 3-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:10573
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:294
#define MO3
Molar mass of ozone [g/mol].
Definition: mptrac.h:299
Here is the call graph for this function:

◆ read_met_nc_surface()

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

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

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

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

The function performs the following steps:

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

Definition at line 9894 of file mptrac.c.

9898 {
9899
9900 /* Set timer... */
9901 SELECT_TIMER("READ_MET_SURFACE", "INPUT");
9902 LOG(2, "Read surface data...");
9903
9904 /* Read surface pressure... */
9905 if (read_met_nc_2d
9906 (ncid, (const char *const[]) { "lnsp", "LNSP" }, 2, ctl, met, dd,
9907 met->ps,
9908 1.0f, 1)) {
9909 for (int ix = 0; ix < met->nx; ix++)
9910 for (int iy = 0; iy < met->ny; iy++)
9911 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
9912 } else
9913 if (!read_met_nc_2d
9914 (ncid, (const char *const[]) { "ps", "PS", "sp", "SP" }, 4, ctl, met,
9915 dd, met->ps,
9916 0.01f, 1)) {
9917 WARN("Cannot not read surface pressure data (use lowest level)!");
9918 for (int ix = 0; ix < met->nx; ix++)
9919 for (int iy = 0; iy < met->ny; iy++)
9920 met->ps[ix][iy]
9921 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
9922 }
9923
9924 /* MPTRAC meteo data... */
9925 if (ctl->met_clams == 0) {
9926
9927 /* Read geopotential height at the surface... */
9928 if (!read_met_nc_2d
9929 (ncid, (const char *const[]) { "z", "Z" }, 2, ctl, met, dd, met->zs,
9930 (float) (1. / (1000. * G0)), 1))
9931 if (!read_met_nc_2d
9932 (ncid, (const char *const[]) { "zm", "ZM" }, 2, ctl, met, dd,
9933 met->zs,
9934 (ctl->met_gp2z ? (float) (1e-3 / G0) : (float) (1. / 1000.)), 1))
9935 WARN("Cannot read surface geopotential height!");
9936 }
9937
9938 /* CLaMS meteo data... */
9939 else {
9940
9941 /* Read geopotential height at the surface
9942 (use lowermost level of 3-D data field)... */
9943 float *help;
9944 ALLOC(help, float,
9945 EX * EY * EP);
9946 memcpy(help, met->pl, sizeof(met->pl));
9947 if (!read_met_nc_3d
9948 (ncid, (const char *const[]) { "gph", "GPH" }, 2, ctl, met, dd,
9949 met->pl,
9950 (float) (1e-3 / G0)))
9951 ERRMSG("Cannot read geopotential height!");
9952 for (int ix = 0; ix < met->nx; ix++)
9953 for (int iy = 0; iy < met->ny; iy++)
9954 met->zs[ix][iy] = met->pl[ix][iy][0];
9955 memcpy(met->pl, help, sizeof(met->pl));
9956 free(help);
9957 }
9958
9959 /* Read temperature at the surface... */
9960 if (!read_met_nc_2d
9961 (ncid, (const char *const[]) { "t2m", "T2M", "2t", "2T", "t2", "T2" },
9962 6, ctl, met, dd, met->ts, 1.0,
9963 1))
9964 WARN("Cannot read surface temperature!");
9965
9966 /* Read zonal wind at the surface... */
9967 if (!read_met_nc_2d
9968 (ncid, (const char *const[]) { "u10m", "U10M", "10u", "10U", "u10",
9969 "U10"
9970 }, 6, ctl, met, dd,
9971 met->us, 1.0, 1))
9972 WARN("Cannot read surface zonal wind!");
9973
9974 /* Read meridional wind at the surface... */
9975 if (!read_met_nc_2d
9976 (ncid, (const char *const[]) { "v10m", "V10M", "10v", "10V", "v10",
9977 "V10"
9978 }, 6, ctl, met, dd,
9979 met->vs, 1.0, 1))
9980 WARN("Cannot read surface meridional wind!");
9981
9982 /* Read eastward turbulent surface stress... */
9983 if (!read_met_nc_2d
9984 (ncid, (const char *const[]) { "iews", "IEWS" }, 2, ctl, met, dd,
9985 met->ess,
9986 1.0, 1))
9987 WARN("Cannot read eastward turbulent surface stress!");
9988
9989 /* Read northward turbulent surface stress... */
9990 if (!read_met_nc_2d
9991 (ncid, (const char *const[]) { "inss", "INSS" }, 2, ctl, met, dd,
9992 met->nss,
9993 1.0, 1))
9994 WARN("Cannot read northward turbulent surface stress!");
9995
9996 /* Read surface sensible heat flux... */
9997 if (!read_met_nc_2d
9998 (ncid, (const char *const[]) { "ishf", "ISHF" }, 2, ctl, met, dd,
9999 met->shf,
10000 1.0, 1))
10001 WARN("Cannot read surface sensible heat flux!");
10002
10003 /* Read land-sea mask... */
10004 if (!read_met_nc_2d
10005 (ncid, (const char *const[]) { "lsm", "LSM" }, 2, ctl, met, dd,
10006 met->lsm,
10007 1.0, 1))
10008 WARN("Cannot read land-sea mask!");
10009
10010 /* Read sea surface temperature... */
10011 if (!read_met_nc_2d
10012 (ncid, (const char *const[]) { "sstk", "SSTK", "sst", "SST" }, 4, ctl,
10013 met, dd, met->sst,
10014 1.0, 1))
10015 WARN("Cannot read sea surface temperature!");
10016
10017 /* Read PBL... */
10018 if (ctl->met_pbl == 0)
10019 if (!read_met_nc_2d
10020 (ncid, (const char *const[]) { "blp", "BLP" }, 2, ctl, met, dd,
10021 met->pbl,
10022 0.01f, 1))
10023 WARN("Cannot read planetary boundary layer pressure!");
10024 if (ctl->met_pbl == 1)
10025 if (!read_met_nc_2d
10026 (ncid, (const char *const[]) { "blh", "BLH" }, 2, ctl, met, dd,
10027 met->pbl,
10028 0.001f, 1))
10029 WARN("Cannot read planetary boundary layer height!");
10030
10031 /* Read CAPE... */
10032 if (ctl->met_cape == 0)
10033 if (!read_met_nc_2d
10034 (ncid, (const char *const[]) { "cape", "CAPE" }, 2, ctl, met, dd,
10035 met->cape, 1.0, 1))
10036 WARN("Cannot read CAPE!");
10037
10038 /* Read CIN... */
10039 if (ctl->met_cape == 0)
10040 if (!read_met_nc_2d
10041 (ncid, (const char *const[]) { "cin", "CIN" }, 2, ctl, met, dd,
10042 met->cin,
10043 1.0, 1))
10044 WARN("Cannot read convective inhibition!");
10045}
int read_met_nc_2d(const int ncid, const char *const varnames[], const size_t nvarnames, const ctl_t *ctl, const met_t *met, dd_t *dd, float dest[EX][EY], const float scl, const int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:10267
Here is the call graph for this function:

◆ read_met_nc_2d()

int read_met_nc_2d ( const int  ncid,
const char *const  varnames[],
const size_t  nvarnames,
const ctl_t ctl,
const met_t met,
dd_t dd,
float  dest[EX][EY],
const float  scl,
const int  init 
)

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

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

Parameters
ncidThe NetCDF file ID.
varnamesArray of variable names in order of preference.
nvarnamesNumber of entries in varnames.
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.
destThe destination array to store the read data.
sclA scaling factor to apply to the read data.
initFlag indicating whether to initialize the destination array before reading.
Returns
Returns 1 on success, 0 on failure.

The function performs the following steps:

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

Definition at line 10267 of file mptrac.c.

10276 {
10277
10278 const char *varsel = NULL;
10279
10280 float offset, scalfac;
10281
10282 int varid;
10283
10284 /* Check if variable exists... */
10285 for (size_t i = 0; i < nvarnames; i++)
10286 if (nc_inq_varid(ncid, varnames[i], &varid) == NC_NOERR) {
10287 varsel = varnames[i];
10288 break;
10289 }
10290 if (varsel == NULL)
10291 return 0;
10292
10293 /* Read packed data... */
10294 if (ctl->met_nc_scale && !ctl->dd
10295 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
10296 && nc_get_att_float(ncid, varid, "scale_factor",
10297 &scalfac) == NC_NOERR) {
10298
10299 /* Allocate... */
10300 short *help;
10301 ALLOC(help, short,
10302 EX * EY * EP);
10303
10304 /* Read fill value and missing value... */
10305 short fillval, missval;
10306 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10307 fillval = 0;
10308 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
10309 missval = 0;
10310
10311 /* Write info... */
10312 LOG(2, "Read 2-D variable: %s"
10313 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
10314 varsel, fillval, missval, scalfac, offset);
10315
10316 /* Read data... */
10317 NC(nc_get_var_short(ncid, varid, help));
10318
10319 /* Check meteo data layout... */
10320 if (ctl->met_convention != 0)
10321 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
10322
10323 /* Copy and check data... */
10324 omp_set_dynamic(1);
10325#pragma omp parallel for default(shared)
10326 for (int ix = 0; ix < met->nx; ix++)
10327 for (int iy = 0; iy < met->ny; iy++) {
10328 if (init)
10329 dest[ix][iy] = 0;
10330 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
10331 if ((fillval == 0 || aux != fillval)
10332 && (missval == 0 || aux != missval)
10333 && fabsf(aux * scalfac + offset) < 1e14f)
10334 dest[ix][iy] += scl * (aux * scalfac + offset);
10335 else
10336 dest[ix][iy] = NAN;
10337 }
10338 omp_set_dynamic(0);
10339
10340 /* Free... */
10341 free(help);
10342 }
10343
10344 /* Unpacked data... */
10345 else if (!ctl->dd) {
10346
10347 /* Allocate... */
10348 float *help;
10349 ALLOC(help, float,
10350 EX * EY);
10351
10352 /* Read fill value and missing value... */
10353 float fillval, missval;
10354 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10355 fillval = 0;
10356 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10357 missval = 0;
10358
10359 /* Write info... */
10360 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
10361 varsel, fillval, missval);
10362
10363 /* Read data... */
10364 NC(nc_get_var_float(ncid, varid, help));
10365
10366 /* Check meteo data layout... */
10367 if (ctl->met_convention == 0) {
10368
10369 /* Copy and check data (ordering: lat, lon)... */
10370 omp_set_dynamic(1);
10371#pragma omp parallel for default(shared)
10372 for (int ix = 0; ix < met->nx; ix++)
10373 for (int iy = 0; iy < met->ny; iy++) {
10374 if (init)
10375 dest[ix][iy] = 0;
10376 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
10377 if ((fillval == 0 || aux != fillval)
10378 && (missval == 0 || aux != missval)
10379 && fabsf(aux) < 1e14f)
10380 dest[ix][iy] += scl * aux;
10381 else
10382 dest[ix][iy] = NAN;
10383 }
10384 omp_set_dynamic(0);
10385
10386 } else {
10387
10388 /* Copy and check data (ordering: lon, lat)... */
10389 omp_set_dynamic(1);
10390#pragma omp parallel for default(shared)
10391 for (int iy = 0; iy < met->ny; iy++)
10392 for (int ix = 0; ix < met->nx; ix++) {
10393 if (init)
10394 dest[ix][iy] = 0;
10395 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
10396 if ((fillval == 0 || aux != fillval)
10397 && (missval == 0 || aux != missval)
10398 && fabsf(aux) < 1e14f)
10399 dest[ix][iy] += scl * aux;
10400 else
10401 dest[ix][iy] = NAN;
10402 }
10403 omp_set_dynamic(0);
10404 }
10405
10406 /* Free... */
10407 free(help);
10408 }
10409
10410 /* Domain decomposed data... */
10411 else {
10412
10413 /* Read fill value and missing value... */
10414 float fillval, missval;
10415 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10416 fillval = 0;
10417 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10418 missval = 0;
10419
10420 /* Write info... */
10421 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
10422 varsel, fillval, missval);
10423
10424 /* Define hyperslab... */
10425 float *help;
10426 size_t help_subdomain_start[3];
10427 size_t help_subdomain_count[3];
10428
10429 help_subdomain_start[0] = 0;
10430 if (ctl->met_convention == 0) {
10431 help_subdomain_start[1] = dd->subdomain_start[2];
10432 help_subdomain_start[2] = dd->subdomain_start[3];
10433 } else {
10434 help_subdomain_start[1] = dd->subdomain_start[3];
10435 help_subdomain_start[2] = dd->subdomain_start[2];
10436 }
10437
10438 help_subdomain_count[0] = 1;
10439 if (ctl->met_convention == 0) {
10440 help_subdomain_count[1] = dd->subdomain_count[2]; //y
10441 help_subdomain_count[2] = dd->subdomain_count[3]; //x
10442 } else {
10443 help_subdomain_count[1] = dd->subdomain_count[3]; //x
10444 help_subdomain_count[2] = dd->subdomain_count[2]; //y
10445 }
10446
10447 ALLOC(help, float,
10448 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
10449
10450 /* Read data... */
10451#ifdef DD
10452 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
10453#endif
10454 NC(nc_get_vara_float
10455 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
10456
10457 /* Read halos at boundaries... */
10458 size_t help_halo_bnd_start[3];
10459 size_t help_halo_bnd_count[3];
10460
10461 help_halo_bnd_start[0] = 0;
10462 if (ctl->met_convention == 0) {
10463 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
10464 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
10465 } else {
10466 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
10467 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
10468 }
10469
10470 help_halo_bnd_count[0] = 1;
10471 if (ctl->met_convention == 0) {
10472 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
10473 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
10474 } else {
10475 help_halo_bnd_count[1] = dd->halo_bnd_count[3]; //x
10476 help_halo_bnd_count[2] = dd->halo_bnd_count[2]; //y
10477 }
10478
10479 float *help_halo;
10480 ALLOC(help_halo, float,
10481 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
10482
10483#ifdef DD
10484 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
10485#endif
10486 NC(nc_get_vara_float
10487 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
10488
10489 /* Check meteo data layout... */
10490 if (ctl->met_convention == 0) {
10491
10492 /* Copy and check data (ordering: lat, lon)... */
10493 omp_set_dynamic(1);
10494#pragma omp parallel for default(shared)
10495 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
10496 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
10497 if (init == 1)
10498 dest[ix + dd->halo_offset_start][iy] = 0;
10499 const float aux =
10500 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
10501 if ((fillval == 0 || aux != fillval)
10502 && (missval == 0 || aux != missval)
10503 && fabsf(aux) < 1e14f) {
10504 dest[ix + dd->halo_offset_start][iy] += scl * aux;
10505 } else
10506 dest[ix + dd->halo_offset_start][iy] = NAN;
10507 }
10508
10509#pragma omp parallel for default(shared)
10510 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
10511 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
10512 if (init == 1)
10513 dest[ix + dd->halo_offset_end][iy] = 0;
10514 const float aux =
10515 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
10516 if ((fillval == 0 || aux != fillval)
10517 && (missval == 0 || aux != missval)
10518 && fabsf(aux) < 1e14f)
10519 dest[ix + dd->halo_offset_end][iy] += scl * aux;
10520 else {
10521 dest[ix + dd->halo_offset_end][iy] = NAN;
10522 }
10523 }
10524 omp_set_dynamic(0);
10525
10526 } else {
10527
10528 /* Copy and check data (ordering: lon, lat)... */
10529 omp_set_dynamic(1);
10530#pragma omp parallel for default(shared)
10531 for (int ix = 0; ix < (int) help_subdomain_count[1]; ix++)
10532 for (int iy = 0; iy < (int) help_subdomain_count[2]; iy++) {
10533 if (init == 1)
10534 dest[ix + dd->halo_offset_start][iy] = 0;
10535 const float aux =
10536 help[ARRAY_2D(ix, iy, (int) help_subdomain_count[1])];
10537 if ((fillval == 0 || aux != fillval)
10538 && (missval == 0 || aux != missval)
10539 && fabsf(aux) < 1e14f)
10540 dest[ix + dd->halo_offset_start][iy] += scl * aux;
10541 else
10542 dest[ix + dd->halo_offset_start][iy] = NAN;
10543 }
10544
10545#pragma omp parallel for default(shared)
10546 for (int ix = 0; ix < (int) help_halo_bnd_count[1]; ix++)
10547 for (int iy = 0; iy < (int) help_halo_bnd_count[2]; iy++) {
10548 if (init == 1)
10549 dest[ix + dd->halo_offset_end][iy] = 0;
10550 const float aux =
10551 help_halo[ARRAY_2D(ix, iy, (int) help_halo_bnd_count[1])];
10552 if ((fillval == 0 || aux != fillval)
10553 && (missval == 0 || aux != missval)
10554 && fabsf(aux) < 1e14f)
10555 dest[ix + dd->halo_offset_end][iy] += scl * aux;
10556 else
10557 dest[ix + dd->halo_offset_end][iy] = NAN;
10558 }
10559 omp_set_dynamic(0);
10560 }
10561
10562 /* Free... */
10563 free(help);
10564 free(help_halo);
10565 }
10566
10567 /* Return... */
10568 return 1;
10569}

◆ read_met_nc_3d()

int read_met_nc_3d ( const int  ncid,
const char *const  varnames[],
const size_t  nvarnames,
const ctl_t ctl,
const met_t met,
dd_t dd,
float  dest[EX][EY][EP],
const float  scl 
)

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

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

Parameters
ncidThe NetCDF file ID.
varnamesArray of variable names in order of preference.
nvarnamesNumber of entries in varnames.
ctlA pointer to a structure containing control parameters.
metA pointer to a structure containing meteorological data.
ddA pointer to an dd_t structure containing MPI information, including rank and neighbours.
destThe destination array to store the read data.
sclA scaling factor to apply to the read data.
Returns
Returns 1 on success, 0 on failure.

The function performs the following steps:

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

Definition at line 10573 of file mptrac.c.

10581 {
10582
10583 const char *varsel = NULL;
10584
10585 float offset, scalfac;
10586
10587 int varid;
10588
10589 /* Check if variable exists... */
10590 for (size_t i = 0; i < nvarnames; i++)
10591 if (nc_inq_varid(ncid, varnames[i], &varid) == NC_NOERR) {
10592 varsel = varnames[i];
10593 break;
10594 }
10595 if (varsel == NULL)
10596 return 0;
10597
10598 /* Read packed data... */
10599 if (ctl->met_nc_scale && !ctl->dd
10600 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
10601 && nc_get_att_float(ncid, varid, "scale_factor",
10602 &scalfac) == NC_NOERR) {
10603
10604 /* Allocate... */
10605 short *help;
10606 ALLOC(help, short,
10607 EX * EY * EP);
10608
10609 /* Read fill value and missing value... */
10610 short fillval, missval;
10611 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10612 fillval = 0;
10613 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
10614 missval = 0;
10615
10616 /* Write info... */
10617 LOG(2, "Read 3-D variable: %s "
10618 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
10619 varsel, fillval, missval, scalfac, offset);
10620
10621 /* Read data... */
10622 NC(nc_get_var_short(ncid, varid, help));
10623
10624 /* Check meteo data layout... */
10625 if (ctl->met_convention != 0)
10626 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
10627
10628 /* Copy and check data... */
10629 omp_set_dynamic(1);
10630#pragma omp parallel for default(shared)
10631 for (int ix = 0; ix < met->nx; ix++)
10632 for (int iy = 0; iy < met->ny; iy++)
10633 for (int ip = 0; ip < met->np; ip++) {
10634 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
10635 if ((fillval == 0 || aux != fillval)
10636 && (missval == 0 || aux != missval)
10637 && fabsf(aux * scalfac + offset) < 1e14f)
10638 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
10639 else
10640 dest[ix][iy][ip] = NAN;
10641 }
10642 omp_set_dynamic(0);
10643
10644 /* Free... */
10645 free(help);
10646 }
10647
10648 /* Unpacked data... */
10649 else if (!ctl->dd) {
10650
10651 /* Allocate... */
10652 float *help;
10653 ALLOC(help, float,
10654 EX * EY * EP);
10655
10656 /* Read fill value and missing value... */
10657 float fillval, missval;
10658 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10659 fillval = 0;
10660 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10661 missval = 0;
10662
10663 /* Write info... */
10664 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
10665 varsel, fillval, missval);
10666
10667 /* Read data... */
10668 NC(nc_get_var_float(ncid, varid, help));
10669
10670 /* Check meteo data layout... */
10671 if (ctl->met_convention == 0) {
10672
10673 /* Copy and check data (ordering: lev, lat, lon)... */
10674 omp_set_dynamic(1);
10675#pragma omp parallel for default(shared)
10676 for (int ix = 0; ix < met->nx; ix++)
10677 for (int iy = 0; iy < met->ny; iy++)
10678 for (int ip = 0; ip < met->np; ip++) {
10679 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
10680 if ((fillval == 0 || aux != fillval)
10681 && (missval == 0 || aux != missval)
10682 && fabsf(aux) < 1e14f)
10683 dest[ix][iy][ip] = scl * aux;
10684 else
10685 dest[ix][iy][ip] = NAN;
10686 }
10687 omp_set_dynamic(0);
10688
10689 } else {
10690
10691 /* Copy and check data (ordering: lon, lat, lev)... */
10692 omp_set_dynamic(1);
10693#pragma omp parallel for default(shared)
10694 for (int ip = 0; ip < met->np; ip++)
10695 for (int iy = 0; iy < met->ny; iy++)
10696 for (int ix = 0; ix < met->nx; ix++) {
10697 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
10698 if ((fillval == 0 || aux != fillval)
10699 && (missval == 0 || aux != missval)
10700 && fabsf(aux) < 1e14f)
10701 dest[ix][iy][ip] = scl * aux;
10702 else
10703 dest[ix][iy][ip] = NAN;
10704 }
10705 omp_set_dynamic(0);
10706 }
10707
10708 /* Free... */
10709 free(help);
10710 }
10711
10712 /* Domain decomposed data... */
10713 else {
10714
10715 /* Read fill value and missing value... */
10716 float fillval, missval;
10717 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10718 fillval = 0;
10719 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10720 missval = 0;
10721
10722 /* Write info... */
10723 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
10724 varsel, fillval, missval);
10725
10726 /* Define hyperslab... */
10727 size_t help_subdomain_start[4];
10728 size_t help_subdomain_count[4];
10729 size_t help_halo_bnd_start[4];
10730 size_t help_halo_bnd_count[4];
10731
10732 if (ctl->met_convention == 0) {
10733 for (int i = 0; i < 4; i++) {
10734 help_subdomain_start[i] = dd->subdomain_start[i];
10735 help_subdomain_count[i] = dd->subdomain_count[i];
10736 help_halo_bnd_start[i] = dd->halo_bnd_start[i];
10737 help_halo_bnd_count[i] = dd->halo_bnd_count[i];
10738 }
10739 } else {
10740 help_subdomain_start[0] = dd->subdomain_start[0];
10741 help_subdomain_start[1] = dd->subdomain_start[3];
10742 help_subdomain_start[2] = dd->subdomain_start[2];
10743 help_subdomain_start[3] = dd->subdomain_start[1];
10744
10745 help_subdomain_count[0] = dd->subdomain_count[0];
10746 help_subdomain_count[1] = dd->subdomain_count[3];
10747 help_subdomain_count[2] = dd->subdomain_count[2];
10748 help_subdomain_count[3] = dd->subdomain_count[1];
10749
10750 help_halo_bnd_start[0] = dd->halo_bnd_start[0];
10751 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
10752 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
10753 help_halo_bnd_start[3] = dd->halo_bnd_start[1];
10754
10755 help_halo_bnd_count[0] = dd->halo_bnd_count[0];
10756 help_halo_bnd_count[1] = dd->halo_bnd_count[3];
10757 help_halo_bnd_count[2] = dd->halo_bnd_count[2];
10758 help_halo_bnd_count[3] = dd->halo_bnd_count[1];
10759 }
10760
10761 /* Allocate... */
10762 float *help;
10763 ALLOC(help, float,
10764 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
10765 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
10766
10767 /* Use default NetCDF parallel I/O behavior */
10768#ifdef DD
10769 NC(nc_var_par_access(ncid, varid, NC_INDEPENDENT));
10770#endif
10771 NC(nc_get_vara_float
10772 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
10773
10774 /* Read halos separately at boundaries... */
10775 float *help_halo;
10776 ALLOC(help_halo, float,
10777 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
10778 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
10779
10780#ifdef DD
10781 NC(nc_var_par_access(ncid, varid, NC_INDEPENDENT));
10782#endif
10783 if (dd->halo_bnd_count[1] > 0 && dd->halo_bnd_count[2] > 0
10784 && dd->halo_bnd_count[3] > 0) {
10785 NC(nc_get_vara_float
10786 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
10787 }
10788
10789 /* Check meteo data layout... */
10790 if (ctl->met_convention == 0) {
10791
10792 /* Copy and check data (ordering: lev, lat, lon)... */
10793 omp_set_dynamic(1);
10794#pragma omp parallel for default(shared)
10795 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
10796 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10797 for (int ip = 0; ip < met->np; ip++) {
10798 const float aux =
10799 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
10800 (int) dd->subdomain_count[3])];
10801 if ((fillval == 0 || aux != fillval)
10802 && (missval == 0 || aux != missval)
10803 && fabsf(aux) < 1e14f) {
10804 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10805
10806 } else
10807 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10808 }
10809
10810#pragma omp parallel for default(shared)
10811 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
10812 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10813 for (int ip = 0; ip < met->np; ip++) {
10814 const float aux =
10815 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
10816 (int) dd->halo_bnd_count[3])];
10817 if ((fillval == 0 || aux != fillval)
10818 && (missval == 0 || aux != missval)
10819 && fabsf(aux) < 1e14f)
10820 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10821 else
10822 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10823 }
10824 omp_set_dynamic(0);
10825
10826 } else {
10827
10828 /* Copy and check data (ordering: lon, lat, lev)... */
10829 omp_set_dynamic(1);
10830#pragma omp parallel for default(shared)
10831 for (int ip = 0; ip < met->np; ip++)
10832 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10833 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
10834 const float aux =
10835 help[ARRAY_3D
10836 (ix, iy, (int) dd->subdomain_count[2], ip, met->np)];
10837 if ((fillval == 0 || aux != fillval)
10838 && (missval == 0 || aux != missval)
10839 && fabsf(aux) < 1e14f)
10840 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10841 else
10842 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10843 }
10844
10845#pragma omp parallel for default(shared)
10846 for (int ip = 0; ip < met->np; ip++)
10847 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10848 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
10849 const float aux =
10850 help_halo[ARRAY_3D(ix, iy, (int) dd->halo_bnd_count[2], ip,
10851 met->np)];
10852 if ((fillval == 0 || aux != fillval)
10853 && (missval == 0 || aux != missval)
10854 && fabsf(aux) < 1e14f)
10855 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10856 else
10857 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10858 }
10859 omp_set_dynamic(0);
10860 }
10861
10862 /* Free... */
10863 free(help);
10864 free(help_halo);
10865 }
10866
10867 /* Return... */
10868 return 1;
10869}

◆ read_met_pbl()

void read_met_pbl ( const ctl_t ctl,
met_t met 
)

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

This function determines the PBL pressure for each grid point using one of four methods: 0. Read PBL pressure from meteo data file.

  1. Read PBL heights from meteo data file and convert to pressure.
  2. Determine PBL pressure based on bulk Richardson number criterion.
  3. Determine PBL pressure Based on potential temperature difference. The calculated PBL height is constrained by user-defined minimum and maximum limits.
Parameters
[in]ctlPointer to the control structure (ctl_t), which contains parameters controlling the PBL calculation.
[in,out]metPointer to the meteorological data structure (met_t), which contains grid and atmospheric data. The met->pbl array is updated with the calculated PBL pressure.

Method 0 (Precomputed PBL pressure from file):

  • Read PBL pressure from meteo data file.

Method 1 (Precomputed PBL height from file):

  • Read PBL height from meteo data file.
  • Interpolates the PBL pressure using the geopotential heights from the meteo file.

Method 2 (Richardson number criterion):

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

Method 3 (Potential temperature difference):

  • Computes the PBL height as the altitude where the potential temperature exceeds the surface value by 2 K.
  • Interpolates between levels to find the precise height.

Final Adjustments:

  • Ensures the PBL height respects user-defined minimum and maximum thresholds.
Note
Method 2 is a standard method for estimating PBL depths, but the current implementation seems to underestimate PBL depths compared to ECMWF PBL data or Method 3. Therefore, Method 3, is selected by default. If PBL heights are available from the meteo data files, it is recommended to select Method 1.
Author
Lars Hoffmann

Definition at line 11660 of file mptrac.c.

11662 {
11663
11664 /* Set timer... */
11665 SELECT_TIMER("READ_MET_PBL", "METPROC");
11666 LOG(2, "Calculate planetary boundary layer...");
11667
11668 /* Convert PBL height from meteo file to pressure... */
11669 if (ctl->met_pbl == 1) {
11670
11671 /* Loop over grid points... */
11672#pragma omp parallel for default(shared) collapse(2)
11673 for (int ix = 0; ix < met->nx; ix++)
11674 for (int iy = 0; iy < met->ny; iy++) {
11675
11676 /* Get pressure at top of PBL... */
11677 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
11678 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
11679 met->pbl[ix][iy] =
11680 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
11681 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
11682 }
11683 }
11684
11685 /* Determine PBL based on Richardson number... */
11686 else if (ctl->met_pbl == 2) {
11687
11688 /* Parameters used to estimate the height of the PBL
11689 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
11690 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
11691
11692 /* Loop over grid points... */
11693#pragma omp parallel for default(shared) collapse(2)
11694 for (int ix = 0; ix < met->nx; ix++)
11695 for (int iy = 0; iy < met->ny; iy++) {
11696
11697 /* Set bottom level of PBL... */
11698 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
11699
11700 /* Find lowest level near the bottom... */
11701 int ip;
11702 for (ip = 1; ip < met->np; ip++)
11703 if (met->p[ip] < pbl_bot)
11704 break;
11705
11706 /* Get near surface data... */
11707 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
11708 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
11709 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
11710
11711 /* Init... */
11712 double rib_old = 0;
11713
11714 /* Loop over levels... */
11715 for (; ip < met->np; ip++) {
11716
11717 /* Get squared horizontal wind speed... */
11718 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
11719 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
11720 vh2 = MAX(vh2, SQR(umin));
11721
11722 /* Calculate bulk Richardson number... */
11723 const double rib =
11724 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
11725 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
11726 met->h2o[ix][iy][ip]) - tvs) / vh2;
11727
11728 /* Check for critical value... */
11729 if (rib >= rib_crit) {
11730 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
11731 rib, met->p[ip], rib_crit));
11732 if (met->pbl[ix][iy] > pbl_bot)
11733 met->pbl[ix][iy] = (float) pbl_bot;
11734 break;
11735 }
11736
11737 /* Save Richardson number... */
11738 rib_old = rib;
11739 }
11740 }
11741 }
11742
11743 /* Determine PBL based on potential temperature... */
11744 if (ctl->met_pbl == 3) {
11745
11746 /* Parameters used to estimate the height of the PBL
11747 (following HYSPLIT model)... */
11748 const double dtheta = 2.0, zmin = 0.1;
11749
11750 /* Loop over grid points... */
11751#pragma omp parallel for default(shared) collapse(2)
11752 for (int ix = 0; ix < met->nx; ix++)
11753 for (int iy = 0; iy < met->ny; iy++) {
11754
11755 /* Potential temperature at the surface... */
11756 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
11757
11758 /* Find topmost level where theta exceeds surface value by 2 K... */
11759 int ip;
11760 for (ip = met->np - 2; ip > 0; ip--)
11761 if (met->p[ip] >= 300.)
11762 if (met->p[ip] > met->ps[ix][iy]
11763 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
11764 break;
11765
11766 /* Interpolate... */
11767 met->pbl[ix][iy]
11768 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
11769 met->p[ip + 1],
11770 THETA(met->p[ip], met->t[ix][iy][ip]),
11771 met->p[ip], theta0 + dtheta));
11772
11773 /* Check minimum value... */
11774 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
11775 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
11776 met->pbl[ix][iy] = (float) pbl_min;
11777 }
11778 }
11779
11780 /* Loop over grid points... */
11781#pragma omp parallel for default(shared) collapse(2)
11782 for (int ix = 0; ix < met->nx; ix++)
11783 for (int iy = 0; iy < met->ny; iy++) {
11784
11785 /* Check minimum value... */
11786 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
11787 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
11788
11789 /* Check maximum value... */
11790 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
11791 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
11792 }
11793}
Here is the call graph for this function:

◆ read_met_periodic()

void read_met_periodic ( met_t met)

Applies periodic boundary conditions to meteorological data along longitudinal axis.

This function applies periodic boundary conditions to meteorological data along the longitudinal axis. It checks if the difference between the last and first longitudes and the difference between the second and first longitudes are approximately equal to 360 degrees, indicating periodicity. If the condition is met, the function increases the longitude counter, sets the longitude value for the new grid point, and copies meteorological data from the first grid point to the last grid point to ensure periodicity.

Parameters
metA pointer to a structure containing meteorological data.

The function performs the following steps:

  • Sets timer for performance monitoring.
  • Checks if the difference between the last and first longitudes and the difference between the second and first longitudes are approximately equal to 360 degrees, indicating periodicity.
  • If periodicity is confirmed:
    • Increases the longitude counter.
    • Sets the longitude value for the new grid point by adding the difference between the second and first longitudes to the longitude of the penultimate grid point.
    • Copies meteorological data from the first grid point to the last grid point to ensure periodicity:
      • Surface variables (e.g., pressure, temperature, wind speed, land-sea mask, sea surface temperature) are copied.
      • Meteorological variables at each pressure level are copied.
      • Meteorological variables at each hybrid pressure level are copied.
Note
This function is useful for generating continuous meteorological fields over a periodic domain, which is common in atmospheric modeling, especially for global simulations.
Author
Lars Hoffmann

Definition at line 11797 of file mptrac.c.

11798 {
11799
11800 /* Set timer... */
11801 SELECT_TIMER("READ_MET_PERIODIC", "METPROC");
11802 LOG(2, "Apply periodic boundary conditions...");
11803
11804 /* Check longitudes... */
11805 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
11806 + met->lon[1] - met->lon[0] - 360) < 0.01))
11807 return;
11808
11809 /* Increase longitude counter... */
11810 if ((++met->nx) >= EX)
11811 ERRMSG("Cannot create periodic boundary conditions!");
11812
11813 /* Set longitude... */
11814 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
11815
11816 /* Loop over latitudes and pressure levels... */
11817#pragma omp parallel for default(shared)
11818 for (int iy = 0; iy < met->ny; iy++) {
11819 met->ps[met->nx - 1][iy] = met->ps[0][iy];
11820 met->zs[met->nx - 1][iy] = met->zs[0][iy];
11821 met->ts[met->nx - 1][iy] = met->ts[0][iy];
11822 met->us[met->nx - 1][iy] = met->us[0][iy];
11823 met->vs[met->nx - 1][iy] = met->vs[0][iy];
11824 met->ess[met->nx - 1][iy] = met->ess[0][iy];
11825 met->nss[met->nx - 1][iy] = met->nss[0][iy];
11826 met->shf[met->nx - 1][iy] = met->shf[0][iy];
11827 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
11828 met->sst[met->nx - 1][iy] = met->sst[0][iy];
11829 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
11830 met->cape[met->nx - 1][iy] = met->cape[0][iy];
11831 met->cin[met->nx - 1][iy] = met->cin[0][iy];
11832 for (int ip = 0; ip < met->np; ip++) {
11833 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
11834 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
11835 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
11836 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
11837 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
11838 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
11839 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
11840 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
11841 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
11842 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
11843 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
11844 }
11845 for (int ip = 0; ip < met->npl; ip++) {
11846 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
11847 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
11848 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
11849 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
11850 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
11851 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
11852 }
11853 }
11854}

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

11859 {
11860
11861 /* Set timer... */
11862 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC");
11863 LOG(2, "Apply fix for polar winds...");
11864
11865 if (met->coord_type != 0)
11866 return;
11867
11868 /* Check latitudes... */
11869 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
11870 return;
11871
11872 /* Loop over hemispheres... */
11873 for (int ihem = 0; ihem < 2; ihem++) {
11874
11875 /* Set latitude indices... */
11876 int i89 = 1, i90 = 0, sign = 1;
11877 if (ihem == 1) {
11878 i89 = met->ny - 2;
11879 i90 = met->ny - 1;
11880 }
11881 if (met->lat[i90] < 0)
11882 sign = -1;
11883
11884 /* Look-up table of cosinus and sinus... */
11885 double clon[EX], slon[EX];
11886#pragma omp parallel for default(shared)
11887 for (int ix = 0; ix < met->nx; ix++) {
11888 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
11889 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
11890 }
11891
11892 /* Loop over levels... */
11893#pragma omp parallel for default(shared)
11894 for (int ip = 0; ip < met->np; ip++) {
11895
11896 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
11897 double vel89x = 0, vel89y = 0;
11898 for (int ix = 0; ix < met->nx; ix++) {
11899 vel89x +=
11900 (met->u[ix][i89][ip] * clon[ix] -
11901 met->v[ix][i89][ip] * slon[ix]) / met->nx;
11902 vel89y +=
11903 (met->u[ix][i89][ip] * slon[ix] +
11904 met->v[ix][i89][ip] * clon[ix]) / met->nx;
11905 }
11906
11907 /* Replace 90 degree winds by 89 degree mean... */
11908 for (int ix = 0; ix < met->nx; ix++) {
11909 met->u[ix][i90][ip]
11910 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
11911 met->v[ix][i90][ip]
11912 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
11913 }
11914 }
11915 }
11916}

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

11921 {
11922
11923 double pows[EP];
11924
11925 /* Set timer... */
11926 SELECT_TIMER("READ_MET_PV", "METPROC");
11927 LOG(2, "Calculate potential vorticity...");
11928
11929 /* Set powers... */
11930#pragma omp parallel for default(shared)
11931 for (int ip = 0; ip < met->np; ip++)
11932 pows[ip] = pow(1000. / met->p[ip], KAPPA);
11933
11934 /* Loop over grid points... */
11935#pragma omp parallel for default(shared)
11936 for (int ix = 0; ix < met->nx; ix++) {
11937
11938 /* Set indices... */
11939 const int ix0 = MAX(ix - 1, 0);
11940 const int ix1 = MIN(ix + 1, met->nx - 1);
11941
11942 /* Loop over grid points... */
11943 for (int iy = 0; iy < met->ny; iy++) {
11944
11945 /* Set indices... */
11946 const int iy0 = MAX(iy - 1, 0);
11947 const int iy1 = MIN(iy + 1, met->ny - 1);
11948
11949 /* Set auxiliary variables... */
11950 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
11951 double dx, dy, c0, c1, cr, vort;
11952
11953 // Calculate potential vorticity..
11954 if (met->coord_type == 0) { // coords are lat/lon
11955 dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
11956 dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
11957 c0 = cos(DEG2RAD(met->lat[iy0]));
11958 c1 = cos(DEG2RAD(met->lat[iy1]));
11959 cr = cos(DEG2RAD(latr));
11960 vort = 2 * OMEGA_EARTH * sin(DEG2RAD(latr));
11961 } else { // coords are in meters
11962 dx = met->lon[ix1] - met->lon[ix0];
11963 dy = met->lat[iy1] - met->lat[iy0];
11964
11965 c0 = 1.0;
11966 c1 = 1.0;
11967 cr = 1.0;
11968
11969 vort = 2 * OMEGA_EARTH * sin(latr / (RE * 1000));
11970 }
11971
11972 /* Loop over grid points... */
11973 for (int ip = 0; ip < met->np; ip++) {
11974
11975 /* Get gradients in longitude... */
11976 const double dtdx
11977 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
11978 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
11979
11980 /* Get gradients in latitude... */
11981 const double dtdy
11982 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
11983 const double dudy
11984 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
11985
11986 /* Set indices... */
11987 const int ip0 = MAX(ip - 1, 0);
11988 const int ip1 = MIN(ip + 1, met->np - 1);
11989
11990 /* Get gradients in pressure... */
11991 double dtdp, dudp, dvdp;
11992 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
11993 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
11994 if (ip != ip0 && ip != ip1) {
11995 double denom = dp0 * dp1 * (dp0 + dp1);
11996 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
11997 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
11998 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
11999 / denom;
12000 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
12001 - dp1 * dp1 * met->u[ix][iy][ip0]
12002 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
12003 / denom;
12004 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
12005 - dp1 * dp1 * met->v[ix][iy][ip0]
12006 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
12007 / denom;
12008 } else {
12009 const double denom = dp0 + dp1;
12010 dtdp =
12011 (met->t[ix][iy][ip1] * pows[ip1] -
12012 met->t[ix][iy][ip0] * pows[ip0]) / denom;
12013 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
12014 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
12015 }
12016
12017 /* Calculate PV... */
12018 met->pv[ix][iy][ip] = (float)
12019 (1e6 * G0 *
12020 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
12021 }
12022 }
12023 }
12024
12025 /* Fix for polar regions... */
12026#pragma omp parallel for default(shared)
12027 for (int ix = 0; ix < met->nx; ix++)
12028 for (int ip = 0; ip < met->np; ip++) {
12029 met->pv[ix][0][ip]
12030 = met->pv[ix][1][ip]
12031 = met->pv[ix][2][ip];
12032 met->pv[ix][met->ny - 1][ip]
12033 = met->pv[ix][met->ny - 2][ip]
12034 = met->pv[ix][met->ny - 3][ip];
12035 }
12036}
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:839
#define OMEGA_EARTH
Angular velocity of Earth [s^-1].
Definition: mptrac.h:329
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:818

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

12041 {
12042
12043 /* Set timer... */
12044 SELECT_TIMER("READ_MET_OZONE", "METPROC");
12045 LOG(2, "Calculate total column ozone...");
12046
12047 /* Loop over columns... */
12048#pragma omp parallel for default(shared) collapse(2)
12049 for (int ix = 0; ix < met->nx; ix++)
12050 for (int iy = 0; iy < met->ny; iy++) {
12051
12052 /* Integrate... */
12053 double cd = 0;
12054 for (int ip = 1; ip < met->np; ip++)
12055 if (met->p[ip - 1] <= met->ps[ix][iy]) {
12056 const double vmr =
12057 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
12058 const double dp = met->p[ip - 1] - met->p[ip];
12059 cd += vmr * MO3 / MA * dp * 1e2 / G0;
12060 }
12061
12062 /* Convert to Dobson units... */
12063 met->o3c[ix][iy] = (float) (cd / DOBSON_UNIT);
12064 }
12065}
#define DOBSON_UNIT
Ozone column mass corresponding to one Dobson unit [kg/m^2].
Definition: mptrac.h:334

◆ read_met_sample()

void read_met_sample ( const ctl_t ctl,
met_t met 
)

Downsamples meteorological data based on specified parameters.

This function downsamples meteorological data based on the provided control parameters. It reduces the resolution of meteorological data by averaging over specified intervals in longitude, latitude, and altitude.

Parameters
ctlA pointer to a structure containing control parameters for downsampling.
metA pointer to a structure containing meteorological data to be downsampled.

The function performs the following steps:

  • Checks if downsampling parameters are set to a value less than or equal to 1, if so, returns without downsampling.
  • Sets a timer for performance monitoring.
  • Allocates memory for a temporary meteorological data structure.
  • Copies metadata from the original structure to the temporary structure.
  • Performs downsampling by smoothing over specified intervals:
    • Computes weighted averages over the specified intervals.
    • Updates the temporary structure with the smoothed values.
  • Downsamples the smoothed data:
    • Updates longitude and latitude arrays with downsampled values.
    • Stores downsampled meteorological variables in the original structure.
  • Frees memory allocated for the temporary structure.
Note
Downsampling meteorological data can be useful for reducing computational cost while preserving essential features for modeling and analysis.
Author
Lars Hoffmann

Definition at line 12069 of file mptrac.c.

12071 {
12072
12073 met_t *help;
12074
12075 /* Check parameters... */
12076 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
12077 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
12078 return;
12079
12080 /* Set timer... */
12081 SELECT_TIMER("READ_MET_SAMPLE", "METPROC");
12082 LOG(2, "Downsampling of meteo data...");
12083
12084 /* Allocate... */
12085 ALLOC(help, met_t, 1);
12086
12087 /* Copy data... */
12088 help->nx = met->nx;
12089 help->ny = met->ny;
12090 help->np = met->np;
12091 memcpy(help->lon, met->lon, sizeof(met->lon));
12092 memcpy(help->lat, met->lat, sizeof(met->lat));
12093 memcpy(help->p, met->p, sizeof(met->p));
12094
12095 /* Smoothing... */
12096 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
12097 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
12098 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
12099 help->ps[ix][iy] = 0;
12100 help->zs[ix][iy] = 0;
12101 help->ts[ix][iy] = 0;
12102 help->us[ix][iy] = 0;
12103 help->vs[ix][iy] = 0;
12104 help->ess[ix][iy] = 0;
12105 help->nss[ix][iy] = 0;
12106 help->shf[ix][iy] = 0;
12107 help->lsm[ix][iy] = 0;
12108 help->sst[ix][iy] = 0;
12109 help->pbl[ix][iy] = 0;
12110 help->cape[ix][iy] = 0;
12111 help->cin[ix][iy] = 0;
12112 help->t[ix][iy][ip] = 0;
12113 help->u[ix][iy][ip] = 0;
12114 help->v[ix][iy][ip] = 0;
12115 help->w[ix][iy][ip] = 0;
12116 help->h2o[ix][iy][ip] = 0;
12117 help->o3[ix][iy][ip] = 0;
12118 help->lwc[ix][iy][ip] = 0;
12119 help->rwc[ix][iy][ip] = 0;
12120 help->iwc[ix][iy][ip] = 0;
12121 help->swc[ix][iy][ip] = 0;
12122 help->cc[ix][iy][ip] = 0;
12123 float wsum = 0;
12124 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
12125 ix2++) {
12126 int ix3 = ix2;
12127 if (ix3 < 0)
12128 ix3 += met->nx;
12129 else if (ix3 >= met->nx)
12130 ix3 -= met->nx;
12131
12132 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
12133 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
12134 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
12135 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
12136 const float w =
12137 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
12138 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
12139 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
12140 help->ps[ix][iy] += w * met->ps[ix3][iy2];
12141 help->zs[ix][iy] += w * met->zs[ix3][iy2];
12142 help->ts[ix][iy] += w * met->ts[ix3][iy2];
12143 help->us[ix][iy] += w * met->us[ix3][iy2];
12144 help->vs[ix][iy] += w * met->vs[ix3][iy2];
12145 help->ess[ix][iy] += w * met->ess[ix3][iy2];
12146 help->nss[ix][iy] += w * met->nss[ix3][iy2];
12147 help->shf[ix][iy] += w * met->shf[ix3][iy2];
12148 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
12149 help->sst[ix][iy] += w * met->sst[ix3][iy2];
12150 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
12151 help->cape[ix][iy] += w * met->cape[ix3][iy2];
12152 help->cin[ix][iy] += w * met->cin[ix3][iy2];
12153 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
12154 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
12155 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
12156 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
12157 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
12158 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
12159 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
12160 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
12161 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
12162 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
12163 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
12164 wsum += w;
12165 }
12166 }
12167 help->ps[ix][iy] /= wsum;
12168 help->zs[ix][iy] /= wsum;
12169 help->ts[ix][iy] /= wsum;
12170 help->us[ix][iy] /= wsum;
12171 help->vs[ix][iy] /= wsum;
12172 help->ess[ix][iy] /= wsum;
12173 help->nss[ix][iy] /= wsum;
12174 help->shf[ix][iy] /= wsum;
12175 help->lsm[ix][iy] /= wsum;
12176 help->sst[ix][iy] /= wsum;
12177 help->pbl[ix][iy] /= wsum;
12178 help->cape[ix][iy] /= wsum;
12179 help->cin[ix][iy] /= wsum;
12180 help->t[ix][iy][ip] /= wsum;
12181 help->u[ix][iy][ip] /= wsum;
12182 help->v[ix][iy][ip] /= wsum;
12183 help->w[ix][iy][ip] /= wsum;
12184 help->h2o[ix][iy][ip] /= wsum;
12185 help->o3[ix][iy][ip] /= wsum;
12186 help->lwc[ix][iy][ip] /= wsum;
12187 help->rwc[ix][iy][ip] /= wsum;
12188 help->iwc[ix][iy][ip] /= wsum;
12189 help->swc[ix][iy][ip] /= wsum;
12190 help->cc[ix][iy][ip] /= wsum;
12191 }
12192 }
12193 }
12194
12195 /* Downsampling... */
12196 met->nx = 0;
12197 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
12198 met->lon[met->nx] = help->lon[ix];
12199 met->ny = 0;
12200 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
12201 met->lat[met->ny] = help->lat[iy];
12202 met->ps[met->nx][met->ny] = help->ps[ix][iy];
12203 met->zs[met->nx][met->ny] = help->zs[ix][iy];
12204 met->ts[met->nx][met->ny] = help->ts[ix][iy];
12205 met->us[met->nx][met->ny] = help->us[ix][iy];
12206 met->vs[met->nx][met->ny] = help->vs[ix][iy];
12207 met->ess[met->nx][met->ny] = help->ess[ix][iy];
12208 met->nss[met->nx][met->ny] = help->nss[ix][iy];
12209 met->shf[met->nx][met->ny] = help->shf[ix][iy];
12210 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
12211 met->sst[met->nx][met->ny] = help->sst[ix][iy];
12212 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
12213 met->cape[met->nx][met->ny] = help->cape[ix][iy];
12214 met->cin[met->nx][met->ny] = help->cin[ix][iy];
12215 met->np = 0;
12216 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
12217 met->p[met->np] = help->p[ip];
12218 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
12219 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
12220 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
12221 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
12222 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
12223 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
12224 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
12225 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
12226 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
12227 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
12228 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
12229 met->np++;
12230 }
12231 met->ny++;
12232 }
12233 met->nx++;
12234 }
12235
12236 /* Free... */
12237 free(help);
12238}

◆ read_met_tropo()

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

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

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

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

The function performs the following steps:

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

Definition at line 12242 of file mptrac.c.

12245 {
12246
12247 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
12248 th2[200], z[EP], z2[200];
12249
12250 /* Set timer... */
12251 SELECT_TIMER("READ_MET_TROPO", "METPROC");
12252 LOG(2, "Calculate tropopause...");
12253
12254 /* Get altitude and pressure profiles... */
12255#pragma omp parallel for default(shared)
12256 for (int iz = 0; iz < met->np; iz++)
12257 z[iz] = Z(met->p[iz]);
12258#pragma omp parallel for default(shared)
12259 for (int iz = 0; iz <= 190; iz++) {
12260 z2[iz] = 4.5 + 0.1 * iz;
12261 p2[iz] = P(z2[iz]);
12262 }
12263
12264 /* Do not calculate tropopause... */
12265 if (ctl->met_tropo == 0)
12266#pragma omp parallel for default(shared) collapse(2)
12267 for (int ix = 0; ix < met->nx; ix++)
12268 for (int iy = 0; iy < met->ny; iy++)
12269 met->pt[ix][iy] = NAN;
12270
12271 /* Use tropopause climatology... */
12272 else if (ctl->met_tropo == 1) {
12273 if (met->coord_type != 0)
12274 ERRMSG("Only lat/lon grid supported");
12275#pragma omp parallel for default(shared) collapse(2)
12276 for (int ix = 0; ix < met->nx; ix++)
12277 for (int iy = 0; iy < met->ny; iy++)
12278 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
12279 }
12280
12281 /* Use cold point... */
12282 else if (ctl->met_tropo == 2) {
12283
12284 /* Loop over grid points... */
12285#pragma omp parallel for default(shared) private(t,t2) collapse(2)
12286 for (int ix = 0; ix < met->nx; ix++)
12287 for (int iy = 0; iy < met->ny; iy++) {
12288
12289 /* Interpolate temperature profile... */
12290 for (int iz = 0; iz < met->np; iz++)
12291 t[iz] = met->t[ix][iy][iz];
12292 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
12293
12294 /* Find minimum... */
12295 int iz = (int) gsl_stats_min_index(t2, 1, 171);
12296 if (iz > 0 && iz < 170)
12297 met->pt[ix][iy] = (float) p2[iz];
12298 else
12299 met->pt[ix][iy] = NAN;
12300 }
12301 }
12302
12303 /* Use WMO definition... */
12304 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
12305
12306 /* Loop over grid points... */
12307#pragma omp parallel for default(shared) private(t,t2) collapse(2)
12308 for (int ix = 0; ix < met->nx; ix++)
12309 for (int iy = 0; iy < met->ny; iy++) {
12310
12311 /* Interpolate temperature profile... */
12312 int iz;
12313 for (iz = 0; iz < met->np; iz++)
12314 t[iz] = met->t[ix][iy][iz];
12315 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
12316
12317 /* Find 1st tropopause... */
12318 met->pt[ix][iy] = NAN;
12319 for (iz = 0; iz <= 170; iz++) {
12320 int found = 1;
12321 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
12322 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
12323 found = 0;
12324 break;
12325 }
12326 if (found) {
12327 if (iz > 0 && iz < 170)
12328 met->pt[ix][iy] = (float) p2[iz];
12329 break;
12330 }
12331 }
12332
12333 /* Find 2nd tropopause... */
12334 if (ctl->met_tropo == 4) {
12335 met->pt[ix][iy] = NAN;
12336 for (; iz <= 170; iz++) {
12337 int found = 1;
12338 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
12339 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
12340 found = 0;
12341 break;
12342 }
12343 if (found)
12344 break;
12345 }
12346 for (; iz <= 170; iz++) {
12347 int found = 1;
12348 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
12349 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
12350 found = 0;
12351 break;
12352 }
12353 if (found) {
12354 if (iz > 0 && iz < 170)
12355 met->pt[ix][iy] = (float) p2[iz];
12356 break;
12357 }
12358 }
12359 }
12360 }
12361 }
12362
12363 /* Use dynamical tropopause... */
12364 else if (ctl->met_tropo == 5) {
12365
12366 /* Loop over grid points... */
12367#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
12368 for (int ix = 0; ix < met->nx; ix++)
12369 for (int iy = 0; iy < met->ny; iy++) {
12370
12371 /* Interpolate potential vorticity profile... */
12372 for (int iz = 0; iz < met->np; iz++)
12373 pv[iz] = met->pv[ix][iy][iz];
12374 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
12375
12376 /* Interpolate potential temperature profile... */
12377 for (int iz = 0; iz < met->np; iz++)
12378 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
12379 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
12380
12381 /* Find dynamical tropopause... */
12382 met->pt[ix][iy] = NAN;
12383 for (int iz = 0; iz <= 170; iz++)
12384 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
12385 || th2[iz] >= ctl->met_tropo_theta) {
12386 if (iz > 0 && iz < 170)
12387 met->pt[ix][iy] = (float) p2[iz];
12388 break;
12389 }
12390 }
12391 }
12392
12393 else
12394 ERRMSG("Cannot calculate tropopause!");
12395
12396 /* Interpolate temperature, geopotential height, and water vapor... */
12397#pragma omp parallel for default(shared) collapse(2)
12398 for (int ix = 0; ix < met->nx; ix++)
12399 for (int iy = 0; iy < met->ny; iy++) {
12400 double h2ot, tt, zt;
12402 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
12403 met->lat[iy], &tt, ci, cw, 1);
12404 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
12405 met->lat[iy], &zt, ci, cw, 0);
12406 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
12407 met->lat[iy], &h2ot, ci, cw, 0);
12408 met->tt[ix][iy] = (float) tt;
12409 met->zt[ix][iy] = (float) zt;
12410 met->h2ot[ix][iy] = (float) h2ot;
12411 }
12412}
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:12622
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:1331
Here is the call graph for this function:

◆ read_obs()

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

Reads observation data from a file and stores it in arrays.

This function reads observation data from a specified file in either ASCII or NetCDF format, depending on the value of the OBS_TYPE control parameter. It stores the time, altitude, longitude, latitude, and observation values in the provided arrays.

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

The function performs the following steps:

  • Logs an informational message indicating the observation data file being read.
  • Reads the observation data from the file based on the OBS_TYPE control parameter:
    • If ctl->obs_type == 0, it reads the data from an ASCII file using the read_obs_asc function.
    • If ctl->obs_type == 1, it reads the data from a NetCDF file using the read_obs_nc function.
    • If ctl->obs_type is neither 0 nor 1, it generates an error message indicating that the OBS_TYPE must be set to 0 or 1.
  • Checks if the time values are in ascending order and generates an error message if not.
  • Logs statistical information about the observation data, including the number of observations, time range, altitude range, longitude range, latitude range, and observation value range.
Note
The function assumes that the observation data file is formatted correctly and that the arrays provided have sufficient memory allocated to store the data.
Author
Lars Hoffmann
Mingzhao Liu

Definition at line 12416 of file mptrac.c.

12424 {
12425
12426 /* Write info... */
12427 LOG(1, "Read observation data: %s", filename);
12428
12429 /* Read data... */
12430 if (ctl->obs_type == 0)
12431 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
12432 else if (ctl->obs_type == 1)
12433 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
12434 else
12435 ERRMSG("Set OBS_TYPE to 0 or 1!");
12436
12437 /* Check time... */
12438 for (int i = 1; i < *nobs; i++)
12439 if (rt[i] < rt[i - 1])
12440 ERRMSG("Time must be ascending!");
12441
12442 /* Write info... */
12443 int n = *nobs;
12444 double mini, maxi;
12445 LOG(2, "Number of observations: %d", *nobs);
12446 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
12447 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
12448 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
12449 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
12450 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
12451 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
12452 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
12453 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
12454 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
12455 LOG(2, "Observation range: %g ... %g", mini, maxi);
12456}
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:12460
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:12488
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 12460 of file mptrac.c.

12467 {
12468
12469 /* Open observation data file... */
12470 FILE *in;
12471 if (!(in = fopen(filename, "r")))
12472 ERRMSG("Cannot open file!");
12473
12474 /* Read observations... */
12475 char line[LEN];
12476 while (fgets(line, LEN, in))
12477 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
12478 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
12479 if ((++(*nobs)) >= NOBS)
12480 ERRMSG("Too many observations!");
12481
12482 /* Close observation data file... */
12483 fclose(in);
12484}
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:588

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

12495 {
12496
12497 int ncid, varid;
12498
12499 /* Open netCDF file... */
12500 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
12501 ERRMSG("Cannot open file!");
12502
12503 /* Read the observations from the NetCDF file... */
12504 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
12505 NC_GET_DOUBLE("time", rt, 1);
12506 NC_GET_DOUBLE("alt", rz, 1);
12507 NC_GET_DOUBLE("lon", rlon, 1);
12508 NC_GET_DOUBLE("lat", rlat, 1);
12509 NC_GET_DOUBLE("obs", robs, 1);
12510
12511 /* Close file... */
12512 NC(nc_close(ncid));
12513}

◆ scan_ctl()

double scan_ctl ( const char *  filename,
int  argc,
char *  argv[],
const char *  varname,
const int  arridx,
const char *  defvalue,
char *  value 
)

Scans a control file or command-line arguments for a specified variable.

This function scans either a control file or command-line arguments for a specified variable name and retrieves its value. It searches for the variable name in the control file or command-line arguments and returns its corresponding value. If the variable is not found, it returns a default value specified by the user.

Parameters
filenameThe name of the control file to be scanned. If NULL, only command-line arguments will be scanned.
argcThe number of command-line arguments.
argvAn array of command-line arguments.
varnameThe name of the variable to be searched.
arridxThe index of the variable array, if applicable. Set to -1 if not an array.
defvalueThe default value to be returned if the variable is not found.
valueA pointer to a character array to store the retrieved value.
Returns
The retrieved value of the variable as a double.

The function performs the following steps:

  • Attempts to open the specified control file in read mode using the fopen function. If the filename ends with a '-', the file is not opened.
  • Constructs the full variable name based on the variable name and array index provided.
  • Reads data from the control file, searching for the full variable name. If found, it sets the contain flag to 1 and breaks the loop.
  • Searches through the command-line arguments for the full variable name. If found, it sets the value and contain flag and breaks the loop.
  • Closes the control file if opened.
  • If the variable is not found, it sets the value to the default value provided or throws an error if no default value is provided.
  • Writes the variable name and its value to the log.
  • Copies the retrieved value to the value parameter if it is not NULL.
  • Returns the retrieved value as a double after converting it from a string using the atof function.
Note
This function assumes that the variable names and their values in the control file or command-line arguments are separated by whitespace.
Author
Lars Hoffmann

Definition at line 12517 of file mptrac.c.

12524 {
12525
12526 FILE *in = NULL;
12527
12528 char fullname1[LEN], fullname2[LEN], rval[LEN];
12529
12530 int contain = 0, i;
12531
12532 /* Open file... */
12533 if (filename[strlen(filename) - 1] != '-')
12534 if (!(in = fopen(filename, "r")))
12535 ERRMSG("Cannot open file!");
12536
12537 /* Set full variable name... */
12538 if (arridx >= 0) {
12539 sprintf(fullname1, "%s[%d]", varname, arridx);
12540 sprintf(fullname2, "%s[*]", varname);
12541 } else {
12542 sprintf(fullname1, "%s", varname);
12543 sprintf(fullname2, "%s", varname);
12544 }
12545
12546 /* Read data... */
12547 if (in != NULL) {
12548 char dummy[LEN], line[LEN], rvarname[LEN];
12549 while (fgets(line, LEN, in)) {
12550 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
12551 if (strcasecmp(rvarname, fullname1) == 0 ||
12552 strcasecmp(rvarname, fullname2) == 0) {
12553 contain = 1;
12554 break;
12555 }
12556 }
12557 }
12558 for (i = 1; i < argc - 1; i++)
12559 if (strcasecmp(argv[i], fullname1) == 0 ||
12560 strcasecmp(argv[i], fullname2) == 0) {
12561 sprintf(rval, "%s", argv[i + 1]);
12562 contain = 1;
12563 break;
12564 }
12565
12566 /* Close file... */
12567 if (in != NULL)
12568 fclose(in);
12569
12570 /* Check for missing variables... */
12571 if (!contain) {
12572 if (strlen(defvalue) > 0)
12573 sprintf(rval, "%s", defvalue);
12574 else
12575 ERRMSG("Missing variable %s!\n", fullname1);
12576 }
12577
12578 /* Write info... */
12579 LOG(1, "%s = %s", fullname1, rval);
12580
12581 /* Return values... */
12582 if (value != NULL)
12583 sprintf(value, "%s", rval);
12584 return atof(rval);
12585}

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

12593 {
12594
12595 /* Convert particle radius from microns to m... */
12596 const double rp_help = rp * 1e-6;
12597
12598 /* Density of dry air [kg / m^3]... */
12599 const double rho = RHO(p, T);
12600
12601 /* Dynamic viscosity of air [kg / (m s)]... */
12602 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
12603
12604 /* Thermal velocity of an air molecule [m / s]... */
12605 const double v = sqrt(8. * KB * T / (M_PI * M_AIR_MOLECULE));
12606
12607 /* Mean free path of an air molecule [m]... */
12608 const double lambda = 2. * eta / (rho * v);
12609
12610 /* Knudsen number for air (dimensionless)... */
12611 const double K = lambda / rp_help;
12612
12613 /* Cunningham slip-flow correction (dimensionless)... */
12614 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
12615
12616 /* Sedimentation velocity [m / s]... */
12617 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
12618}
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:284
#define M_AIR_MOLECULE
Mean mass of an air molecule [kg].
Definition: mptrac.h:339

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

12629 {
12630
12631 /* Cubic spline interpolation... */
12632 if (method == 1) {
12633
12634 /* Allocate... */
12635 gsl_interp_accel *acc = gsl_interp_accel_alloc();
12636 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
12637
12638 /* Interpolate profile... */
12639 gsl_spline_init(s, x, y, (size_t) n);
12640 for (int i = 0; i < n2; i++)
12641 if (x2[i] <= x[0])
12642 y2[i] = y[0];
12643 else if (x2[i] >= x[n - 1])
12644 y2[i] = y[n - 1];
12645 else
12646 y2[i] = gsl_spline_eval(s, x2[i], acc);
12647
12648 /* Free... */
12649 gsl_spline_free(s);
12650 gsl_interp_accel_free(acc);
12651 }
12652
12653 /* Linear interpolation... */
12654 else {
12655 for (int i = 0; i < n2; i++)
12656 if (x2[i] <= x[0])
12657 y2[i] = y[0];
12658 else if (x2[i] >= x[n - 1])
12659 y2[i] = y[n - 1];
12660 else {
12661 const int idx = locate_irr(x, n, x2[i]);
12662 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
12663 }
12664 }
12665}
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 12669 of file mptrac.c.

12671 {
12672
12673 if (n <= 0)
12674 return 0;
12675
12676 float mean = 0, var = 0;
12677
12678 for (int i = 0; i < n; ++i) {
12679 mean += data[i];
12680 var += SQR(data[i]);
12681 }
12682
12683 var = var / (float) n - SQR(mean / (float) n);
12684
12685 return (var > 0 ? sqrtf(var) : 0);
12686}

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

12698 {
12699
12700 struct tm t0, t1;
12701
12702 t0.tm_year = 100;
12703 t0.tm_mon = 0;
12704 t0.tm_mday = 1;
12705 t0.tm_hour = 0;
12706 t0.tm_min = 0;
12707 t0.tm_sec = 0;
12708
12709 t1.tm_year = year - 1900;
12710 t1.tm_mon = mon - 1;
12711 t1.tm_mday = day;
12712 t1.tm_hour = hour;
12713 t1.tm_min = min;
12714 t1.tm_sec = sec;
12715
12716 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
12717}

◆ timer()

void timer ( const char *  name,
const char *  group,
const int  output 
)

Measures and reports elapsed time for named and grouped timers.

The timer function measures elapsed time for a specified named timer and an optional group of timers, accumulating time statistics such as minimum, maximum, and mean elapsed times. It also provides an option to log the timing statistics to an output.

Parameters
nameA string representing the name of the timer.
groupA string representing the group to which the timer belongs.
outputAn integer flag indicating whether to report the timing statistics (non-zero to report).

The function keeps track of multiple timers and groups. When called, it:

  • Gets the current time and calculates the elapsed time since the last call.
  • Adds the elapsed time to the current timers' statistics.
  • Reports the statistics if the output parameter is non-zero.
  • Identifies the IDs of the next timer and group based on the provided name and group.
  • Checks if the name and group are new, and if so, initializes them.
  • Saves the starting time for the next measurement.
Note
The function uses OpenMP's omp_get_wtime() to get the current wall time.
The function maintains static arrays and variables to store timer names, groups, and statistics.
The maximum number of timers and groups is defined by the NTIMER macro.
Warning
If the number of timers or groups exceeds NTIMER, the function will trigger an error message.
Author
Lars Hoffmann

Definition at line 12721 of file mptrac.c.

12724 {
12725
12726 static char names[NTIMER][100], groups[NTIMER][100];
12727
12728 static double rt_name[NTIMER], rt_group[NTIMER],
12729 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
12730
12731 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
12732
12733 /* Get time... */
12734 t1 = omp_get_wtime();
12735 dt = t1 - t0;
12736
12737 /* Add elapsed time to current timers... */
12738 if (iname >= 0) {
12739 rt_name[iname] += dt;
12740 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
12741 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
12742 ct_name[iname]++;
12743 }
12744 if (igroup >= 0)
12745 rt_group[igroup] += t1 - t0;
12746
12747 /* Report timers... */
12748 if (output) {
12749 for (int i = 0; i < nname; i++)
12750 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
12751 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
12752 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
12753 for (int i = 0; i < ngroup; i++)
12754 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
12755 double total = 0.0;
12756 for (int i = 0; i < nname; i++)
12757 total += rt_name[i];
12758 LOG(1, "TIMER_TOTAL = %.3f s", total);
12759 }
12760
12761 /* Identify IDs of next timer... */
12762 for (iname = 0; iname < nname; iname++)
12763 if (strcasecmp(name, names[iname]) == 0)
12764 break;
12765 for (igroup = 0; igroup < ngroup; igroup++)
12766 if (strcasecmp(group, groups[igroup]) == 0)
12767 break;
12768
12769 /* Check whether this is a new timer... */
12770 if (iname >= nname) {
12771 sprintf(names[iname], "%s", name);
12772 if ((++nname) >= NTIMER)
12773 ERRMSG("Too many timers!");
12774 }
12775
12776 /* Check whether this is a new group... */
12777 if (igroup >= ngroup) {
12778 sprintf(groups[igroup], "%s", group);
12779 if ((++ngroup) >= NTIMER)
12780 ERRMSG("Too many groups!");
12781 }
12782
12783 /* Save starting time... */
12784 t0 = t1;
12785}
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2460

◆ time_from_filename()

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

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

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

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

The function performs the following steps:

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

Definition at line 12789 of file mptrac.c.

12792 {
12793
12794 char tstr[10];
12795
12796 double t;
12797
12798 /* Get time from filename... */
12799 int len = (int) strlen(filename);
12800 sprintf(tstr, "%.4s", &filename[len - offset]);
12801 int year = atoi(tstr);
12802 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
12803 int mon = atoi(tstr);
12804 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
12805 int day = atoi(tstr);
12806 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
12807 int hour = atoi(tstr);
12808 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
12809 int min = atoi(tstr);
12810
12811 int sec = 0;
12812 if (with_seconds) {
12813 sprintf(tstr, "%.2s", &filename[len - offset + 17]);
12814 sec = atoi(tstr);
12815 }
12816
12817 /* Check time... */
12818 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
12819 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
12820 ERRMSG("Cannot read time from filename!");
12821
12822 /* Convert time to Julian seconds... */
12823 time2jsec(year, mon, day, hour, min, sec, 0.0, &t);
12824
12825 /* Return time... */
12826 return t;
12827}
Here is the call graph for this function:

◆ tropo_weight()

double tropo_weight ( const ctl_t ctl,
const clim_t clim,
const atm_t atm,
const int  ip 
)

Computes a weighting factor based on tropopause pressure.

This function calculates a weighting factor for a given pressure value in relation to the tropopause pressure. The weighting factor is determined as follows:

  • Returns 1 if the pressure is greater than a calculated upper limit.
  • Returns 0 if the pressure is less than a calculated lower limit.
  • Linearly interpolates between 1 and 0 within the range defined by the upper and lower limits.
Parameters
[in]ctlPointer to the control data structure.
[in]climPointer to the climatology data structure.
[in]atmPointer to the atmospheric data structure.
[in]ipIndex of the pressure value to evaluate within the atmospheric data.
Returns
Weighting factor (double) in the range [0, 1].
Author
Lars Hoffmann

Definition at line 12831 of file mptrac.c.

12835 {
12836
12837 /* Get tropopause pressure... */
12838 const double pt = clim_tropo(clim, atm->time[ip],
12839 ctl->met_coord_type ==
12840 0 ? atm->lat[ip] : ctl->met_utm_ref_lat);
12841
12842 /* Get pressure range... */
12843 const double p1 = pt * 0.866877899;
12844 const double p0 = pt / 0.866877899;
12845
12846 /* Get weighting factor... */
12847 if (atm->p[ip] > p0)
12848 return 1;
12849 else if (atm->p[ip] < p1)
12850 return 0;
12851 else
12852 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
12853}
Here is the call graph for this function:

◆ write_atm_asc()

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

Writes air parcel data to an ASCII file or gnuplot.

The write_atm_asc function writes the atmospheric data stored in the atm structure to an ASCII file specified by filename or to pipe to gnuplot if requested.

Parameters
filenameA string representing the name of the file to write the data to.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.
tThe current time used for filtering and timestamping.

The function performs the following steps:

  • Sets the time interval for the output data based on the control parameters.
  • Checks if gnuplot output is requested and, if so, creates a pipe to gnuplot and sets up the plot.
  • If gnuplot output is not requested, creates an ASCII file for writing.
  • Writes the header information to the output file, including the description of each column.
  • Iterates over the particles in the atm structure, filtering by time if specified, and writes the data to the output file.
  • Closes the output file or gnuplot pipe.
Author
Lars Hoffmann

Definition at line 12857 of file mptrac.c.

12861 {
12862
12863 FILE *out;
12864
12865 /* Set time interval for output... */
12866 const double t0 = t - 0.5 * ctl->dt_mod;
12867 const double t1 = t + 0.5 * ctl->dt_mod;
12868
12869 /* Check if gnuplot output is requested... */
12870 if (ctl->atm_gpfile[0] != '-') {
12871
12872 /* Create gnuplot pipe... */
12873 if (!(out = popen("gnuplot", "w")))
12874 ERRMSG("Cannot create pipe to gnuplot!");
12875
12876 /* Set plot filename... */
12877 fprintf(out, "set out \"%s.png\"\n", filename);
12878
12879 /* Set time string... */
12880 double r;
12881 int year, mon, day, hour, min, sec;
12882 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12883 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12884 year, mon, day, hour, min);
12885
12886 /* Dump gnuplot file to pipe... */
12887 FILE *in;
12888 if (!(in = fopen(ctl->atm_gpfile, "r")))
12889 ERRMSG("Cannot open file!");
12890 char line[LEN];
12891 while (fgets(line, LEN, in))
12892 fprintf(out, "%s", line);
12893 fclose(in);
12894 }
12895
12896 else {
12897
12898 /* Create file... */
12899 if (!(out = fopen(filename, "w")))
12900 ERRMSG("Cannot create file!");
12901 }
12902
12903 /* Write header... */
12904
12905 if (ctl->met_coord_type == 0) {
12906 fprintf(out,
12907 "# $1 = time [s]\n"
12908 "# $2 = altitude [km]\n"
12909 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12910 } else {
12911 fprintf(out,
12912 "# $1 = time [s]\n"
12913 "# $2 = altitude [km]\n" "# $3 = x [m]\n" "# $4 = y [m]\n");
12914 }
12915
12916 for (int iq = 0; iq < ctl->nq; iq++)
12917 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
12918 ctl->qnt_unit[iq]);
12919 fprintf(out, "\n");
12920
12921 /* Write data... */
12922 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
12923
12924 /* Check time... */
12925 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12926 continue;
12927
12928 /* Write output... */
12929 if (ctl->met_coord_type == 0) {
12930 fprintf(out, "%.2f %g %g %g",
12931 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]
12932 );
12933 } else {
12934 fprintf(out, "%.2f %g %.2f %.2f",
12935 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]
12936 );
12937 }
12938
12939 for (int iq = 0; iq < ctl->nq; iq++) {
12940 fprintf(out, " ");
12941 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12942 fprintf(out, ctl->qnt_format[iq], NAN);
12943 else
12944 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
12945 }
12946 fprintf(out, "\n");
12947 }
12948
12949 /* Close file... */
12950 fclose(out);
12951}
Here is the call graph for this function:

◆ write_atm_bin()

void write_atm_bin ( const char *  filename,
const ctl_t ctl,
const atm_t atm 
)

Writes air parcel data to a binary file.

The write_atm_bin function writes the air parcel data stored in the atm structure to a binary file specified by filename. The function includes versioning information and ensures that all relevant data arrays are written in a consistent binary format.

Parameters
filenameA string representing the name of the file to write the data to.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.

The function performs the following steps:

  • Creates the binary file for writing. If the file cannot be created, it triggers an error message.
  • Writes a version number for the binary data format.
  • Writes the number of particles to the file.
  • Writes the time, pressure, longitude, and latitude arrays to the file.
  • Iterates over the quantities specified in the ctl structure and writes each quantity array to the file.
  • Writes a final flag to indicate the end of the binary data.
  • Closes the file.
Author
Lars Hoffmann

Definition at line 12955 of file mptrac.c.

12958 {
12959
12960 FILE *out;
12961
12962 /* Create file... */
12963 if (!(out = fopen(filename, "w")))
12964 ERRMSG("Cannot create file!");
12965
12966 /* Write version of binary data... */
12967 int version = 100;
12968 FWRITE(&version, int,
12969 1,
12970 out);
12971
12972 /* Write data... */
12973 FWRITE(&atm->np, int,
12974 1,
12975 out);
12976 FWRITE(atm->time, double,
12977 (size_t) atm->np,
12978 out);
12979 FWRITE(atm->p, double,
12980 (size_t) atm->np,
12981 out);
12982 FWRITE(atm->lon, double,
12983 (size_t) atm->np,
12984 out);
12985 FWRITE(atm->lat, double,
12986 (size_t) atm->np,
12987 out);
12988 for (int iq = 0; iq < ctl->nq; iq++)
12989 FWRITE(atm->q[iq], double,
12990 (size_t) atm->np,
12991 out);
12992
12993 /* Write final flag... */
12994 int final = 999;
12995 FWRITE(&final, int,
12996 1,
12997 out);
12998
12999 /* Close file... */
13000 fclose(out);
13001}

◆ write_atm_clams()

void write_atm_clams ( const char *  filename,
const ctl_t ctl,
const atm_t atm 
)

Writes air parcel data to a NetCDF file in the CLaMS format.

The write_atm_clams function creates a NetCDF file and writes air parcel data into it. The data includes time, latitude, longitude, pressure, and other specified quantities. The function defines the dimensions and variables, sets global attributes, and writes the data to the file.

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

The function performs the following steps:

  • Creates the NetCDF file with the specified filename.
  • Defines the dimensions for time and the number of particles (NPARTS).
  • Defines variables for time, latitude, longitude, pressure, zeta, and other quantities.
  • Sets global attributes for the vertical coordinate name and model.
  • Writes the data into the NetCDF file.
  • Closes the NetCDF file after writing.
Author
Jan Clemens

Definition at line 13005 of file mptrac.c.

13008 {
13009
13010 if (ctl->met_coord_type != 0)
13011 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
13012
13013 int tid, pid, ncid, varid;
13014 size_t start[2], count[2];
13015
13016 /* Create file... */
13017 NC(nc_create(filename, NC_NETCDF4, &ncid));
13018
13019 /* Define dimensions... */
13020 NC(nc_def_dim(ncid, "time", 1, &tid));
13021 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
13022
13023 /* Define variables and their attributes... */
13024 int dim_ids[2] = { tid, pid };
13025 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
13026 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
13027 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
13028 ctl->atm_nc_level, 0);
13029 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
13030 ctl->atm_nc_level, 0);
13031 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
13032 ctl->atm_nc_level, 0);
13033 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
13034 for (int iq = 0; iq < ctl->nq; iq++)
13035 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
13036 ctl->qnt_name[iq], ctl->qnt_unit[iq],
13037 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
13038
13039 /* Define global attributes... */
13040 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
13041 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
13042
13043 /* End definitions... */
13044 NC(nc_enddef(ncid));
13045
13046 /* Write data... */
13047 NC_PUT_DOUBLE("time", atm->time, 0);
13048 NC_PUT_DOUBLE("LAT", atm->lat, 0);
13049 NC_PUT_DOUBLE("LON", atm->lon, 0);
13050 NC_PUT_DOUBLE("PRESS", atm->p, 0);
13051 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
13052 for (int iq = 0; iq < ctl->nq; iq++)
13053 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
13054
13055 /* Close file... */
13056 NC(nc_close(ncid));
13057}
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1717
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1536
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1631

◆ write_atm_clams_traj()

void write_atm_clams_traj ( const char *  dirname,
const ctl_t ctl,
const atm_t atm,
const double  t 
)

Writes CLaMS trajectory data to a NetCDF file.

The write_atm_clams_traj function writes trajectory data for the CLaMS model to a NetCDF file. The file is created and populated with data including time, latitude, longitude, pressure, and other quantities. The function also handles the creation of a final initialization file at the last time step.

Parameters
dirnameA string representing the directory name where the file will be created.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure containing atmospheric data.
tThe current time in seconds since a reference epoch.

The function performs the following steps:

  • Determines the start and stop times of the calculation.
  • Constructs the output filename based on the start and stop times.
  • Defines the hyperslab for the trajectory file.
  • Creates the NetCDF file if it's the first time step and defines dimensions and variables.
  • Writes the trajectory data to the NetCDF file.
  • At the last time step, creates an initialization file with the final data.
Author
Jan Clemens

Definition at line 13061 of file mptrac.c.

13065 {
13066
13067 if (ctl->met_coord_type != 0)
13068 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
13069
13070 /* Global Counter... */
13071 static size_t out_cnt = 0;
13072
13073 double r, r_start, r_stop;
13074 int year, mon, day, hour, min, sec;
13075 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
13076 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
13077 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
13078
13079 int ncid, varid, tid, pid, cid;
13080 int dim_ids[2];
13081
13082 /* time, nparc */
13083 size_t start[2];
13084 size_t count[2];
13085
13086 /* Determine start and stop times of calculation... */
13087 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
13088 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
13089 &min_start, &sec_start, &r_start);
13090 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
13091 &min_stop, &sec_stop, &r_stop);
13092
13093 sprintf(filename_out,
13094 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
13095 year_start % 100, mon_start, day_start, hour_start,
13096 year_stop % 100, mon_stop, day_stop, hour_stop);
13097 LOG(1, "Write traj file: %s", filename_out);
13098
13099 /* Define hyperslap for the traj_file... */
13100 start[0] = out_cnt;
13101 start[1] = 0;
13102 count[0] = 1;
13103 count[1] = (size_t) atm->np;
13104
13105 /* Create the file at the first timestep... */
13106 if (out_cnt == 0) {
13107
13108 /* Create file... */
13109 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
13110
13111 /* Define dimensions... */
13112 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
13113 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
13114 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
13115 dim_ids[0] = tid;
13116 dim_ids[1] = pid;
13117
13118 /* Define variables and their attributes... */
13119 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
13120 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
13121 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
13122 ctl->atm_nc_level, 0);
13123 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
13124 ctl->atm_nc_level, 0);
13125 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
13126 ctl->atm_nc_level, 0);
13127 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
13128 ctl->atm_nc_level, 0);
13129 for (int iq = 0; iq < ctl->nq; iq++)
13130 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
13131 ctl->qnt_name[iq], ctl->qnt_unit[iq],
13132 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
13133
13134 /* Define global attributes... */
13135 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
13136 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
13137
13138 /* End definitions... */
13139 NC(nc_enddef(ncid));
13140 NC(nc_close(ncid));
13141 }
13142
13143 /* Increment global counter to change hyperslap... */
13144 out_cnt++;
13145
13146 /* Open file... */
13147 NC(nc_open(filename_out, NC_WRITE, &ncid));
13148
13149 /* Write data... */
13150 NC_PUT_DOUBLE("time", atm->time, 1);
13151 NC_PUT_DOUBLE("LAT", atm->lat, 1);
13152 NC_PUT_DOUBLE("LON", atm->lon, 1);
13153 NC_PUT_DOUBLE("PRESS", atm->p, 1);
13154 if (ctl->advect_vert_coord == 1) {
13155 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
13156 } else if (ctl->qnt_zeta >= 0) {
13157 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
13158 }
13159 for (int iq = 0; iq < ctl->nq; iq++)
13160 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
13161
13162 /* Close file... */
13163 NC(nc_close(ncid));
13164
13165 /* At the last time step create the init_fix_YYYYMMDDHH file... */
13166 if ((year == year_stop) && (mon == mon_stop)
13167 && (day == day_stop) && (hour == hour_stop)) {
13168
13169 /* Set filename... */
13170 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
13171 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
13172 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
13173 LOG(1, "Write init file: %s", filename_init);
13174
13175 /* Create file... */
13176 NC(nc_create(filename_init, NC_NETCDF4, &ncid));
13177
13178 /* Define dimensions... */
13179 NC(nc_def_dim(ncid, "time", 1, &tid));
13180 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
13181 dim_ids[0] = tid;
13182 dim_ids[1] = pid;
13183
13184 /* Define variables and their attributes... */
13185 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
13186 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
13187 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
13188 ctl->atm_nc_level, 0);
13189 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
13190 ctl->atm_nc_level, 0);
13191 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
13192 ctl->atm_nc_level, 0);
13193 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
13194 for (int iq = 0; iq < ctl->nq; iq++)
13195 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
13196 ctl->qnt_name[iq], ctl->qnt_unit[iq],
13197 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
13198
13199 /* Define global attributes... */
13200 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
13201 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
13202
13203 /* End definitions... */
13204 NC(nc_enddef(ncid));
13205
13206 /* Write data... */
13207 NC_PUT_DOUBLE("time", atm->time, 0);
13208 NC_PUT_DOUBLE("LAT", atm->lat, 0);
13209 NC_PUT_DOUBLE("LON", atm->lon, 0);
13210 NC_PUT_DOUBLE("PRESS", atm->p, 0);
13211 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
13212 for (int iq = 0; iq < ctl->nq; iq++)
13213 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
13214
13215 /* Close file... */
13216 NC(nc_close(ncid));
13217 }
13218}
Here is the call graph for this function:

◆ write_atm_nc()

void write_atm_nc ( const char *  filename,
const ctl_t ctl,
const atm_t atm 
)

Writes air parcel data to a NetCDF file.

The write_atm_nc function creates a NetCDF file and writes air parcel data into it. The data includes time, pressure, longitude, latitude, and other specified quantities. The function defines the dimensions and variables, sets global attributes, and writes the data to the file.

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

The function performs the following steps:

  • Creates the NetCDF file with the specified filename.
  • Defines the dimension for the number of observations (obs).
  • Defines variables for time, pressure, longitude, latitude, and other quantities.
  • Sets global attributes for the feature type.
  • Writes the data into the NetCDF file.
  • Closes the NetCDF file after writing.
Author
Lars Hoffmann

Definition at line 13222 of file mptrac.c.

13225 {
13226
13227 int ncid, obsid, varid;
13228
13229 size_t start[2], count[2];
13230
13231 /* Create file... */
13232 NC(nc_create(filename, NC_NETCDF4, &ncid));
13233
13234 /* Define dimensions... */
13235 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
13236
13237 /* Define variables and their attributes... */
13238 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
13239 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
13240 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
13241 ctl->atm_nc_level, 0);
13242 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
13243 ctl->atm_nc_level, 0);
13244 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
13245 ctl->atm_nc_level, 0);
13246 for (int iq = 0; iq < ctl->nq; iq++)
13247 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
13248 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
13249 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
13250
13251 /* Define global attributes... */
13252 NC_PUT_ATT_GLOBAL("featureType", "point");
13253
13254 /* End definitions... */
13255 NC(nc_enddef(ncid));
13256
13257 /* Write data... */
13258 NC_PUT_DOUBLE("time", atm->time, 0);
13259 NC_PUT_DOUBLE("press", atm->p, 0);
13260 NC_PUT_DOUBLE("lon", atm->lon, 0);
13261 NC_PUT_DOUBLE("lat", atm->lat, 0);
13262 for (int iq = 0; iq < ctl->nq; iq++)
13263 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
13264
13265 /* Close file... */
13266 NC(nc_close(ncid));
13267}

◆ write_budget()

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

Writes a time series of the atmospheric tracer mass budget.

The output contains the number of active air parcels, their total mass, and sums of the configured cumulative mass-loss quantities. If ensembles are enabled, one row per ensemble and an additional total row are written. Domain-decomposed runs report the local budget of each subdomain. Missing mass-loss quantities are reported as NaN.

Parameters
filenamePath to the budget output file.
ctlPointer to the control structure.
atmPointer to the atmospheric data structure.
tCurrent model time [s].
Author
Lars Hoffmann

Definition at line 13271 of file mptrac.c.

13275 {
13276
13277 static FILE *out;
13278
13279 /* Set timer... */
13280 SELECT_TIMER("WRITE_BUDGET", "OUTPUT");
13281
13282 /* Check quantities... */
13283 if (ctl->qnt_m < 0)
13284 ERRMSG("Need quantity mass!");
13285 const int ensemble = (ctl->nens > 0);
13286 if (ensemble && ctl->qnt_ens < 0)
13287 ERRMSG("Missing ensemble IDs!");
13288 if (ctl->nens > NENS)
13289 ERRMSG("Too many ensembles!");
13290
13291 /* Initialize output file... */
13292 if (out == NULL) {
13293 LOG(1, "Write mass budget data: %s", filename);
13294 if (!(out = fopen(filename, "w")))
13295 ERRMSG("Cannot create file!");
13296 fprintf(out,
13297 "# $1 = time [s]\n"
13298 "# $2 = ensemble ID (-999=total)\n"
13299 "# $3 = number of active air parcels [1]\n"
13300 "# $4 = total mass [kg]\n"
13301 "# $5 = mass loss due to OH chemistry [kg]\n"
13302 "# $6 = mass loss due to H2O2 chemistry [kg]\n"
13303 "# $7 = mass loss due to KPP chemistry [kg]\n"
13304 "# $8 = mass loss due to wet deposition [kg]\n"
13305 "# $9 = mass loss due to dry deposition [kg]\n"
13306 "# $10 = mass loss due to exponential decay [kg]\n"
13307 "# $11 = total tracked mass loss [kg]\n"
13308 "# $12 = accounted mass [kg]\n\n");
13309 }
13310
13311 /* Calculate mass budget... */
13312 const int nq = 7;
13313 const int qnt[7] = {
13314 ctl->qnt_m, ctl->qnt_mloss_oh, ctl->qnt_mloss_h2o2,
13315 ctl->qnt_mloss_kpp, ctl->qnt_mloss_wet, ctl->qnt_mloss_dry,
13316 ctl->qnt_mloss_decay
13317 };
13318 double sum[NENS + 1][7] = { {0} };
13319 int np[NENS + 1] = { 0 };
13320 const double t0 = t - 0.5 * ctl->dt_mod;
13321 const double t1 = t + 0.5 * ctl->dt_mod;
13322
13323 /* Sum active air parcels... */
13324 for (int ip = 0; ip < atm->np; ip++) {
13325 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13326 continue;
13327 int e = 0;
13328 if (ensemble) {
13329 e = (int) atm->q[ctl->qnt_ens][ip];
13330 if (e < 0 || e >= ctl->nens)
13331 ERRMSG("Ensemble ID out of range!");
13332 }
13333 np[e]++;
13334 np[NENS]++;
13335 for (int iq = 0; iq < nq; iq++)
13336 if (qnt[iq] >= 0) {
13337 sum[e][iq] += atm->q[qnt[iq]][ip];
13338 sum[NENS][iq] += atm->q[qnt[iq]][ip];
13339 }
13340 }
13341
13342 /* Write total and ensemble budgets... */
13343 for (int ie = -1; ie < (ensemble ? ctl->nens : 0); ie++) {
13344 const int e = (ie < 0 ? NENS : ie);
13345 double mloss = 0;
13346 for (int iq = 1; iq < nq; iq++)
13347 if (qnt[iq] >= 0)
13348 mloss += sum[e][iq];
13349 fprintf(out, "%.2f %d %d %g", t, ie < 0 ? -999 : ie, np[e], sum[e][0]);
13350 for (int iq = 1; iq < nq; iq++)
13351 fprintf(out, " %g", qnt[iq] >= 0 ? sum[e][iq] : NAN);
13352 fprintf(out, " %g %g\n", mloss, sum[e][0] + mloss);
13353 }
13354 fflush(out);
13355
13356 /* Finalize... */
13357 if (t == ctl->t_stop) {
13358 fclose(out);
13359 out = NULL;
13360 }
13361}
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:583

◆ write_csi()

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

Writes Critical Success Index (CSI) data to a file.

The write_csi function processes air parcel and observation data to calculate and write various verification statistics, including the Critical Success Index (CSI), to a specified output file at regular intervals. The statistics include measures such as the number of hits, misses, and false alarms, bias, probability of detection, false alarm rate, equitable threat score, and correlation coefficients.

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

The function performs the following steps:

  • Initializes resources and sets up the output file if the current time is the start time.
  • Reads observation data and kernel data if provided.
  • Sets grid box sizes and horizontal coordinates.
  • Allocates memory for mean and count arrays.
  • Loops over observations and model data to accumulate mean values and counts.
  • Analyzes the grid cells to calculate CSI and other statistics.
  • Writes the calculated statistics to the output file at specified intervals.
  • Frees allocated resources and closes the file when the processing is complete.
Author
Lars Hoffmann

Definition at line 13365 of file mptrac.c.

13369 {
13370
13371 if (ctl->met_coord_type != 0)
13372 ERRMSG("Only lat/lon grid supported");
13373
13374 static FILE *out;
13375
13376 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
13377 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
13378
13379 static int *obscount, nobs, nk;
13380
13381 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
13382
13383 const int ensemble = (ctl->nens > 0);
13384
13385 /* Set timer */
13386 SELECT_TIMER("WRITE_CSI", "OUTPUT");
13387
13388 /* Check quantities... */
13389 if (ctl->qnt_m < 0)
13390 ERRMSG("Need quantity mass!");
13391 if (ensemble) {
13392 if (ctl->qnt_ens < 0)
13393 ERRMSG("Missing ensemble IDs!");
13394 if (ctl->nens > NENS)
13395 ERRMSG("Too many ensembles!");
13396 }
13397
13398 /* Init... */
13399 if (t == ctl->t_start) {
13400
13401 /* Allocate.. */
13402 ALLOC(area, double,
13403 ctl->csi_ny);
13404 ALLOC(rt, double,
13405 NOBS);
13406 ALLOC(rz, double,
13407 NOBS);
13408 ALLOC(rlon, double,
13409 NOBS);
13410 ALLOC(rlat, double,
13411 NOBS);
13412 ALLOC(robs, double,
13413 NOBS);
13414
13415 /* Read observation data... */
13416 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13417
13418 /* Read kernel data... */
13419 if (ctl->csi_kernel[0] != '-')
13420 read_kernel(ctl->csi_kernel, kz, kw, &nk);
13421
13422 /* Create new file... */
13423 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
13424 if (!(out = fopen(filename, "w")))
13425 ERRMSG("Cannot create file!");
13426
13427 /* Write header... */
13428 fprintf(out,
13429 "# $1 = time [s]\n"
13430 "# $2 = ensemble ID\n"
13431 "# $3 = number of hits (cx)\n"
13432 "# $4 = number of misses (cy)\n"
13433 "# $5 = number of false alarms (cz)\n"
13434 "# $6 = number of observations (cx + cy)\n"
13435 "# $7 = number of forecasts (cx + cz)\n"
13436 "# $8 = bias (%%)\n"
13437 "# $9 = POD (%%)\n"
13438 "# $10 = FAR (%%)\n"
13439 "# $11 = CSI (%%)\n"
13440 "# $12 = hits by random chance\n"
13441 "# $13 = ETS (%%)\n"
13442 "# $14 = Pearson R\n"
13443 "# $15 = Spearman R\n"
13444 "# $16 = mean error [kg/m²]\n"
13445 "# $17 = RMSE [kg/m²]\n"
13446 "# $18 = MAE [kg/m²]\n"
13447 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
13448
13449 /* Set grid box size... */
13450 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
13451 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
13452 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
13453
13454 /* Set horizontal coordinates... */
13455 for (int iy = 0; iy < ctl->csi_ny; iy++) {
13456 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
13457 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
13458 }
13459 }
13460
13461 /* Set time interval... */
13462 const double t0 = t - 0.5 * ctl->dt_mod;
13463 const double t1 = t + 0.5 * ctl->dt_mod;
13464
13465 /* Allocate... */
13466 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
13467 ALLOC(modmean, double,
13468 (ensemble ? ctl->nens : 1) * grid_size);
13469 ALLOC(obsmean, double,
13470 grid_size);
13471 ALLOC(obscount, int,
13472 grid_size);
13473 ALLOC(obsstd, double,
13474 grid_size);
13475
13476 /* Init... */
13477 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
13478 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
13479
13480 /* Loop over observations... */
13481 for (int i = 0; i < nobs; i++) {
13482 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
13483 continue;
13484
13485 /* Check grid boundaries and calculate indices... */
13486 if (rlon[i] < ctl->csi_lon0 || rlon[i] >= ctl->csi_lon1
13487 || rlat[i] < ctl->csi_lat0 || rlat[i] >= ctl->csi_lat1
13488 || rz[i] < ctl->csi_z0 || rz[i] >= ctl->csi_z1)
13489 continue;
13490 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
13491 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
13492 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
13493 if (ix >= ctl->csi_nx || iy >= ctl->csi_ny || iz >= ctl->csi_nz)
13494 continue;
13495
13496 /* Get mean observation index... */
13497 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
13498 obsmean[idx] += robs[i];
13499 obsstd[idx] += SQR(robs[i]);
13500 obscount[idx]++;
13501 }
13502
13503 /* Analyze model data... */
13504 for (int ip = 0; ip < atm->np; ip++) {
13505
13506 /* Check time... */
13507 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13508 continue;
13509
13510 /* Get ensemble ID... */
13511 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
13512 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
13513 ERRMSG("Ensemble ID out of range!");
13514
13515 /* Check grid boundaries and get indices... */
13516 const double zpart = Z(atm->p[ip]);
13517 if (atm->lon[ip] < ctl->csi_lon0
13518 || atm->lon[ip] >= ctl->csi_lon1
13519 || atm->lat[ip] < ctl->csi_lat0
13520 || atm->lat[ip] >= ctl->csi_lat1
13521 || zpart < ctl->csi_z0 || zpart >= ctl->csi_z1)
13522 continue;
13523 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
13524 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
13525 const int iz = (int) ((zpart - ctl->csi_z0) / dz);
13526 if (ix >= ctl->csi_nx || iy >= ctl->csi_ny || iz >= ctl->csi_nz)
13527 continue;
13528
13529 /* Get total mass in grid cell... */
13530 const int idx =
13531 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
13532 modmean[idx] +=
13533 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13534 }
13535 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
13536 /* Analyze all grid cells... */
13537 for (int ix = 0; ix < ctl->csi_nx; ix++)
13538 for (int iy = 0; iy < ctl->csi_ny; iy++)
13539 for (int iz = 0; iz < ctl->csi_nz; iz++) {
13540
13541 /* Calculate mean observation index... */
13542 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
13543 if (e == 0)
13544 if (obscount[idx]) {
13545 obsmean[idx] /= obscount[idx];
13546 obsstd[idx] =
13547 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
13548 }
13549
13550 /* Calculate model mean per ensemble... */
13551 const int midx = e * grid_size + idx;
13552 if (modmean[midx] > 0)
13553 modmean[midx] /= (1e6 * area[iy]);
13554
13555 /* Check number of observations... */
13556 if (obscount[idx]) {
13557
13558 /* Calculate CSI... */
13559 ct[e]++;
13560 if (obsmean[idx] >= ctl->csi_obsmin
13561 && modmean[midx] >= ctl->csi_modmin)
13562 cx[e]++;
13563 else if (obsmean[idx] >= ctl->csi_obsmin)
13564 cy[e]++;
13565 else if (modmean[midx] >= ctl->csi_modmin)
13566 cz[e]++;
13567
13568 /* Save data for other verification statistics... */
13569 if (obsmean[idx] >= ctl->csi_obsmin
13570 || modmean[midx] >= ctl->csi_modmin) {
13571 x[n[e]] = modmean[midx];
13572 y[n[e]] = obsmean[idx];
13573 if (modmean[midx] >= ctl->csi_modmin)
13574 obsstdn[n[e]] = obsstd[idx];
13575 if ((++n[e]) >= NCSI)
13576 ERRMSG("Too many points for statistics!");
13577 }
13578 }
13579 }
13580 /* Write output... */
13581 if (fmod(t, ctl->csi_dt_out) == 0) {
13582
13583 if (n[e] == 0)
13584 continue;
13585
13586 /* Calculate verification statistics
13587 (https://www.cawcr.gov.au/projects/verification/) ... */
13588 static double work[2 * NCSI], work2[2 * NCSI];
13589 const int n_obs = cx[e] + cy[e];
13590 const int n_for = cx[e] + cz[e];
13591 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
13592 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
13593 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
13594 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
13595 const double csi =
13596 (cx[e] + cy[e] + cz[e] >
13597 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
13598 const double ets =
13599 (cx[e] + cy[e] + cz[e] - cx_rd >
13600 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
13601 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
13602 const double rho_s =
13603 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
13604 for (int i = 0; i < n[e]; i++) {
13605 work[i] = x[i] - y[i];
13606 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
13607 }
13608 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
13609 const double rmse =
13610 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
13611 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
13612 const double loglikelihood =
13613 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
13614
13615 /* Write... */
13616 fprintf(out,
13617 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
13618 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
13619 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
13620 loglikelihood, n[e]);
13621
13622 /* Set counters to zero... */
13623 for (int i = 0; i < n[e]; i++)
13624 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
13625 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
13626 }
13627 }
13628 /* Free... */
13629 free(modmean);
13630 free(obsmean);
13631 free(obscount);
13632 free(obsstd);
13633
13634 /* Finalize... */
13635 if (t == ctl->t_stop) {
13636
13637 /* Close output file... */
13638 fclose(out);
13639
13640 /* Free... */
13641 free(area);
13642 free(rt);
13643 free(rz);
13644 free(rlon);
13645 free(rlat);
13646 free(robs);
13647 }
13648}
void read_obs(const char *filename, const ctl_t *ctl, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
Reads observation data from a file and stores it in arrays.
Definition: mptrac.c:12416
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:8915
double kernel_weight(const double kz[EP], const double kw[EP], const int nk, const double p)
Calculates the kernel weight based on altitude and given kernel data.
Definition: mptrac.c:3298
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:578
Here is the call graph for this function:

◆ write_csi_ens()

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

Writes ensemble-based Critical Success Index (CSI) and other verification statistics to an output file.

This function computes and writes various statistical verification metrics that assess the performance of ensemble forecasts compared to observations. The output includes, for each ensemble member:

  • Critical Success Index (CSI)
  • Equitable Threat Score (ETS)
  • Bias (forecast/observation ratio)
  • Probability of Detection (POD)
  • False Alarm Rate (FAR)
  • Correlation coefficients (Pearson, Spearman)
  • Error metrics (mean error, RMSE, mean absolute error)
  • Log-likelihood of the normalized errors

On the first invocation (when t == ctl->t_start), the function loads observation data and kernel weights, allocates necessary arrays, and creates a new output file with a descriptive header. On the final call (when t == ctl->t_stop), the function closes the file and frees all persistent memory.

Output is written at time steps divisible by ctl->csi_dt_out.

Parameters
[in]filenamePath to the output file where statistics will be written.
[in]ctlPointer to control structure containing configuration, ensemble settings, and spatial/time grid info.
[in]atmPointer to atmospheric data structure holding model output.
[in]tCurrent simulation/model time.
Note
This function maintains internal static buffers and handles memory management across time steps. It validates input configuration and will terminate with an error message if required quantities are missing or if limits (e.g., number of ensembles or data points) are exceeded.
Exceptions
Ifrequired quantities (mass or ensemble IDs) are undefined, if ensemble IDs are out of bounds, or if the output file cannot be created.
Author
Mingzhao Liu

◆ write_ens()

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

Writes ensemble data to a file.

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

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

The function performs the following steps:

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

Definition at line 13652 of file mptrac.c.

13656 {
13657
13658 if (ctl->met_coord_type != 0)
13659 ERRMSG("Only lat/lon grid supported");
13660
13661 static FILE *out;
13662
13663 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
13664 x[3], zm[NENS];
13665
13666 static int n[NENS];
13667
13668 /* Set timer... */
13669 SELECT_TIMER("WRITE_ENS", "OUTPUT");
13670
13671 /* Check quantities... */
13672 if (ctl->qnt_ens < 0)
13673 ERRMSG("Missing ensemble IDs!");
13674
13675 /* Set time interval... */
13676 const double t0 = t - 0.5 * ctl->dt_mod;
13677 const double t1 = t + 0.5 * ctl->dt_mod;
13678
13679 /* Init... */
13680 for (int i = 0; i < NENS; i++) {
13681 for (int iq = 0; iq < ctl->nq; iq++)
13682 qm[iq][i] = qs[iq][i] = 0;
13683 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
13684 n[i] = 0;
13685 }
13686
13687 /* Loop over air parcels... */
13688 for (int ip = 0; ip < atm->np; ip++) {
13689
13690 /* Check time... */
13691 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13692 continue;
13693
13694 /* Check ensemble ID... */
13695 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
13696 ERRMSG("Ensemble ID is out of range!");
13697
13698 /* Get means... */
13699 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
13700 for (int iq = 0; iq < ctl->nq; iq++) {
13701 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
13702 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
13703 }
13704 xm[ctl->qnt_ens][0] += x[0];
13705 xm[ctl->qnt_ens][1] += x[1];
13706 xm[ctl->qnt_ens][2] += x[2];
13707 zm[ctl->qnt_ens] += Z(atm->p[ip]);
13708 n[ctl->qnt_ens]++;
13709 }
13710
13711 /* Create file... */
13712 LOG(1, "Write ensemble data: %s", filename);
13713 if (!(out = fopen(filename, "w")))
13714 ERRMSG("Cannot create file!");
13715
13716 /* Write header... */
13717 fprintf(out,
13718 "# $1 = time [s]\n"
13719 "# $2 = altitude [km]\n"
13720 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13721 for (int iq = 0; iq < ctl->nq; iq++)
13722 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
13723 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13724 for (int iq = 0; iq < ctl->nq; iq++)
13725 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
13726 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13727 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
13728
13729 /* Write data... */
13730 for (int i = 0; i < NENS; i++)
13731 if (n[i] > 0) {
13732 cart2geo(xm[i], &dummy, &lon, &lat);
13733 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
13734 for (int iq = 0; iq < ctl->nq; iq++) {
13735 fprintf(out, " ");
13736 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
13737 }
13738 for (int iq = 0; iq < ctl->nq; iq++) {
13739 fprintf(out, " ");
13740 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
13741 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
13742 }
13743 fprintf(out, " %d\n", n[i]);
13744 }
13745
13746 /* Close file... */
13747 fclose(out);
13748}
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
Here is the call graph for this function:

◆ write_depo()

void write_depo ( const char *  filename,
const ctl_t ctl,
const depo_t depo,
const double  t 
)

Convert cumulative ground inventories to Bq m^-2 and write them.

Cell centers and areas are derived from GRID_LON*, GRID_LAT*, GRID_NX, and GRID_NY. If RADIO_DECAY is enabled, inventories are decayed to t. Output format is selected by DEPO_TYPE.

Parameters
[in]filenameOutput filename.
[in]ctlGrid, format, compression, and decay settings.
[in]depoCumulative radionuclide inventories.
[in]tOutput validity time [s since 2000-01-01 00:00 UTC].

Definition at line 13752 of file mptrac.c.

13756 {
13757
13758 double *area, *data, *lat, *lon;
13759
13760 /* Set timer... */
13761 SELECT_TIMER("WRITE_DEPO", "OUTPUT");
13762 LOG(1, "Write radioactive deposition data: %s", filename);
13763
13764 /* Allocate output arrays... */
13765 const int nxy = ctl->grid_nx * ctl->grid_ny;
13766 ALLOC(area, double,
13767 ctl->grid_ny);
13768 ALLOC(data, double,
13769 4 * nxy);
13770 ALLOC(lat, double,
13771 ctl->grid_ny);
13772 ALLOC(lon, double,
13773 ctl->grid_nx);
13774
13775 /* Set horizontal coordinates and grid-cell areas... */
13776 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
13777 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
13778 for (int ix = 0; ix < ctl->grid_nx; ix++)
13779 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
13780 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13781 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
13782 area[iy] = 1e6 * dlat * dlon * SQR(RE * M_PI / 180.)
13783 * cos(DEG2RAD(lat[iy]));
13784 }
13785
13786 /* Convert inventories to activity densities at output time... */
13787 const double lambda[4] = {
13788 log(2.0) / RADIO_HALF_LIFE_PB210,
13789 log(2.0) / RADIO_HALF_LIFE_BE7,
13790 log(2.0) / RADIO_HALF_LIFE_CS137,
13791 log(2.0) / RADIO_HALF_LIFE_I131
13792 };
13793 const double *inventory[4] = {
13794 depo->Apb210, depo->Abe7, depo->Acs137, depo->Ai131
13795 };
13796 for (int iq = 0; iq < 4; iq++) {
13797 const double decay = ctl->radio_decay
13798 ? exp(-lambda[iq] * (t - ctl->t_start)) : 1.0;
13799 for (int ix = 0; ix < ctl->grid_nx; ix++)
13800 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13801 const int idx = ARRAY_2D(ix, iy, ctl->grid_ny);
13802 data[iq * nxy + idx] = inventory[iq][idx] * decay / area[iy];
13803 }
13804 }
13805
13806 /* Write output... */
13807 if (ctl->depo_type == 0)
13808 write_depo_asc(filename, ctl, data, t, lon, lat, area);
13809 else if (ctl->depo_type == 1)
13810 write_depo_nc(filename, ctl, data, t, lon, lat, area);
13811 else
13812 ERRMSG("Radioactive deposition output type unknown!");
13813
13814 /* Free... */
13815 free(area);
13816 free(data);
13817 free(lat);
13818 free(lon);
13819}
void write_depo_asc(const char *filename, const ctl_t *ctl, const double *data, const double t, const double *lon, const double *lat, const double *area)
Write radioactive deposition densities as a gnuplot-compatible table.
Definition: mptrac.c:13823
void write_depo_nc(const char *filename, const ctl_t *ctl, const double *data, const double t, const double *lon, const double *lat, const double *area)
Write radioactive deposition densities as a CF-style netCDF file.
Definition: mptrac.c:13863
Here is the call graph for this function:

◆ write_depo_asc()

void write_depo_asc ( const char *  filename,
const ctl_t ctl,
const double *  data,
const double  t,
const double *  lon,
const double *  lat,
const double *  area 
)

Write radioactive deposition densities as a gnuplot-compatible table.

Parameters
[in]filenameOutput filename.
[in]ctlDeposition grid dimensions.
[in]dataFour consecutive fields in Bq m^-2.
[in]tOutput validity time [s since 2000-01-01 00:00 UTC].
[in]lonGrid-cell center longitudes [deg].
[in]latGrid-cell center latitudes [deg].
[in]areaGrid-cell areas by latitude [m^2].

Definition at line 13823 of file mptrac.c.

13830 {
13831
13832 FILE *out;
13833 if (!(out = fopen(filename, "w")))
13834 ERRMSG("Cannot create file!");
13835
13836 fprintf(out,
13837 "# $1 = time [s]\n"
13838 "# $2 = longitude [deg]\n"
13839 "# $3 = latitude [deg]\n"
13840 "# $4 = area [m^2]\n"
13841 "# $5 = deposited Pb-210 activity [Bq/m^2]\n"
13842 "# $6 = deposited Be-7 activity [Bq/m^2]\n"
13843 "# $7 = deposited Cs-137 activity [Bq/m^2]\n"
13844 "# $8 = deposited I-131 activity [Bq/m^2]\n\n");
13845
13846 const int nxy = ctl->grid_nx * ctl->grid_ny;
13847 for (int ix = 0; ix < ctl->grid_nx; ix++) {
13848 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13849 const int idx = ARRAY_2D(ix, iy, ctl->grid_ny);
13850 fprintf(out, "%.2f %g %g %g %g %g %g %g\n",
13851 t, lon[ix], lat[iy], area[iy],
13852 data[idx], data[nxy + idx],
13853 data[2 * nxy + idx], data[3 * nxy + idx]);
13854 }
13855 fprintf(out, "\n");
13856 }
13857
13858 fclose(out);
13859}

◆ write_depo_nc()

void write_depo_nc ( const char *  filename,
const ctl_t ctl,
const double *  data,
const double  t,
const double *  lon,
const double *  lat,
const double *  area 
)

Write radioactive deposition densities as a CF-style netCDF file.

Parameters
[in]filenameOutput filename.
[in]ctlDeposition grid dimensions and netCDF compression setting.
[in]dataFour consecutive fields in Bq m^-2.
[in]tOutput validity time [s since 2000-01-01 00:00 UTC].
[in]lonGrid-cell center longitudes [deg].
[in]latGrid-cell center latitudes [deg].
[in]areaGrid-cell areas by latitude [m^2].

Definition at line 13863 of file mptrac.c.

13870 {
13871
13872 double *help;
13873 int ncid, dimid[3], varid;
13874 size_t start[2], count[2];
13875
13876 const int nxy = ctl->grid_nx * ctl->grid_ny;
13877 ALLOC(help, double,
13878 nxy);
13879
13880 /* Create file and dimensions... */
13881 NC(nc_create(filename, NC_NETCDF4, &ncid));
13882 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
13883 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[1]));
13884 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[2]));
13885
13886 /* Define variables... */
13887 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
13888 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
13889 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[1], "latitude",
13890 "degrees_north", 0, 0);
13891 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[2], "longitude",
13892 "degrees_east", 0, 0);
13893 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[1], "surface area", "m**2", 0, 0);
13894 NC_DEF_VAR("depo_pb210", NC_DOUBLE, 3, dimid,
13895 "ground inventory of Pb-210", "Bq m**-2", ctl->grid_nc_level, 0);
13896 NC_DEF_VAR("depo_be7", NC_DOUBLE, 3, dimid,
13897 "ground inventory of Be-7", "Bq m**-2", ctl->grid_nc_level, 0);
13898 NC_DEF_VAR("depo_cs137", NC_DOUBLE, 3, dimid,
13899 "ground inventory of Cs-137", "Bq m**-2", ctl->grid_nc_level, 0);
13900 NC_DEF_VAR("depo_i131", NC_DOUBLE, 3, dimid,
13901 "ground inventory of aerosol-bound I-131", "Bq m**-2",
13902 ctl->grid_nc_level, 0);
13903 NC(nc_enddef(ncid));
13904
13905 /* Write coordinates... */
13906 NC_PUT_DOUBLE("time", &t, 0);
13907 NC_PUT_DOUBLE("lon", lon, 0);
13908 NC_PUT_DOUBLE("lat", lat, 0);
13909 NC_PUT_DOUBLE("area", area, 0);
13910
13911 /* Write fields in netCDF dimension order... */
13912 const char *varname[4] = {
13913 "depo_pb210", "depo_be7", "depo_cs137", "depo_i131"
13914 };
13915 for (int iq = 0; iq < 4; iq++) {
13916 for (int ix = 0; ix < ctl->grid_nx; ix++)
13917 for (int iy = 0; iy < ctl->grid_ny; iy++)
13918 help[ARRAY_2D(iy, ix, ctl->grid_nx)] =
13919 data[iq * nxy + ARRAY_2D(ix, iy, ctl->grid_ny)];
13920 NC_PUT_DOUBLE(varname[iq], help, 0);
13921 }
13922
13923 NC(nc_close(ncid));
13924 free(help);
13925}

◆ write_grid()

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

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

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

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

The function performs the following steps:

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

Definition at line 13929 of file mptrac.c.

13935 {
13936
13937 if (ctl->met_coord_type != 0)
13938 ERRMSG("Only lat/lon grid supported");
13939
13940 static double kz[EP], kw[EP];
13941
13942 static int nk;
13943
13944 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
13945
13946 int *ixs, *iys, *izs, *np;
13947
13948 /* Set timer... */
13949 SELECT_TIMER("WRITE_GRID", "OUTPUT");
13950
13951 /* Write info... */
13952 LOG(1, "Write grid data: %s", filename);
13953
13954 /* Init... */
13955 if (t == ctl->t_start) {
13956
13957 /* Read kernel data... */
13958 if (ctl->grid_kernel[0] != '-')
13959 read_kernel(ctl->grid_kernel, kz, kw, &nk);
13960 }
13961
13962 /* Allocate... */
13963 ALLOC(cd, double,
13964 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13965 for (int iq = 0; iq < ctl->nq; iq++) {
13966 ALLOC(mean[iq], double,
13967 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13968 ALLOC(sigma[iq], double,
13969 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13970 }
13971 ALLOC(vmr_impl, double,
13972 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13973 ALLOC(z, double,
13974 ctl->grid_nz);
13975 ALLOC(lon, double,
13976 ctl->grid_nx);
13977 ALLOC(lat, double,
13978 ctl->grid_ny);
13979 ALLOC(area, double,
13980 ctl->grid_ny);
13981 ALLOC(press, double,
13982 ctl->grid_nz);
13983 ALLOC(np, int,
13984 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13985 ALLOC(ixs, int,
13986 atm->np);
13987 ALLOC(iys, int,
13988 atm->np);
13989 ALLOC(izs, int,
13990 atm->np);
13991
13992 /* Set grid box size... */
13993 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
13994 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
13995 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
13996
13997 /* Set vertical coordinates... */
13998#pragma omp parallel for default(shared)
13999 for (int iz = 0; iz < ctl->grid_nz; iz++) {
14000 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
14001 press[iz] = P(z[iz]);
14002 }
14003
14004 /* Set horizontal coordinates... */
14005 for (int ix = 0; ix < ctl->grid_nx; ix++)
14006 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
14007#pragma omp parallel for default(shared)
14008 for (int iy = 0; iy < ctl->grid_ny; iy++) {
14009 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
14010 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
14011 }
14012
14013 /* Set time interval for output... */
14014 const double t0 = t - 0.5 * ctl->dt_mod;
14015 const double t1 = t + 0.5 * ctl->dt_mod;
14016
14017 /* Get grid box indices... */
14018#pragma omp parallel for default(shared)
14019 for (int ip = 0; ip < atm->np; ip++) {
14020 const double zpart = Z(atm->p[ip]);
14021 if (atm->time[ip] < t0 || atm->time[ip] > t1
14022 || atm->lon[ip] < ctl->grid_lon0
14023 || atm->lon[ip] >= ctl->grid_lon1
14024 || atm->lat[ip] < ctl->grid_lat0
14025 || atm->lat[ip] >= ctl->grid_lat1
14026 || zpart < ctl->grid_z0 || zpart >= ctl->grid_z1) {
14027 izs[ip] = -1;
14028 continue;
14029 }
14030 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
14031 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
14032 izs[ip] = (int) ((zpart - ctl->grid_z0) / dz);
14033 if (ixs[ip] >= ctl->grid_nx || iys[ip] >= ctl->grid_ny
14034 || izs[ip] >= ctl->grid_nz)
14035 izs[ip] = -1;
14036 }
14037
14038 /* Average data... */
14039 for (int ip = 0; ip < atm->np; ip++)
14040 if (izs[ip] >= 0) {
14041 const int idx =
14042 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
14043 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
14044 np[idx]++;
14045 for (int iq = 0; iq < ctl->nq; iq++) {
14046 mean[iq][idx] += kernel * atm->q[iq][ip];
14047 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
14048 }
14049 }
14050
14051 /* Calculate column density and volume mixing ratio... */
14052#pragma omp parallel for default(shared)
14053 for (int ix = 0; ix < ctl->grid_nx; ix++)
14054 for (int iy = 0; iy < ctl->grid_ny; iy++)
14055 for (int iz = 0; iz < ctl->grid_nz; iz++) {
14056
14057 /* Get grid index... */
14058 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
14059
14060 /* Calculate column density... */
14061 cd[idx] = NAN;
14062 if (ctl->qnt_m >= 0)
14063 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
14064
14065 /* Calculate volume mixing ratio (implicit)... */
14066 vmr_impl[idx] = NAN;
14067 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
14068 && met1 != NULL) {
14069 vmr_impl[idx] = 0;
14070 if (mean[ctl->qnt_m][idx] > 0) {
14071
14072 /* Get temperature... */
14073 double temp;
14075 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
14076 lon[ix], lat[iy], &temp, ci, cw, 1);
14077
14078 /* Calculate volume mixing ratio... */
14079 vmr_impl[idx] =
14080 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
14081 }
14082 }
14083
14084 /* Calculate mean... */
14085 if (np[idx] > 0)
14086 for (int iq = 0; iq < ctl->nq; iq++) {
14087 mean[iq][idx] /= np[idx];
14088 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
14089 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
14090 } else
14091 for (int iq = 0; iq < ctl->nq; iq++) {
14092 mean[iq][idx] = NAN;
14093 sigma[iq][idx] = NAN;
14094 }
14095 }
14096
14097 /* Write ASCII data... */
14098 if (ctl->grid_type == 0)
14099 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
14100 t, z, lon, lat, area, dz, np);
14101
14102 /* Write netCDF data... */
14103 else if (ctl->grid_type == 1)
14104 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
14105 t, z, lon, lat, area, dz, np);
14106
14107 /* Error message... */
14108 else
14109 ERRMSG("Grid data format GRID_TYPE unknown!");
14110
14111 /* Free... */
14112 free(cd);
14113 for (int iq = 0; iq < ctl->nq; iq++) {
14114 free(mean[iq]);
14115 free(sigma[iq]);
14116 }
14117 free(vmr_impl);
14118 free(z);
14119 free(lon);
14120 free(lat);
14121 free(area);
14122 free(press);
14123 free(np);
14124 free(ixs);
14125 free(iys);
14126 free(izs);
14127}
void write_grid_asc(const char *filename, const ctl_t *ctl, const double *cd, double *mean[NQ], double *sigma[NQ], const double *vmr_impl, const double t, const double *z, const double *lon, const double *lat, const double *area, const double dz, const int *np)
Writes grid data to an ASCII file.
Definition: mptrac.c:14131
void write_grid_nc(const char *filename, const ctl_t *ctl, const double *cd, double *mean[NQ], double *sigma[NQ], const double *vmr_impl, const double t, const double *z, const double *lon, const double *lat, const double *area, const double dz, const int *np)
Writes grid data to a NetCDF file.
Definition: mptrac.c:14235
Here is the call graph for this function:

◆ write_grid_asc()

void write_grid_asc ( const char *  filename,
const ctl_t ctl,
const double *  cd,
double *  mean[NQ],
double *  sigma[NQ],
const double *  vmr_impl,
const double  t,
const double *  z,
const double *  lon,
const double *  lat,
const double *  area,
const double  dz,
const int *  np 
)

Writes grid data to an ASCII file.

The write_grid_asc function writes gridded air parcel data, including column density, mean and standard deviation for specified quantities, and volume mixing ratio (if available), to an ASCII file. The function also supports writing gnuplot commands to generate plots if requested in the control parameters.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
cdAn array of doubles representing column density values.
meanAn array of arrays of doubles representing the mean values for specified quantities.
sigmaAn array of arrays of doubles representing the standard deviation values for specified quantities.
vmr_implAn array of doubles representing the volume mixing ratio (implicit) values.
tA double representing the current time.
zAn array of doubles representing vertical coordinates (altitude).
lonAn array of doubles representing longitudinal coordinates.
latAn array of doubles representing latitudinal coordinates.
areaAn array of doubles representing surface area values.
dzA double representing the layer depth.
npAn array of integers representing the number of particles.

The function performs the following steps:

  • Checks if gnuplot output is requested in the control parameters and sets up a gnuplot pipe if needed.
  • If gnuplot output is requested, sets the plot filename and time string, and dumps gnuplot file contents to the pipe.
  • Otherwise, creates the output file for writing in ASCII format.
  • Writes the header information to the output file, including column labels.
  • Writes the grid data to the output file, including time, altitude, coordinates, surface area, layer depth, column density, volume mixing ratio, number of particles, mean values for specified quantities, and standard deviation values if requested.
  • Closes the output file.
Note
The function supports writing gnuplot commands to generate plots if requested in the control parameters. It also supports writing mean and standard deviation values for specified quantities if requested.
Author
Lars Hoffmann

Definition at line 14131 of file mptrac.c.

14144 {
14145
14146 FILE *out;
14147
14148 /* Check if gnuplot output is requested... */
14149 if (ctl->grid_gpfile[0] != '-') {
14150
14151 /* Create gnuplot pipe... */
14152 if (!(out = popen("gnuplot", "w")))
14153 ERRMSG("Cannot create pipe to gnuplot!");
14154
14155 /* Set plot filename... */
14156 fprintf(out, "set out \"%s.png\"\n", filename);
14157
14158 /* Set time string... */
14159 double r;
14160 int year, mon, day, hour, min, sec;
14161 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
14162 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
14163 year, mon, day, hour, min);
14164
14165 /* Dump gnuplot file to pipe... */
14166 FILE *in;
14167 char line[LEN];
14168 if (!(in = fopen(ctl->grid_gpfile, "r")))
14169 ERRMSG("Cannot open file!");
14170 while (fgets(line, LEN, in))
14171 fprintf(out, "%s", line);
14172 fclose(in);
14173 }
14174
14175 else {
14176
14177 /* Create file... */
14178 if (!(out = fopen(filename, "w")))
14179 ERRMSG("Cannot create file!");
14180 }
14181
14182 /* Write header... */
14183 fprintf(out,
14184 "# $1 = time [s]\n"
14185 "# $2 = altitude [km]\n"
14186 "# $3 = longitude [deg]\n"
14187 "# $4 = latitude [deg]\n"
14188 "# $5 = surface area [km^2]\n"
14189 "# $6 = layer depth [km]\n"
14190 "# $7 = column density (implicit) [kg/m^2]\n"
14191 "# $8 = volume mixing ratio (implicit) [ppv]\n"
14192 "# $9 = number of particles [1]\n");
14193 for (int iq = 0; iq < ctl->nq; iq++)
14194 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
14195 ctl->qnt_unit[iq]);
14196 if (ctl->grid_stddev)
14197 for (int iq = 0; iq < ctl->nq; iq++)
14198 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
14199 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
14200 fprintf(out, "\n");
14201
14202 /* Write data... */
14203 for (int ix = 0; ix < ctl->grid_nx; ix++) {
14204 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
14205 fprintf(out, "\n");
14206 for (int iy = 0; iy < ctl->grid_ny; iy++) {
14207 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
14208 fprintf(out, "\n");
14209 for (int iz = 0; iz < ctl->grid_nz; iz++) {
14210 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
14211 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
14212 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
14213 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
14214 for (int iq = 0; iq < ctl->nq; iq++) {
14215 fprintf(out, " ");
14216 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
14217 }
14218 if (ctl->grid_stddev)
14219 for (int iq = 0; iq < ctl->nq; iq++) {
14220 fprintf(out, " ");
14221 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
14222 }
14223 fprintf(out, "\n");
14224 }
14225 }
14226 }
14227 }
14228
14229 /* Close file... */
14230 fclose(out);
14231}
Here is the call graph for this function:

◆ write_grid_nc()

void write_grid_nc ( const char *  filename,
const ctl_t ctl,
const double *  cd,
double *  mean[NQ],
double *  sigma[NQ],
const double *  vmr_impl,
const double  t,
const double *  z,
const double *  lon,
const double *  lat,
const double *  area,
const double  dz,
const int *  np 
)

Writes grid data to a NetCDF file.

The write_grid_nc function writes gridded air parcel data, including column density, mean and standard deviation for specified quantities, and volume mixing ratio (if available), to a NetCDF file. NetCDF is a self-describing, machine-independent data format for storing scientific data.

Parameters
filenameA string representing the name of the output file.
ctlA pointer to a ctl_t structure containing control parameters.
cdAn array of doubles representing column density values.
meanAn array of arrays of doubles representing the mean values for specified quantities.
sigmaAn array of arrays of doubles representing the standard deviation values for specified quantities.
vmr_implAn array of doubles representing the volume mixing ratio (implicit) values.
tA double representing the current time.
zAn array of doubles representing vertical coordinates (altitude).
lonAn array of doubles representing longitudinal coordinates.
latAn array of doubles representing latitudinal coordinates.
areaAn array of doubles representing surface area values.
dzA double representing the layer depth.
npAn array of integers representing the number of particles.

The function performs the following steps:

  • Allocates memory for temporary arrays required for writing data.
  • Creates a NetCDF file with the specified filename.
  • Defines dimensions and variables in the NetCDF file, along with their attributes.
  • Writes the data arrays to the NetCDF file.
  • Closes the NetCDF file.
  • Frees allocated memory.
Note
NetCDF files are commonly used in scientific computing and can be accessed by various programming languages and software packages. Additionally, the function supports writing mean and standard deviation values for specified quantities if requested.
Author
Lars Hoffmann

Definition at line 14235 of file mptrac.c.

14248 {
14249
14250 char longname[2 * LEN], varname[2 * LEN];
14251
14252 double *help;
14253
14254 int *help2, ncid, dimid[10], varid;
14255
14256 size_t start[2], count[2];
14257
14258 /* Allocate... */
14259 ALLOC(help, double,
14260 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
14261 ALLOC(help2, int,
14262 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
14263
14264 /* Create file... */
14265 NC(nc_create(filename, NC_NETCDF4, &ncid));
14266
14267 /* Define dimensions... */
14268 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
14269 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
14270 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
14271 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
14272 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
14273
14274 /* Define variables and their attributes... */
14275 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
14276 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
14277 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
14278 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
14279 0);
14280 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
14281 0);
14282 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
14283 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
14284
14285 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
14286 ctl->grid_nc_level, 0);
14287 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
14288 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
14289 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
14290 for (int iq = 0; iq < ctl->nq; iq++) {
14291 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
14292 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
14293 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
14294 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
14295 if (ctl->grid_stddev) {
14296 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
14297 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
14298 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
14299 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
14300 }
14301 }
14302 /* End definitions... */
14303 NC(nc_enddef(ncid));
14304
14305 /* Write data... */
14306 NC_PUT_DOUBLE("time", &t, 0);
14307 NC_PUT_DOUBLE("lon", lon, 0);
14308 NC_PUT_DOUBLE("lat", lat, 0);
14309 NC_PUT_DOUBLE("z", z, 0);
14310 NC_PUT_DOUBLE("area", area, 0);
14311 NC_PUT_DOUBLE("dz", &dz, 0);
14312
14313 for (int ix = 0; ix < ctl->grid_nx; ix++)
14314 for (int iy = 0; iy < ctl->grid_ny; iy++)
14315 for (int iz = 0; iz < ctl->grid_nz; iz++)
14316 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14317 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14318 NC_PUT_DOUBLE("cd", help, 0);
14319
14320 for (int ix = 0; ix < ctl->grid_nx; ix++)
14321 for (int iy = 0; iy < ctl->grid_ny; iy++)
14322 for (int iz = 0; iz < ctl->grid_nz; iz++)
14323 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14324 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14325 NC_PUT_DOUBLE("vmr_impl", help, 0);
14326
14327 for (int ix = 0; ix < ctl->grid_nx; ix++)
14328 for (int iy = 0; iy < ctl->grid_ny; iy++)
14329 for (int iz = 0; iz < ctl->grid_nz; iz++)
14330 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14331 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14332 NC_PUT_INT("np", help2, 0);
14333
14334 for (int iq = 0; iq < ctl->nq; iq++) {
14335 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
14336 for (int ix = 0; ix < ctl->grid_nx; ix++)
14337 for (int iy = 0; iy < ctl->grid_ny; iy++)
14338 for (int iz = 0; iz < ctl->grid_nz; iz++)
14339 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14340 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14341 NC_PUT_DOUBLE(varname, help, 0);
14342 }
14343
14344 if (ctl->grid_stddev)
14345 for (int iq = 0; iq < ctl->nq; iq++) {
14346 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
14347 for (int ix = 0; ix < ctl->grid_nx; ix++)
14348 for (int iy = 0; iy < ctl->grid_ny; iy++)
14349 for (int iz = 0; iz < ctl->grid_nz; iz++)
14350 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14351 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14352 NC_PUT_DOUBLE(varname, help, 0);
14353 }
14354
14355 /* Close file... */
14356 NC(nc_close(ncid));
14357
14358 /* Free... */
14359 free(help);
14360 free(help2);
14361}
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1678

◆ write_met_bin()

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

Writes meteorological data in binary format to a specified file.

This function writes meteorological data from the met_t structure to a binary file. The data includes grid and surface data, as well as multi-level data such as temperature, velocity components, and atmospheric properties. The compression options for multi-level data (ZFP) are controlled via the ctl_t structure. The function supports multiple variables, such as surface pressure, temperature, wind components, and cloud properties.

Parameters
filenameA constant character pointer representing the name of the file to write the binary data to.
ctlA pointer to a ctl_t structure, which holds control parameters including the type of meteorological data, compression settings, and grid dimensions.
metA pointer to a met_t structure that contains the meteorological data to be written to the binary file.
Note
  • The function creates a new file to write the data. If the file cannot be created, an error is generated.
  • The type of meteorological data (ctl->met_type) and the version of the binary format are written at the beginning of the file.
  • Grid data such as longitude, latitude, pressure levels, and time are written to the file.
  • Surface data (e.g., pressure, temperature, wind components) are written using the write_met_bin_2d helper function.
  • Multi-level (3D) data such as geopotential height, temperature, and wind velocity are written using the write_met_bin_3d function with optional ZFP compression settings.
Author
Lars Hoffmann

Definition at line 14365 of file mptrac.c.

14368 {
14369
14370 /* Create file... */
14371 FILE *out, *level_log = NULL;
14372 if (!(out = fopen(filename, "w")))
14373 ERRMSG("Cannot create file!");
14374
14375 /* Create diagnostics file... */
14376 if (strcmp(ctl->met_comp_logfile, "-") != 0) {
14377
14378 if (!(level_log = fopen(ctl->met_comp_logfile, "w")))
14379 ERRMSG("Cannot create compression log file!");
14380 LOG(1, "Write compression diagnostics: %s", ctl->met_comp_logfile);
14381
14382 /* Write header... */
14383 fprintf(level_log,
14384 "# $1 = compression codec name [-]\n"
14385 "# $2 = variable name [-]\n"
14386 "# $3 = level index [-]\n"
14387 "# $4 = pressure level [hPa]\n"
14388 "# $5 = compression ratio [-]\n"
14389 "# $6 = bits per value [bit/value]\n"
14390 "# $7 = correlation coefficient [-]\n"
14391 "# $8 = mean compression error [-]\n"
14392 "# $9 = standard deviation of compression error [-]\n"
14393 "# $10 = minimum compression error [-]\n"
14394 "# $11 = maximum compression error [-]\n"
14395 "# $12 = mean value of original field [-]\n"
14396 "# $13 = value range of original field [-]\n"
14397 "# $14 = normalized root mean square error [-]\n"
14398 "# $15 = compression time [s]\n"
14399 "# $16 = compression speed [MiB/s]\n"
14400 "# $17 = decompression time [s]\n"
14401 "# $18 = decompression speed [MiB/s]\n\n");
14402 }
14403
14404 /* Write type of binary data... */
14405 FWRITE(&ctl->met_type, int,
14406 1,
14407 out);
14408
14409 /* Write version of binary data... */
14410 int version = 104;
14411 FWRITE(&version, int,
14412 1,
14413 out);
14414
14415 /* Write grid data... */
14416 FWRITE(&met->time, double,
14417 1,
14418 out);
14419 FWRITE(&met->nx, int,
14420 1,
14421 out);
14422 FWRITE(&met->ny, int,
14423 1,
14424 out);
14425 FWRITE(&met->np, int,
14426 1,
14427 out);
14428 FWRITE(met->lon, double,
14429 (size_t) met->nx,
14430 out);
14431 FWRITE(met->lat, double,
14432 (size_t) met->ny,
14433 out);
14434 FWRITE(met->p, double,
14435 (size_t) met->np,
14436 out);
14437
14438 /* Write surface data... */
14439 write_met_bin_2d(out, met, met->ps, "PS");
14440 write_met_bin_2d(out, met, met->ts, "TS");
14441 write_met_bin_2d(out, met, met->zs, "ZS");
14442 write_met_bin_2d(out, met, met->us, "US");
14443 write_met_bin_2d(out, met, met->vs, "VS");
14444 write_met_bin_2d(out, met, met->ess, "ESS");
14445 write_met_bin_2d(out, met, met->nss, "NSS");
14446 write_met_bin_2d(out, met, met->shf, "SHF");
14447 write_met_bin_2d(out, met, met->lsm, "LSM");
14448 write_met_bin_2d(out, met, met->sst, "SST");
14449 write_met_bin_2d(out, met, met->pbl, "PBL");
14450 write_met_bin_2d(out, met, met->pt, "PT");
14451 write_met_bin_2d(out, met, met->tt, "TT");
14452 write_met_bin_2d(out, met, met->zt, "ZT");
14453 write_met_bin_2d(out, met, met->h2ot, "H2OT");
14454 write_met_bin_2d(out, met, met->pct, "PCT");
14455 write_met_bin_2d(out, met, met->pcb, "PCB");
14456 write_met_bin_2d(out, met, met->cl, "CL");
14457 write_met_bin_2d(out, met, met->plcl, "PLCL");
14458 write_met_bin_2d(out, met, met->plfc, "PLFC");
14459 write_met_bin_2d(out, met, met->pel, "PEL");
14460 write_met_bin_2d(out, met, met->cape, "CAPE");
14461 write_met_bin_2d(out, met, met->cin, "CIN");
14462 write_met_bin_2d(out, met, met->o3c, "O3C");
14463
14464 /* Write level data... */
14465 write_met_bin_3d(out, ctl, met, met->z, "Z", 0, level_log);
14466 write_met_bin_3d(out, ctl, met, met->t, "T", 1, level_log);
14467 write_met_bin_3d(out, ctl, met, met->u, "U", 2, level_log);
14468 write_met_bin_3d(out, ctl, met, met->v, "V", 3, level_log);
14469 write_met_bin_3d(out, ctl, met, met->w, "W", 4, level_log);
14470 write_met_bin_3d(out, ctl, met, met->pv, "PV", 5, level_log);
14471 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", 6, level_log);
14472 write_met_bin_3d(out, ctl, met, met->o3, "O3", 7, level_log);
14473 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", 8, level_log);
14474 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", 9, level_log);
14475 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", 10, level_log);
14476 write_met_bin_3d(out, ctl, met, met->swc, "SWC", 11, level_log);
14477 write_met_bin_3d(out, ctl, met, met->cc, "CC", 12, level_log);
14478 if (METVAR != 13)
14479 ERRMSG("Number of meteo variables doesn't match!");
14480
14481 /* Write final flag... */
14482 int final = 999;
14483 FWRITE(&final, int,
14484 1,
14485 out);
14486
14487 /* Close file... */
14488 if (level_log)
14489 fclose(level_log);
14490 fclose(out);
14491}
void write_met_bin_3d(FILE *out, const ctl_t *ctl, met_t *met, float var[EX][EY][EP], const char *varname, const int metvar, FILE *level_log)
Writes a 3-dimensional meteorological variable to a binary file.
Definition: mptrac.c:14524
void write_met_bin_2d(FILE *out, met_t *met, float var[EX][EY], const char *varname)
Writes a 2-dimensional meteorological variable to a binary file.
Definition: mptrac.c:14495
Here is the call graph for this function:

◆ write_met_bin_2d()

void write_met_bin_2d ( FILE *  out,
met_t met,
float  var[EX][EY],
const char *  varname 
)

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

The write_met_bin_2d function writes a 2-dimensional meteorological variable to a binary file specified by the out parameter. The variable data is provided in a 2-dimensional array var with maximum dimensions EX by EY. The variable name is provided as a string in the varname parameter.

Parameters
outA pointer to a FILE structure representing the output file.
metA pointer to a met_t structure containing meteorological data.
varAn array of floats representing the 2-dimensional variable data.
varnameA string containing the name of the variable being written.

The function performs the following steps:

  • Allocates memory for a temporary buffer to hold the variable data.
  • Copies the variable data from the 2-dimensional array var to the temporary buffer help.
  • Writes the uncompressed variable data to the binary file specified by out.
  • Logs a message indicating the successful writing of the variable data.
  • Frees the allocated memory.
Note
This function is typically used to write surface data or other 2-dimensional meteorological variables to a binary file.
Author
Lars Hoffmann

Definition at line 14495 of file mptrac.c.

14499 {
14500
14501 float *help;
14502
14503 /* Allocate... */
14504 ALLOC(help, float,
14505 EX * EY);
14506
14507 /* Copy data... */
14508 for (int ix = 0; ix < met->nx; ix++)
14509 for (int iy = 0; iy < met->ny; iy++)
14510 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
14511
14512 /* Write uncompressed data... */
14513 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
14514 FWRITE(help, float,
14515 (size_t) (met->nx * met->ny),
14516 out);
14517
14518 /* Free... */
14519 free(help);
14520}

◆ write_met_bin_3d()

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

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

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

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

The function performs the following steps:

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

Definition at line 14524 of file mptrac.c.

14531 {
14532
14533 float *help;
14534
14535 /* Allocate... */
14536 ALLOC(help, float,
14537 EX * EY * EP);
14538
14539 /* Copy data... */
14540#pragma omp parallel for default(shared) collapse(2)
14541 for (int ix = 0; ix < met->nx; ix++)
14542 for (int iy = 0; iy < met->ny; iy++)
14543 for (int ip = 0; ip < met->np; ip++)
14544 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
14545
14546 /* Write uncompressed data... */
14547 if (ctl->met_type == 1) {
14548 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
14549 FWRITE(help, float,
14550 (size_t) (met->nx * met->ny * met->np),
14551 out);
14552 }
14553
14554 /* Write packed data... */
14555 else if (ctl->met_type == 2)
14556 compress_pck(ctl, met, varname, help, 0, level_log, out);
14557
14558 /* Write ZFP data... */
14559#ifdef ZFP
14560 else if (ctl->met_type == 3) {
14561 FWRITE(&ctl->met_zfp_prec[metvar], int,
14562 1,
14563 out);
14564 FWRITE(&ctl->met_zfp_tol[metvar], double,
14565 1,
14566 out);
14567 compress_zfp(ctl, met, varname, help, 0, level_log, out);
14568 }
14569#endif
14570
14571 /* Write zstd data... */
14572#ifdef ZSTD
14573 else if (ctl->met_type == 4)
14574 compress_zstd(ctl, met, varname, help, 0, level_log, out);
14575#endif
14576
14577 /* Write LZ4 data... */
14578#ifdef LZ4
14579 else if (ctl->met_type == 8)
14580 compress_lz4(ctl, met, varname, help, 0, level_log, out);
14581#endif
14582
14583 /* Write cmultiscale data... */
14584#ifdef CMS
14585 else if (ctl->met_type == 5) {
14586 compress_cms(ctl, met, varname, help, 0, level_log, out);
14587 }
14588#endif
14589
14590 /* Write SZ3 data... */
14591#ifdef SZ3
14592 else if (ctl->met_type == 7) {
14593 FWRITE(&ctl->met_sz3_prec[metvar], int,
14594 1,
14595 out);
14596 FWRITE(&ctl->met_sz3_tol[metvar], double,
14597 1,
14598 out);
14599 compress_sz3(ctl, met, varname, help, 0, level_log, out);
14600 }
14601#endif
14602
14603 /* Unknown method... */
14604 else {
14605 ERRMSG("MET_TYPE not supported!");
14606
14607 /* This will never execute, hack to avoid compilation error... */
14608 LOG(3, "%d", metvar);
14609 }
14610
14611 /* Free... */
14612 free(help);
14613}
Here is the call graph for this function:

◆ write_met_nc()

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

Writes meteorological data to a NetCDF file.

This function creates and writes meteorological data to a NetCDF file in the NetCDF-4 format. It defines the required dimensions, grid, surface variables, and level data within the NetCDF structure and writes the corresponding values from the met_t structure. The function uses helper functions to write 2D surface and 3D level data.

Parameters
filenameA constant character pointer representing the name of the NetCDF file to create and write the data to.
ctlA pointer to a ctl_t structure that contains control parameters, such as the NetCDF level and quantization settings.
metA pointer to a met_t structure that contains the meteorological data to be written to the NetCDF file.
Note
  • The function uses the NetCDF-4 format for efficient data storage.
  • It defines the grid dimensions (time, longitude, latitude, pressure levels) and adds global attributes like units and descriptions for each variable.
  • The surface variables include surface pressure, geopotential, 2-meter temperature, and wind components, which are defined on a 2D grid (latitude × longitude).
  • The level variables, such as temperature, wind velocities, and cloud properties, are defined on a 3D grid (pressure level × latitude × longitude).
Author
Lars Hoffmann

Definition at line 14617 of file mptrac.c.

14620 {
14621
14622 /* Create file... */
14623 int ncid, varid;
14624 size_t start[4], count[4];
14625 NC(nc_create(filename, NC_NETCDF4, &ncid));
14626
14627 /* Define dimensions... */
14628 int tid, lonid, latid, levid;
14629 NC(nc_def_dim(ncid, "time", 1, &tid));
14630
14631 if (met->coord_type == 0) {
14632 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
14633 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
14634 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0,
14635 0);
14636 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0,
14637 0);
14638 } else {
14639 NC(nc_def_dim(ncid, "x", (size_t) met->nx, &lonid));
14640 NC(nc_def_dim(ncid, "y", (size_t) met->ny, &latid));
14641 NC_DEF_VAR("x", NC_DOUBLE, 1, &lonid, "x", "easting", 0, 0);
14642 NC_DEF_VAR("y", NC_DOUBLE, 1, &latid, "y", "northing", 0, 0);
14643 }
14644
14645 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
14646
14647 /* Define grid... */
14648 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
14649 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
14650 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
14651
14652 /* Define surface variables... */
14653 int dimid2[3] = { tid, latid, lonid };
14654 NC_DEF_VAR("sp", NC_FLOAT, 3, dimid2, "Surface pressure", "Pa",
14655 ctl->met_nc_level, 0);
14656 NC_DEF_VAR("z", NC_FLOAT, 3, dimid2, "Geopotential", "m**2 s**-2",
14657 ctl->met_nc_level, 0);
14658 NC_DEF_VAR("t2m", NC_FLOAT, 3, dimid2, "2 metre temperature", "K",
14659 ctl->met_nc_level, 0);
14660 NC_DEF_VAR("u10m", NC_FLOAT, 3, dimid2, "10 metre U wind component",
14661 "m s**-1", ctl->met_nc_level, 0);
14662 NC_DEF_VAR("v10m", NC_FLOAT, 3, dimid2, "10 metre V wind component",
14663 "m s**-1", ctl->met_nc_level, 0);
14664 NC_DEF_VAR("iews", NC_FLOAT, 3, dimid2,
14665 "Instantaneous eastward turbulent surface stress", "N m**-2",
14666 ctl->met_nc_level, 0);
14667 NC_DEF_VAR("inss", NC_FLOAT, 3, dimid2,
14668 "Instantaneous northward turbulent surface stress", "N m**-2",
14669 ctl->met_nc_level, 0);
14670 NC_DEF_VAR("ishf", NC_FLOAT, 3, dimid2,
14671 "Instantaneous surface sensible heat flux", "W m**-2",
14672 ctl->met_nc_level, 0);
14673 NC_DEF_VAR("lsm", NC_FLOAT, 3, dimid2, "Land/sea mask", "-",
14674 ctl->met_nc_level, 0);
14675 NC_DEF_VAR("sstk", NC_FLOAT, 3, dimid2, "Sea surface temperature", "K",
14676 ctl->met_nc_level, 0);
14677 NC_DEF_VAR("blp", NC_FLOAT, 3, dimid2, "Boundary layer pressure", "Pa",
14678 ctl->met_nc_level, 0);
14679 NC_DEF_VAR("pt", NC_FLOAT, 3, dimid2, "Tropopause pressure", "Pa",
14680 ctl->met_nc_level, 0);
14681 NC_DEF_VAR("tt", NC_FLOAT, 3, dimid2, "Tropopause temperature", "K",
14682 ctl->met_nc_level, 0);
14683 NC_DEF_VAR("zt", NC_FLOAT, 3, dimid2, "Tropopause height", "m",
14684 ctl->met_nc_level, 0);
14685 NC_DEF_VAR("h2ot", NC_FLOAT, 3, dimid2, "Tropopause water vapor", "ppv",
14686 ctl->met_nc_level, 0);
14687 NC_DEF_VAR("pct", NC_FLOAT, 3, dimid2, "Cloud top pressure", "Pa",
14688 ctl->met_nc_level, 0);
14689 NC_DEF_VAR("pcb", NC_FLOAT, 3, dimid2, "Cloud bottom pressure", "Pa",
14690 ctl->met_nc_level, 0);
14691 NC_DEF_VAR("cl", NC_FLOAT, 3, dimid2, "Total column cloud water",
14692 "kg m**2", ctl->met_nc_level, 0);
14693 NC_DEF_VAR("plcl", NC_FLOAT, 3, dimid2,
14694 "Pressure at lifted condensation level (LCL)", "Pa",
14695 ctl->met_nc_level, 0);
14696 NC_DEF_VAR("plfc", NC_FLOAT, 3, dimid2,
14697 "Pressure at level of free convection (LFC)", "Pa",
14698 ctl->met_nc_level, 0);
14699 NC_DEF_VAR("pel", NC_FLOAT, 3, dimid2,
14700 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
14701 0);
14702 NC_DEF_VAR("cape", NC_FLOAT, 3, dimid2,
14703 "Convective available potential energy", "J kg**-1",
14704 ctl->met_nc_level, 0);
14705 NC_DEF_VAR("cin", NC_FLOAT, 3, dimid2, "Convective inhibition",
14706 "J kg**-1", ctl->met_nc_level, 0);
14707 NC_DEF_VAR("o3c", NC_FLOAT, 3, dimid2, "Total column ozone", "DU",
14708 ctl->met_nc_level, 0);
14709
14710 /* Define level data... */
14711 int dimid3[4] = { tid, levid, latid, lonid };
14712 NC_DEF_VAR("t", NC_FLOAT, 4, dimid3, "Temperature", "K",
14713 ctl->met_nc_level, ctl->met_nc_quant);
14714 NC_DEF_VAR("u", NC_FLOAT, 4, dimid3, "U velocity", "m s**-1",
14715 ctl->met_nc_level, ctl->met_nc_quant);
14716 NC_DEF_VAR("v", NC_FLOAT, 4, dimid3, "V velocity", "m s**-1",
14717 ctl->met_nc_level, ctl->met_nc_quant);
14718 NC_DEF_VAR("w", NC_FLOAT, 4, dimid3, "Vertical velocity", "Pa s**-1",
14719 ctl->met_nc_level, ctl->met_nc_quant);
14720 NC_DEF_VAR("q", NC_FLOAT, 4, dimid3, "Specific humidity", "kg kg**-1",
14721 ctl->met_nc_level, ctl->met_nc_quant);
14722 NC_DEF_VAR("o3", NC_FLOAT, 4, dimid3, "Ozone mass mixing ratio",
14723 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14724 NC_DEF_VAR("clwc", NC_FLOAT, 4, dimid3, "Cloud liquid water content",
14725 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14726 NC_DEF_VAR("crwc", NC_FLOAT, 4, dimid3, "Cloud rain water content",
14727 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14728 NC_DEF_VAR("ciwc", NC_FLOAT, 4, dimid3, "Cloud ice water content",
14729 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14730 NC_DEF_VAR("cswc", NC_FLOAT, 4, dimid3, "Cloud snow water content",
14731 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14732 NC_DEF_VAR("cc", NC_FLOAT, 4, dimid3, "Cloud cover", "-",
14733 ctl->met_nc_level, ctl->met_nc_quant);
14734
14735 /* End definitions... */
14736 NC(nc_enddef(ncid));
14737
14738 /* Write grid data... */
14739 NC_PUT_DOUBLE("time", &met->time, 0);
14740
14741 if (met->coord_type == 0) {
14742 NC_PUT_DOUBLE("lon", met->lon, 0);
14743 NC_PUT_DOUBLE("lat", met->lat, 0);
14744 } else {
14745 NC_PUT_DOUBLE("x", met->lon, 0);
14746 NC_PUT_DOUBLE("y", met->lat, 0);
14747 }
14748
14749 double phelp[EP];
14750 for (int ip = 0; ip < met->np; ip++)
14751 phelp[ip] = 100. * met->p[ip];
14752 NC_PUT_DOUBLE("lev", phelp, 0);
14753
14754 /* Write surface data... */
14755 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
14756 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
14757 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
14758 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
14759 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
14760 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
14761 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
14762 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
14763 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
14764 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
14765 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
14766 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
14767 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
14768 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
14769 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
14770 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
14771 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
14772 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
14773 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
14774 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
14775 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
14776 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
14777 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
14778 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
14779
14780 /* Write level data... */
14781 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
14782 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
14783 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
14784 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
14785 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
14786 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
14787 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
14788 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
14789 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
14790 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
14791 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
14792
14793 /* Close file... */
14794 NC(nc_close(ncid));
14795}
void write_met_nc_2d(const int ncid, const char *varname, met_t *met, float var[EX][EY], const float scl)
Writes a 2D meteorological variable to a NetCDF file.
Definition: mptrac.c:14799
void write_met_nc_3d(const int ncid, const char *varname, met_t *met, float var[EX][EY][EP], const float scl)
Writes a 3D meteorological variable to a NetCDF file.
Definition: mptrac.c:14829
Here is the call graph for this function:

◆ write_met_nc_2d()

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

Writes a 2D meteorological variable to a NetCDF file.

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

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

Definition at line 14799 of file mptrac.c.

14804 {
14805
14806 int varid;
14807 size_t start[4], count[4];
14808
14809 /* Allocate... */
14810 float *help;
14811 ALLOC(help, float,
14812 EX * EY);
14813
14814 /* Copy data... */
14815 for (int ix = 0; ix < met->nx; ix++)
14816 for (int iy = 0; iy < met->ny; iy++)
14817 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
14818
14819 /* Write data... */
14820 LOG(2, "Write 2-D variable: %s (netCDF)", varname);
14821 NC_PUT_FLOAT(varname, help, 0);
14822
14823 /* Free... */
14824 free(help);
14825}
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1655

◆ write_met_nc_3d()

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

Writes a 3D meteorological variable to a NetCDF file.

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

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

Definition at line 14829 of file mptrac.c.

14834 {
14835
14836 int varid;
14837 size_t start[4], count[4];
14838
14839 /* Allocate... */
14840 float *help;
14841 ALLOC(help, float,
14842 EX * EY * EP);
14843
14844 /* Copy data... */
14845 for (int ix = 0; ix < met->nx; ix++)
14846 for (int iy = 0; iy < met->ny; iy++)
14847 for (int ip = 0; ip < met->np; ip++)
14848 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
14849
14850 /* Write data... */
14851 LOG(2, "Write 3-D variable: %s (netCDF)", varname);
14852 NC_PUT_FLOAT(varname, help, 0);
14853
14854 /* Free... */
14855 free(help);
14856}

◆ write_prof()

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

Writes profile data to a specified file.

The write_prof function writes profile data to a file specified by the filename parameter. It takes control parameters (ctl), two meteorological data structures (met0 and met1), an atmospheric data structure (atm), and a time value (t) as input.

Parameters
filenameA string representing the filename where the profile data will be written.
ctlA pointer to a ctl_t structure containing control parameters.
met0A pointer to a met_t structure representing the first set of meteorological data.
met1A pointer to a met_t structure representing the second set of meteorological data.
atmA pointer to an atm_t structure representing atmospheric data.
tA double value representing the time at which the profile data is being written.

The function performs the following steps:

  • Initializes variables and allocates memory if it's the start of the simulation.
  • Reads observation data and creates a new output file if necessary.
  • Writes header information to the output file.
  • Sets grid box size and vertical coordinates.
  • Processes observations and model data within the specified time interval.
  • Calculates and writes output data for each grid cell.
  • Finalizes by closing the output file and freeing allocated memory if it's the end of the simulation.
Note
This function writes profile data to a file, including time, altitude, coordinates, atmospheric properties, observed data, and the number of observations.
Author
Lars Hoffmann

Definition at line 14860 of file mptrac.c.

14866 {
14867
14868 if (ctl->met_coord_type != 0)
14869 ERRMSG("Only lat/lon grid supported");
14870
14871 static FILE *out;
14872
14873 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
14874 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
14875
14876 static int nobs, *obscount, ip, okay;
14877
14878 /* Set timer... */
14879 SELECT_TIMER("WRITE_PROF", "OUTPUT");
14880
14881 /* Init... */
14882 if (t == ctl->t_start) {
14883
14884 /* Check quantity index for mass... */
14885 if (ctl->qnt_m < 0)
14886 ERRMSG("Need quantity mass!");
14887
14888 /* Check molar mass... */
14889 if (ctl->molmass <= 0)
14890 ERRMSG("Specify molar mass!");
14891
14892 /* Allocate... */
14893 ALLOC(lon, double,
14894 ctl->prof_nx);
14895 ALLOC(lat, double,
14896 ctl->prof_ny);
14897 ALLOC(area, double,
14898 ctl->prof_ny);
14899 ALLOC(z, double,
14900 ctl->prof_nz);
14901 ALLOC(press, double,
14902 ctl->prof_nz);
14903 ALLOC(rt, double,
14904 NOBS);
14905 ALLOC(rz, double,
14906 NOBS);
14907 ALLOC(rlon, double,
14908 NOBS);
14909 ALLOC(rlat, double,
14910 NOBS);
14911 ALLOC(robs, double,
14912 NOBS);
14913
14914 /* Read observation data... */
14915 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
14916
14917 /* Create new output file... */
14918 LOG(1, "Write profile data: %s", filename);
14919 if (!(out = fopen(filename, "w")))
14920 ERRMSG("Cannot create file!");
14921
14922 /* Write header... */
14923 fprintf(out,
14924 "# $1 = time [s]\n"
14925 "# $2 = altitude [km]\n"
14926 "# $3 = longitude [deg]\n"
14927 "# $4 = latitude [deg]\n"
14928 "# $5 = pressure [hPa]\n"
14929 "# $6 = temperature [K]\n"
14930 "# $7 = volume mixing ratio [ppv]\n"
14931 "# $8 = H2O volume mixing ratio [ppv]\n"
14932 "# $9 = O3 volume mixing ratio [ppv]\n"
14933 "# $10 = observed BT index [K]\n"
14934 "# $11 = number of observations\n");
14935
14936 /* Set grid box size... */
14937 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
14938 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
14939 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
14940
14941 /* Set vertical coordinates... */
14942 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14943 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
14944 press[iz] = P(z[iz]);
14945 }
14946
14947 /* Set horizontal coordinates... */
14948 for (int ix = 0; ix < ctl->prof_nx; ix++)
14949 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
14950 for (int iy = 0; iy < ctl->prof_ny; iy++) {
14951 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
14952 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
14953 }
14954 }
14955
14956 /* Set time interval... */
14957 const double t0 = t - 0.5 * ctl->dt_mod;
14958 const double t1 = t + 0.5 * ctl->dt_mod;
14959
14960 /* Allocate... */
14961 ALLOC(mass, double,
14962 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
14963 ALLOC(obsmean, double,
14964 ctl->prof_nx * ctl->prof_ny);
14965 ALLOC(obscount, int,
14966 ctl->prof_nx * ctl->prof_ny);
14967
14968 /* Loop over observations... */
14969 for (int i = 0; i < nobs; i++) {
14970
14971 /* Check time... */
14972 if (rt[i] < t0)
14973 continue;
14974 else if (rt[i] >= t1)
14975 break;
14976
14977 /* Check observation data... */
14978 if (!isfinite(robs[i]))
14979 continue;
14980
14981 /* Check grid boundaries and calculate indices... */
14982 if (rlon[i] < ctl->prof_lon0 || rlon[i] >= ctl->prof_lon1
14983 || rlat[i] < ctl->prof_lat0 || rlat[i] >= ctl->prof_lat1)
14984 continue;
14985 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
14986 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
14987 if (ix >= ctl->prof_nx || iy >= ctl->prof_ny)
14988 continue;
14989
14990 /* Get mean observation index... */
14991 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
14992 obsmean[idx] += robs[i];
14993 obscount[idx]++;
14994 }
14995
14996 /* Analyze model data... */
14997 for (ip = 0; ip < atm->np; ip++) {
14998
14999 /* Check time... */
15000 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15001 continue;
15002
15003 /* Check grid boundaries and get indices... */
15004 const double zpart = Z(atm->p[ip]);
15005 if (atm->lon[ip] < ctl->prof_lon0
15006 || atm->lon[ip] >= ctl->prof_lon1
15007 || atm->lat[ip] < ctl->prof_lat0
15008 || atm->lat[ip] >= ctl->prof_lat1
15009 || zpart < ctl->prof_z0 || zpart >= ctl->prof_z1)
15010 continue;
15011 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
15012 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
15013 const int iz = (int) ((zpart - ctl->prof_z0) / dz);
15014 if (ix >= ctl->prof_nx || iy >= ctl->prof_ny || iz >= ctl->prof_nz)
15015 continue;
15016
15017 /* Get total mass in grid cell... */
15018 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
15019 mass[idx] += atm->q[ctl->qnt_m][ip];
15020 }
15021
15022 /* Extract profiles... */
15023 for (int ix = 0; ix < ctl->prof_nx; ix++)
15024 for (int iy = 0; iy < ctl->prof_ny; iy++) {
15025 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
15026 if (obscount[idx2] > 0) {
15027
15028 /* Check profile... */
15029 okay = 0;
15030 for (int iz = 0; iz < ctl->prof_nz; iz++) {
15031 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
15032 if (mass[idx3] > 0) {
15033 okay = 1;
15034 break;
15035 }
15036 }
15037 if (!okay)
15038 continue;
15039
15040 /* Write output... */
15041 fprintf(out, "\n");
15042
15043 /* Loop over altitudes... */
15044 for (int iz = 0; iz < ctl->prof_nz; iz++) {
15045
15046 /* Get temperature, water vapor, and ozone... */
15048 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
15049 lon[ix], lat[iy], &temp, ci, cw, 1);
15050 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
15051 lon[ix], lat[iy], &h2o, ci, cw, 0);
15052 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
15053 lon[ix], lat[iy], &o3, ci, cw, 0);
15054
15055 /* Calculate volume mixing ratio... */
15056 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
15057 vmr = MA / ctl->molmass * mass[idx3]
15058 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
15059
15060 /* Write output... */
15061 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
15062 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
15063 obsmean[idx2] / obscount[idx2], obscount[idx2]);
15064 }
15065 }
15066 }
15067
15068 /* Free... */
15069 free(mass);
15070 free(obsmean);
15071 free(obscount);
15072
15073 /* Finalize... */
15074 if (t == ctl->t_stop) {
15075
15076 /* Close output file... */
15077 fclose(out);
15078
15079 /* Free... */
15080 free(lon);
15081 free(lat);
15082 free(area);
15083 free(z);
15084 free(press);
15085 free(rt);
15086 free(rz);
15087 free(rlon);
15088 free(rlat);
15089 free(robs);
15090 }
15091}
Here is the call graph for this function:

◆ write_sample()

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

Writes sample data to a specified file.

The write_sample function writes sample data to a file specified by the filename parameter. It takes control parameters (ctl), two meteorological data structures (met0 and met1), an atmospheric data structure (atm), and a time value (t) as input.

Parameters
filenameA string representing the filename where the sample data will be written.
ctlA pointer to a ctl_t structure containing control parameters.
met0A pointer to a met_t structure representing the first set of meteorological data.
met1A pointer to a met_t structure representing the second set of meteorological data.
atmA pointer to an atm_t structure representing atmospheric data.
tA double value representing the time at which the sample data is being written.

The function performs the following steps:

  • Initializes variables and allocates memory if it's the start of the simulation.
  • Reads observation data and kernel data if necessary.
  • Creates a new output file and writes header information to it.
  • Sets latitude range, squared radius, and area.
  • Processes observations and calculates sample data within the specified time interval.
  • Writes output data for each observation.
  • Finalizes by closing the output file and freeing allocated memory if it's the end of the simulation.
Note
This function writes sample data to a file, including time, altitude, coordinates, surface area, layer depth, number of particles, column density, volume mixing ratio, and observed data.
Author
Lars Hoffmann

Definition at line 15095 of file mptrac.c.

15101 {
15102
15103 if (ctl->met_coord_type != 0)
15104 ERRMSG("Only lat/lon grid supported");
15105
15106 static FILE *out;
15107
15108 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
15109 kw[EP];
15110
15111 static int nobs, nk;
15112
15113 /* Set timer... */
15114 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT");
15115
15116 /* Init... */
15117 if (t == ctl->t_start) {
15118
15119 /* Allocate... */
15120 ALLOC(rt, double,
15121 NOBS);
15122 ALLOC(rz, double,
15123 NOBS);
15124 ALLOC(rlon, double,
15125 NOBS);
15126 ALLOC(rlat, double,
15127 NOBS);
15128 ALLOC(robs, double,
15129 NOBS);
15130
15131 /* Read observation data... */
15132 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
15133
15134 /* Read kernel data... */
15135 if (ctl->sample_kernel[0] != '-')
15136 read_kernel(ctl->sample_kernel, kz, kw, &nk);
15137
15138 /* Create output file... */
15139 LOG(1, "Write sample data: %s", filename);
15140 if (!(out = fopen(filename, "w")))
15141 ERRMSG("Cannot create file!");
15142
15143 /* Write header... */
15144 fprintf(out,
15145 "# $1 = time [s]\n"
15146 "# $2 = altitude [km]\n"
15147 "# $3 = longitude [deg]\n"
15148 "# $4 = latitude [deg]\n"
15149 "# $5 = surface area [km^2]\n"
15150 "# $6 = layer depth [km]\n"
15151 "# $7 = number of particles [1]\n"
15152 "# $8 = column density [kg/m^2]\n"
15153 "# $9 = volume mixing ratio [ppv]\n"
15154 "# $10 = observed BT index [K]\n\n");
15155
15156 /* Set latitude range, squared radius, and area... */
15157 dlat = DY2DEG(ctl->sample_dx);
15158 rmax2 = SQR(ctl->sample_dx);
15159 area = M_PI * rmax2;
15160 }
15161
15162 /* Set time interval for output... */
15163 const double t0 = t - 0.5 * ctl->dt_mod;
15164 const double t1 = t + 0.5 * ctl->dt_mod;
15165
15166 /* Loop over observations... */
15167 for (int i = 0; i < nobs; i++) {
15168
15169 /* Check time... */
15170 if (rt[i] < t0)
15171 continue;
15172 else if (rt[i] >= t1)
15173 break;
15174
15175 /* Calculate Cartesian coordinates... */
15176 double x0[3];
15177 geo2cart(0, rlon[i], rlat[i], x0);
15178
15179 /* Set pressure range... */
15180 const double rp = P(rz[i]);
15181 const double ptop = P(rz[i] + ctl->sample_dz);
15182 const double pbot = P(rz[i] - ctl->sample_dz);
15183
15184 /* Init... */
15185 double mass = 0;
15186 int np = 0;
15187
15188 /* Loop over air parcels... */
15189 //#pragma omp parallel for default(shared) reduction(+:mass,np)
15190 for (int ip = 0; ip < atm->np; ip++) {
15191
15192 /* Check time... */
15193 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15194 continue;
15195
15196 /* Check latitude... */
15197 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
15198 continue;
15199
15200 /* Check horizontal distance... */
15201 double x1[3];
15202 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
15203 if (DIST2(x0, x1) > rmax2)
15204 continue;
15205
15206 /* Check pressure... */
15207 if (ctl->sample_dz > 0)
15208 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
15209 continue;
15210
15211 /* Add mass... */
15212 if (ctl->qnt_m >= 0)
15213 mass +=
15214 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
15215 np++;
15216 }
15217
15218 /* Calculate column density... */
15219 const double cd = mass / (1e6 * area);
15220
15221 /* Calculate volume mixing ratio... */
15222 double vmr = 0;
15223 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
15224 if (mass > 0) {
15225
15226 /* Get temperature... */
15227 double temp;
15229 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
15230 rlon[i], rlat[i], &temp, ci, cw, 1);
15231
15232 /* Calculate volume mixing ratio... */
15233 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
15234 }
15235 } else
15236 vmr = NAN;
15237
15238 /* Write output... */
15239 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
15240 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
15241 }
15242
15243 /* Finalize...... */
15244 if (t == ctl->t_stop) {
15245
15246 /* Close output file... */
15247 fclose(out);
15248
15249 /* Free... */
15250 free(rt);
15251 free(rz);
15252 free(rlon);
15253 free(rlat);
15254 free(robs);
15255 }
15256}
Here is the call graph for this function:

◆ write_station()

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

Writes station data to a specified file.

The write_station function writes station data to a file specified by the filename parameter. It takes control parameters (ctl), an atmospheric data structure (atm), and a time value (t) as input.

Parameters
filenameA string representing the filename where the station data will be written.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure representing atmospheric data.
tA double value representing the time at which the station data is being written.

The function performs the following steps:

  • Initializes variables and opens a new file if it's the start of the simulation.
  • Writes header information to the output file.
  • Sets geolocation and search radius for station data.
  • Processes air parcels and writes station data within the specified time interval and search radius.
  • Writes station data for each air parcel satisfying the criteria.
  • Closes the output file if it's the end of the simulation.
Note
This function writes station data to a file, including time, altitude, longitude, latitude, and additional quantities specified in the control parameters.
Author
Lars Hoffmann

Definition at line 15260 of file mptrac.c.

15264 {
15265
15266 if (ctl->met_coord_type != 0)
15267 ERRMSG("Only lat/lon grid supported");
15268
15269 static FILE *out;
15270
15271 static double rmax2, x0[3], x1[3];
15272
15273 /* Set timer... */
15274 SELECT_TIMER("WRITE_STATION", "OUTPUT");
15275
15276 /* Init... */
15277 if (t == ctl->t_start) {
15278
15279 /* Write info... */
15280 LOG(1, "Write station data: %s", filename);
15281
15282 /* Create new file... */
15283 if (!(out = fopen(filename, "w")))
15284 ERRMSG("Cannot create file!");
15285
15286 /* Write header... */
15287 fprintf(out,
15288 "# $1 = time [s]\n"
15289 "# $2 = altitude [km]\n"
15290 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
15291 for (int iq = 0; iq < ctl->nq; iq++)
15292 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
15293 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
15294 fprintf(out, "\n");
15295
15296 /* Set geolocation and search radius... */
15297 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
15298 rmax2 = SQR(ctl->stat_r);
15299 }
15300
15301 /* Set time interval for output... */
15302 const double t0 = t - 0.5 * ctl->dt_mod;
15303 const double t1 = t + 0.5 * ctl->dt_mod;
15304
15305 /* Loop over air parcels... */
15306 for (int ip = 0; ip < atm->np; ip++) {
15307
15308 /* Check time... */
15309 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15310 continue;
15311
15312 /* Check time range for station output... */
15313 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
15314 continue;
15315
15316 /* Check station flag... */
15317 if (ctl->qnt_stat >= 0)
15318 if ((int) atm->q[ctl->qnt_stat][ip])
15319 continue;
15320
15321 /* Get Cartesian coordinates... */
15322 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
15323
15324 /* Check horizontal distance... */
15325 if (DIST2(x0, x1) > rmax2)
15326 continue;
15327
15328 /* Set station flag... */
15329 if (ctl->qnt_stat >= 0)
15330 atm->q[ctl->qnt_stat][ip] = 1;
15331
15332 /* Write data... */
15333 fprintf(out, "%.2f %g %g %g",
15334 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
15335 for (int iq = 0; iq < ctl->nq; iq++) {
15336 fprintf(out, " ");
15337 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
15338 }
15339 fprintf(out, "\n");
15340 }
15341
15342 /* Close file... */
15343 if (t == ctl->t_stop)
15344 fclose(out);
15345}
Here is the call graph for this function:

◆ write_vtk()

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

Writes VTK (Visualization Toolkit) data to a specified file.

The write_vtk function writes VTK data to a file specified by the filename parameter. It takes control parameters (ctl), an atmospheric data structure (atm), and a time value (t) as input.

Parameters
filenameA string representing the filename where the VTK data will be written.
ctlA pointer to a ctl_t structure containing control parameters.
atmA pointer to an atm_t structure representing atmospheric data.
tA double value representing the time at which the VTK data is being written.

The function performs the following steps:

  • Sets a timer and logs information about writing VTK data.
  • Sets a time interval for output based on the specified time and control parameters.
  • Creates a new file and checks if the file creation was successful.
  • Counts the number of data points to be written.
  • Writes the VTK header, including metadata.
  • Writes point coordinates based on the sphere or Cartesian coordinate system.
  • Writes point data for each quantity specified in the control parameters.
  • Closes the output file.
Note
This function writes VTK data in ASCII format, including point coordinates and associated scalar data for visualization purposes.
Author
Lars Hoffmann

Definition at line 15349 of file mptrac.c.

15353 {
15354
15355 if (ctl->met_coord_type != 0)
15356 ERRMSG("Only lat/lon grid supported");
15357
15358 FILE *out;
15359
15360 /* Set timer... */
15361 SELECT_TIMER("WRITE_VTK", "OUTPUT");
15362
15363 /* Write info... */
15364 LOG(1, "Write VTK data: %s", filename);
15365
15366 /* Set time interval for output... */
15367 const double t0 = t - 0.5 * ctl->dt_mod;
15368 const double t1 = t + 0.5 * ctl->dt_mod;
15369
15370 /* Create file... */
15371 if (!(out = fopen(filename, "w")))
15372 ERRMSG("Cannot create file!");
15373
15374 /* Count data points... */
15375 int np = 0;
15376 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15377 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15378 continue;
15379 np++;
15380 }
15381
15382 /* Write header... */
15383 fprintf(out,
15384 "# vtk DataFile Version 3.0\n"
15385 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
15386
15387 /* Write point coordinates... */
15388 fprintf(out, "POINTS %d float\n", np);
15389 if (ctl->vtk_sphere) {
15390 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15391 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15392 continue;
15393 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
15394 + ctl->vtk_offset) / RE;
15395 const double coslat = cos(DEG2RAD(atm->lat[ip]));
15396 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
15397 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
15398 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
15399 fprintf(out, "%g %g %g\n", x, y, z);
15400 }
15401 } else
15402 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15403 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15404 continue;
15405 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
15406 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
15407 }
15408
15409 /* Write point data... */
15410 fprintf(out, "POINT_DATA %d\n", np);
15411 for (int iq = 0; iq < ctl->nq; iq++) {
15412 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
15413 ctl->qnt_name[iq]);
15414 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15415 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15416 continue;
15417 fprintf(out, "%g\n", atm->q[iq][ip]);
15418 }
15419 }
15420
15421 /* Close file... */
15422 fclose(out);
15423}