58 ERRMSG(
"Missing or invalid command-line arguments.\n\n"
59 "Usage: atm_init <ctl> <atm_out> [KEY VALUE ...]\n\n"
60 "Use -h for full help.");
72 (int)
scan_ctl(argv[1], argc, argv,
"INIT_ENS", -1,
"0", NULL);
73 const double t0 =
scan_ctl(argv[1], argc, argv,
"INIT_T0", -1,
"0", NULL);
74 const double t1 =
scan_ctl(argv[1], argc, argv,
"INIT_T1", -1,
"0", NULL);
75 const double dt =
scan_ctl(argv[1], argc, argv,
"INIT_DT", -1,
"1", NULL);
76 const double z0 =
scan_ctl(argv[1], argc, argv,
"INIT_Z0", -1,
"0", NULL);
77 const double z1 =
scan_ctl(argv[1], argc, argv,
"INIT_Z1", -1,
"0", NULL);
78 const double dz =
scan_ctl(argv[1], argc, argv,
"INIT_DZ", -1,
"1", NULL);
80 scan_ctl(argv[1], argc, argv,
"INIT_RELZ0", -1,
"-999", NULL);
82 scan_ctl(argv[1], argc, argv,
"INIT_RELZ1", -1,
"-999", NULL);
84 scan_ctl(argv[1], argc, argv,
"INIT_DRELZ", -1,
"1", NULL);
85 const int random_relz =
86 (int)
scan_ctl(argv[1], argc, argv,
"INIT_RANDOM_RELZ", -1,
"0", NULL);
87 const int use_relz = (relz0 > -900.0 || relz1 > -900.0);
89 scan_ctl(argv[1], argc, argv,
"INIT_LON0", -1,
"0", NULL);
91 scan_ctl(argv[1], argc, argv,
"INIT_LON1", -1,
"0", NULL);
93 scan_ctl(argv[1], argc, argv,
"INIT_DLON", -1,
"1", NULL);
95 scan_ctl(argv[1], argc, argv,
"INIT_LAT0", -1,
"0", NULL);
97 scan_ctl(argv[1], argc, argv,
"INIT_LAT1", -1,
"0", NULL);
99 scan_ctl(argv[1], argc, argv,
"INIT_DLAT", -1,
"1", NULL);
100 const double st =
scan_ctl(argv[1], argc, argv,
"INIT_ST", -1,
"0", NULL);
101 const double sz =
scan_ctl(argv[1], argc, argv,
"INIT_SZ", -1,
"0", NULL);
103 scan_ctl(argv[1], argc, argv,
"INIT_SLON", -1,
"0", NULL);
105 scan_ctl(argv[1], argc, argv,
"INIT_SLAT", -1,
"0", NULL);
106 const double sx =
scan_ctl(argv[1], argc, argv,
"INIT_SX", -1,
"0", NULL);
107 const double ut =
scan_ctl(argv[1], argc, argv,
"INIT_UT", -1,
"0", NULL);
108 const double uz =
scan_ctl(argv[1], argc, argv,
"INIT_UZ", -1,
"0", NULL);
110 scan_ctl(argv[1], argc, argv,
"INIT_ULON", -1,
"0", NULL);
112 scan_ctl(argv[1], argc, argv,
"INIT_ULAT", -1,
"0", NULL);
114 (int)
scan_ctl(argv[1], argc, argv,
"INIT_EVENLY", -1,
"0", NULL);
116 (int)
scan_ctl(argv[1], argc, argv,
"INIT_COL_MASS", -1,
"0", NULL);
117 const int well_mixed =
118 (int)
scan_ctl(argv[1], argc, argv,
"INIT_WELL_MIXED", -1,
"0", NULL);
120 (int)
scan_ctl(argv[1], argc, argv,
"INIT_REP", -1,
"1", NULL);
122 (int)
scan_ctl(argv[1], argc, argv,
"INIT_NP", -1,
"0", NULL);
123 const double m =
scan_ctl(argv[1], argc, argv,
"INIT_MASS", -1,
"0", NULL);
124 const double vmr =
scan_ctl(argv[1], argc, argv,
"INIT_VMR", -1,
"0", NULL);
125 const double bellrad =
126 scan_ctl(argv[1], argc, argv,
"INIT_BELLRAD", -1,
"0", NULL);
127 const int idx_offset =
128 (int)
scan_ctl(argv[1], argc, argv,
"INIT_IDX_OFFSET", -1,
"0", NULL);
132 ERRMSG(
"INIT_EVENLY is only supported for lat/lon grids");
134 ERRMSG(
"INIT_BELLRAD is only supported for lat/lon grids");
136 ERRMSG(
"INIT_REP must be positive!");
137 if (init_np < 0 || init_np >
NP)
138 ERRMSG(
"INIT_NP must be between 0 and NP!");
140 ERRMSG(
"INIT_WELL_MIXED is only supported for lat/lon grids!");
141 if (well_mixed && !even)
142 ERRMSG(
"INIT_WELL_MIXED requires INIT_EVENLY=1!");
143 if (well_mixed && !col_mass)
144 ERRMSG(
"INIT_WELL_MIXED requires INIT_COL_MASS=1!");
145 if (init_np > 0 && !well_mixed)
146 ERRMSG(
"INIT_NP requires INIT_WELL_MIXED!");
147 if (col_mass && (t1 != t0 || st > 0 || ut > 0))
149 (
"INIT_COL_MASS/INIT_WELL_MIXED require INIT_T0 == INIT_T1 and no time scattering!");
150 if (use_relz && (z0 != 0.0 || z1 != 0.0))
151 ERRMSG(
"INIT_RELZ0/INIT_RELZ1 cannot be combined with INIT_Z0/INIT_Z1!");
152 if (use_relz && (relz0 <= -900.0 || relz1 <= -900.0))
153 ERRMSG(
"INIT_RELZ0 and INIT_RELZ1 must both be set!");
154 if (use_relz && (t1 != t0 || st > 0 || ut > 0))
156 (
"INIT_RELZ0/INIT_RELZ1 require INIT_T0 == INIT_T1 and no time scattering!");
157 if (use_relz && random_relz && relz1 < relz0)
158 ERRMSG(
"INIT_RELZ1 must be greater than or equal to INIT_RELZ0!");
159 if (use_relz && !random_relz && drelz <= 0)
160 ERRMSG(
"INIT_DRELZ must be positive!");
161 if (!use_relz && dz <= 0)
162 ERRMSG(
"INIT_DZ must be positive!");
169 gsl_rng *rng = gsl_rng_alloc(gsl_rng_default);
172 double ptop = 0, dpcolmax = 0;
173 if (col_mass || use_relz) {
175 ptop = gsl_stats_min(met0->
p, 1, (
size_t) met0->
np);
177 for (
int ix = 0; ix < met0->
nx; ix++)
178 for (
int iy = 0; iy < met0->
ny; iy++) {
179 psmax =
MAX(psmax, met0->
ps[ix][iy]);
180 psmax =
MAX(psmax, met1->
ps[ix][iy]);
182 dpcolmax = psmax - ptop;
187 const int ntrymax = init_np > 0 ? 1000000 * init_np : 0;
189 const double vert0 = use_relz ? relz0 : z0;
190 const double vert1 = use_relz ? (random_relz ? relz0 : relz1) : z1;
191 const double dvert = use_relz ? (random_relz ? 1.0 : drelz) : dz;
192 for (
double t = t0; t <= t1 && !(init_np > 0 && atm->
np >= init_np);
194 for (
double vert = vert0;
195 vert <= vert1 && !(init_np > 0 && atm->
np >= init_np);
197 for (
double lon = lon0;
198 lon <= lon1 && !(init_np > 0 && atm->
np >= init_np); lon += dlon)
199 for (
double lat = lat0;
200 lat <= lat1 && !(init_np > 0 && atm->
np >= init_np);
203 irep < rep && !(init_np > 0 && atm->
np >= init_np); irep++) {
206 if (init_np > 0 && ++ntry > ntrymax)
208 (
"INIT_NP could not be reached by INIT_WELL_MIXED sampling!");
211 double rg = gsl_ran_gaussian_ziggurat(rng, st / 2.3548);
212 double ru = ut * (gsl_rng_uniform(rng) - 0.5);
213 atm->
time[atm->
np] = (t + rg + ru);
217 rg = gsl_ran_gaussian_ziggurat(rng, sz / 2.3548);
218 ru = uz * (gsl_rng_uniform(rng) - 0.5);
219 atm->
p[atm->
np] =
P(vert + rg + ru);
223 rg = gsl_ran_gaussian_ziggurat(rng, slon / 2.3548);
224 const double sx_coord =
226 double rx = gsl_ran_gaussian_ziggurat(rng, sx_coord / 2.3548);
227 ru = ulon * (gsl_rng_uniform(rng) - 0.5);
228 atm->
lon[atm->
np] = (lon + rg + rx + ru);
236 rg = gsl_ran_gaussian_ziggurat(rng, slat / 2.3548);
237 const double sy_coord =
239 rx = gsl_ran_gaussian_ziggurat(rng, sy_coord / 2.3548);
240 ru = ulat * (gsl_rng_uniform(rng) - 0.5);
241 atm->
lat[atm->
np] = (lat + rg + rx + ru);
242 }
while (even && gsl_rng_uniform(rng) >
247 rg = gsl_ran_gaussian_ziggurat(rng, sz / 2.3548);
248 ru = uz * (gsl_rng_uniform(rng) - 0.5);
249 const double relz_sample =
250 random_relz ? relz0 + gsl_rng_uniform(rng) * (relz1 - relz0)
256 atm->
lat[atm->
np], &ps, ci, cw, 1);
259 atm->
lat[atm->
np], &pbl, ci, cw, 1);
264 const double zsurf =
Z(ps);
265 const double zpbl =
Z(pbl);
266 const double depth = zpbl - zsurf;
269 atm->
p[atm->
np] =
P(zsurf + (relz_sample + rg + ru) * depth);
275 geo2cart(0.0, 0.5 * (lon0 + lon1), 0.5 * (lat0 + lat1), x0);
284 0.5 * (1. + cos(M_PI * rad / bellrad));
287 0.5 * (1. + cos(M_PI * rad / bellrad));
296 atm->
lat[atm->
np], &ps, ci, cw, 1);
297 const double dpcol = ps - ptop;
298 if (gsl_rng_uniform(rng) > dpcol / dpcolmax)
301 atm->
p[atm->
np] = ptop + dpcol * gsl_rng_uniform(rng);
305 if ((++atm->
np) >
NP)
306 ERRMSG(
"Too many particles!");
309 }
while (init_np > 0 && atm->
np < init_np);
313 ERRMSG(
"Did not create any air parcels!");
316 if (ctl.
qnt_m >= 0 && bellrad <= 0)
317 for (
int ip = 0; ip < atm->
np; ip++)
318 atm->
q[ctl.
qnt_m][ip] = m / atm->
np;
321 if (ctl.
qnt_vmr >= 0 && bellrad <= 0)
322 for (
int ip = 0; ip < atm->
np; ip++)
327 for (
int ip = 0; ip < atm->
np; ip++)
328 atm->
q[ctl.
qnt_idx][ip] = idx_offset + ip;
332 for (
int ip = 0; ip < atm->
np; ip++)
355 printf(
"\nMPTRAC atm_init tool.\n\n");
357 (
"Create an atmospheric data file with initial air parcel positions.\n");
360 printf(
" atm_init <ctl> <atm_out> [KEY VALUE ...]\n");
362 printf(
"Arguments:\n");
363 printf(
" <ctl> Control file.\n");
364 printf(
" <atm_out> Atmospheric output file.\n");
365 printf(
" [KEY VALUE] Optional control parameters.\n");
366 printf(
"\nFurther information:\n");
367 printf(
" Manual: https://slcs-jsc.github.io/mptrac/\n");
int main(int argc, char *argv[])
void usage(void)
Print command-line help.
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.
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.
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.
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
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.
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.
void geo2cart(const double z, const double lon, const double lat, double *x)
Converts geographic coordinates (longitude, latitude, altitude) to Cartesian coordinates.
MPTRAC library declarations.
#define RE
Mean radius of Earth [km].
#define DOTP(a, b)
Calculate the dot product of two vectors.
#define INTPOL_INIT
Initialize arrays for interpolation.
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
#define USAGE
Print usage information on -h or --help.
#define Z(p)
Convert pressure to altitude.
#define P(z)
Compute pressure at given altitude.
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
#define DEG2RAD(deg)
Converts degrees to radians.
#define NP
Maximum number of atmospheric data points.
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
#define MAX(a, b)
Macro to determine the maximum of two values.
double lat[NP]
Latitude [deg].
double lon[NP]
Longitude [deg].
int np
Number of air parcels.
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
double p[NP]
Pressure [hPa].
int qnt_m
Quantity array index for mass.
int qnt_aoa
Quantity array index for age of air.
int qnt_vmr
Quantity array index for volume mixing ratio.
int qnt_pbl
Quantity array index for boundary layer pressure.
int qnt_ps
Quantity array index for surface pressure.
int qnt_ens
Quantity array index for ensemble IDs.
int met_coord_type
Type of coordinates for meteo data (-1=detect, 0=lat/lon [deg], 1=UTM [m]).
int qnt_idx
Quantity array index for air parcel IDs.
Domain decomposition data structure.
int nx
Number of longitudes.
int ny
Number of latitudes.
float ps[EX][EY]
Surface pressure [hPa].
int np
Number of pressure levels.
float pbl[EX][EY]
Boundary layer pressure [hPa].
double p[EP]
Pressure levels [hPa].