29 {
30
32
34
35 FILE *out;
36
37 double *ahtd, *aqtd, *avtd, ahtdm, aqtdm[
NQ], avtdm, *lat1_old, *lat2_old,
38 *lh1, *lh2, *lon1_old, *lon2_old, *lv1, *lv2, *rhtd, *rqtd, *rvtd, rhtdm,
39 rqtdm[
NQ], rvtdm, t0 =
40 0, x0[3], x1[3], x2[3], z1, *z1_old, z2, *z2_old, *work;
41
42 int init = 0, np;
43
44
47 ALLOC(lon1_old,
double,
49 ALLOC(lat1_old,
double,
57 ALLOC(lon2_old,
double,
59 ALLOC(lat2_old,
double,
81
82
83 if (argc < 6)
84 ERRMSG(
"Give parameters: <ctl> <dist.tab> <param> <atm1a> <atm1b>"
85 " [<atm2a> <atm2b> ...]");
86
87
89 const int ens =
90 (int)
scan_ctl(argv[1], argc, argv,
"DIST_ENS", -1,
"-999", NULL);
91 const double p0 =
92 P(
scan_ctl(argv[1], argc, argv,
"DIST_Z0", -1,
"-1000", NULL));
93 const double p1 =
94 P(
scan_ctl(argv[1], argc, argv,
"DIST_Z1", -1,
"1000", NULL));
95 const double lat0 =
96 scan_ctl(argv[1], argc, argv,
"DIST_LAT0", -1,
"-1000", NULL);
97 const double lat1 =
98 scan_ctl(argv[1], argc, argv,
"DIST_LAT1", -1,
"1000", NULL);
99 const double lon0 =
100 scan_ctl(argv[1], argc, argv,
"DIST_LON0", -1,
"-1000", NULL);
101 const double lon1 =
102 scan_ctl(argv[1], argc, argv,
"DIST_LON1", -1,
"1000", NULL);
103 const double zscore =
104 scan_ctl(argv[1], argc, argv,
"DIST_ZSCORE", -1,
"-999", NULL);
105
106
107 LOG(1,
"Write transport deviations: %s", argv[2]);
108
109
110 if (!(out = fopen(argv[2], "w")))
111 ERRMSG(
"Cannot create file!");
112
113
114 fprintf(out,
115 "# $1 = time [s]\n"
116 "# $2 = time difference [s]\n"
117 "# $3 = absolute horizontal distance (%s) [km]\n"
118 "# $4 = relative horizontal distance (%s) [%%]\n"
119 "# $5 = absolute vertical distance (%s) [km]\n"
120 "# $6 = relative vertical distance (%s) [%%]\n",
121 argv[3], argv[3], argv[3], argv[3]);
122 for (
int iq = 0; iq < ctl.
nq; iq++)
123 fprintf(out,
124 "# $%d = %s absolute difference (%s) [%s]\n"
125 "# $%d = %s relative difference (%s) [%%]\n",
127 8 + 2 * iq, ctl.
qnt_name[iq], argv[3]);
128 fprintf(out,
"# $%d = number of particles\n\n", 7 + 2 * ctl.
nq);
129
130
131 for (int f = 4; f < argc; f += 2) {
132
133
135 continue;
136
137
138 if (atm1->
np != atm2->
np)
139 ERRMSG(
"Different numbers of particles!");
140
141
143
144
145 if (!init) {
146 init = 1;
147 t0 = t;
148 }
149
150
151 np = 0;
152 for (
int ip = 0; ip < atm1->
np; ip++) {
153 ahtd[ip] = avtd[ip] = rhtd[ip] = rvtd[ip] = 0;
154 for (
int iq = 0; iq < ctl.
nq; iq++)
155 aqtd[iq *
NP + ip] = rqtd[iq *
NP + ip] = 0;
156 }
157
158
159 for (
int ip = 0; ip < atm1->
np; ip++) {
160
161
164 ERRMSG(
"Air parcel index does not match!");
165
166
169 || atm2->
q[ctl.
qnt_ens][ip] != ens))
170 continue;
171
172
173 if (!isfinite(atm1->
time[ip]) || !isfinite(atm2->
time[ip]))
174 continue;
175
176
177 if (atm1->
p[ip] > p0 || atm1->
p[ip] < p1
178 || atm1->
lon[ip] < lon0 || atm1->
lon[ip] > lon1
179 || atm1->
lat[ip] < lat0 || atm1->
lat[ip] > lat1)
180 continue;
181 if (atm2->
p[ip] > p0 || atm2->
p[ip] < p1
182 || atm2->
lon[ip] < lon0 || atm2->
lon[ip] > lon1
183 || atm2->
lat[ip] < lat0 || atm2->
lat[ip] > lat1)
184 continue;
185
186
191
192
193 ahtd[np] =
DIST(x1, x2);
194 avtd[np] = z1 - z2;
195 for (
int iq = 0; iq < ctl.
nq; iq++)
196 aqtd[iq *
NP + np] = atm1->
q[iq][ip] - atm2->
q[iq][ip];
197
198
199 if (f > 4) {
200
201
202 geo2cart(0, lon1_old[ip], lat1_old[ip], x0);
203 lh1[ip] +=
DIST(x0, x1);
204 lv1[ip] += fabs(z1_old[ip] - z1);
205
206 geo2cart(0, lon2_old[ip], lat2_old[ip], x0);
207 lh2[ip] +=
DIST(x0, x2);
208 lv2[ip] += fabs(z2_old[ip] - z2);
209
210
211 if (lh1[ip] + lh2[ip] > 0)
212 rhtd[np] = 200. *
DIST(x1, x2) / (lh1[ip] + lh2[ip]);
213 if (lv1[ip] + lv2[ip] > 0)
214 rvtd[np] = 200. * (z1 - z2) / (lv1[ip] + lv2[ip]);
215 }
216
217
218 for (
int iq = 0; iq < ctl.
nq; iq++)
219 rqtd[iq *
NP + np] = 200. * (atm1->
q[iq][ip] - atm2->
q[iq][ip])
220 / (fabs(atm1->
q[iq][ip]) + fabs(atm2->
q[iq][ip]));
221
222
223 lon1_old[ip] = atm1->
lon[ip];
224 lat1_old[ip] = atm1->
lat[ip];
225 z1_old[ip] = z1;
226
227 lon2_old[ip] = atm2->
lon[ip];
228 lat2_old[ip] = atm2->
lat[ip];
229 z2_old[ip] = z2;
230
231
232 np++;
233 }
234
235
236 if (zscore > 0 && np > 1) {
237
238
239 const size_t n = (size_t) np;
240 const double muh = gsl_stats_mean(ahtd, 1, n);
241 const double muv = gsl_stats_mean(avtd, 1, n);
242 const double sigh = gsl_stats_sd(ahtd, 1, n);
243 const double sigv = gsl_stats_sd(avtd, 1, n);
244
245
246 np = 0;
247 for (size_t i = 0; i < n; i++)
248 if (fabs((ahtd[i] - muh) / sigh) < zscore
249 && fabs((avtd[i] - muv) / sigv) < zscore) {
250 ahtd[np] = ahtd[i];
251 rhtd[np] = rhtd[i];
252 avtd[np] = avtd[i];
253 rvtd[np] = rvtd[i];
254 for (
int iq = 0; iq < ctl.
nq; iq++) {
255 aqtd[iq *
NP + np] = aqtd[iq *
NP + (int) i];
256 rqtd[iq *
NP + np] = rqtd[iq *
NP + (int) i];
257 }
258 np++;
259 }
260 }
261
262
263 if (strcasecmp(argv[3], "mean") == 0) {
264 ahtdm = gsl_stats_mean(ahtd, 1, (size_t) np);
265 rhtdm = gsl_stats_mean(rhtd, 1, (size_t) np);
266 avtdm = gsl_stats_mean(avtd, 1, (size_t) np);
267 rvtdm = gsl_stats_mean(rvtd, 1, (size_t) np);
268 for (
int iq = 0; iq < ctl.
nq; iq++) {
269 aqtdm[iq] = gsl_stats_mean(&aqtd[iq *
NP], 1, (
size_t) np);
270 rqtdm[iq] = gsl_stats_mean(&rqtd[iq *
NP], 1, (
size_t) np);
271 }
272 } else if (strcasecmp(argv[3], "stddev") == 0) {
273 ahtdm = gsl_stats_sd(ahtd, 1, (size_t) np);
274 rhtdm = gsl_stats_sd(rhtd, 1, (size_t) np);
275 avtdm = gsl_stats_sd(avtd, 1, (size_t) np);
276 rvtdm = gsl_stats_sd(rvtd, 1, (size_t) np);
277 for (
int iq = 0; iq < ctl.
nq; iq++) {
278 aqtdm[iq] = gsl_stats_sd(&aqtd[iq *
NP], 1, (
size_t) np);
279 rqtdm[iq] = gsl_stats_sd(&rqtd[iq *
NP], 1, (
size_t) np);
280 }
281 } else if (strcasecmp(argv[3], "min") == 0) {
282 ahtdm = gsl_stats_min(ahtd, 1, (size_t) np);
283 rhtdm = gsl_stats_min(rhtd, 1, (size_t) np);
284 avtdm = gsl_stats_min(avtd, 1, (size_t) np);
285 rvtdm = gsl_stats_min(rvtd, 1, (size_t) np);
286 for (
int iq = 0; iq < ctl.
nq; iq++) {
287 aqtdm[iq] = gsl_stats_min(&aqtd[iq *
NP], 1, (
size_t) np);
288 rqtdm[iq] = gsl_stats_min(&rqtd[iq *
NP], 1, (
size_t) np);
289 }
290 } else if (strcasecmp(argv[3], "max") == 0) {
291 ahtdm = gsl_stats_max(ahtd, 1, (size_t) np);
292 rhtdm = gsl_stats_max(rhtd, 1, (size_t) np);
293 avtdm = gsl_stats_max(avtd, 1, (size_t) np);
294 rvtdm = gsl_stats_max(rvtd, 1, (size_t) np);
295 for (
int iq = 0; iq < ctl.
nq; iq++) {
296 aqtdm[iq] = gsl_stats_max(&aqtd[iq *
NP], 1, (
size_t) np);
297 rqtdm[iq] = gsl_stats_max(&rqtd[iq *
NP], 1, (
size_t) np);
298 }
299 } else if (strcasecmp(argv[3], "skew") == 0) {
300 ahtdm = gsl_stats_skew(ahtd, 1, (size_t) np);
301 rhtdm = gsl_stats_skew(rhtd, 1, (size_t) np);
302 avtdm = gsl_stats_skew(avtd, 1, (size_t) np);
303 rvtdm = gsl_stats_skew(rvtd, 1, (size_t) np);
304 for (
int iq = 0; iq < ctl.
nq; iq++) {
305 aqtdm[iq] = gsl_stats_skew(&aqtd[iq *
NP], 1, (
size_t) np);
306 rqtdm[iq] = gsl_stats_skew(&rqtd[iq *
NP], 1, (
size_t) np);
307 }
308 } else if (strcasecmp(argv[3], "kurt") == 0) {
309 ahtdm = gsl_stats_kurtosis(ahtd, 1, (size_t) np);
310 rhtdm = gsl_stats_kurtosis(rhtd, 1, (size_t) np);
311 avtdm = gsl_stats_kurtosis(avtd, 1, (size_t) np);
312 rvtdm = gsl_stats_kurtosis(rvtd, 1, (size_t) np);
313 for (
int iq = 0; iq < ctl.
nq; iq++) {
314 aqtdm[iq] = gsl_stats_kurtosis(&aqtd[iq *
NP], 1, (
size_t) np);
315 rqtdm[iq] = gsl_stats_kurtosis(&rqtd[iq *
NP], 1, (
size_t) np);
316 }
317 } else if (strcasecmp(argv[3], "absdev") == 0) {
318 ahtdm = gsl_stats_absdev_m(ahtd, 1, (size_t) np, 0.0);
319 rhtdm = gsl_stats_absdev_m(rhtd, 1, (size_t) np, 0.0);
320 avtdm = gsl_stats_absdev_m(avtd, 1, (size_t) np, 0.0);
321 rvtdm = gsl_stats_absdev_m(rvtd, 1, (size_t) np, 0.0);
322 for (
int iq = 0; iq < ctl.
nq; iq++) {
323 aqtdm[iq] = gsl_stats_absdev_m(&aqtd[iq *
NP], 1, (
size_t) np, 0.0);
324 rqtdm[iq] = gsl_stats_absdev_m(&rqtd[iq *
NP], 1, (
size_t) np, 0.0);
325 }
326 } else if (strcasecmp(argv[3], "median") == 0) {
327 ahtdm = gsl_stats_median(ahtd, 1, (size_t) np);
328 rhtdm = gsl_stats_median(rhtd, 1, (size_t) np);
329 avtdm = gsl_stats_median(avtd, 1, (size_t) np);
330 rvtdm = gsl_stats_median(rvtd, 1, (size_t) np);
331 for (
int iq = 0; iq < ctl.
nq; iq++) {
332 aqtdm[iq] = gsl_stats_median(&aqtd[iq *
NP], 1, (
size_t) np);
333 rqtdm[iq] = gsl_stats_median(&rqtd[iq *
NP], 1, (
size_t) np);
334 }
335 } else if (strcasecmp(argv[3], "mad") == 0) {
336 ahtdm = gsl_stats_mad0(ahtd, 1, (size_t) np, work);
337 rhtdm = gsl_stats_mad0(rhtd, 1, (size_t) np, work);
338 avtdm = gsl_stats_mad0(avtd, 1, (size_t) np, work);
339 rvtdm = gsl_stats_mad0(rvtd, 1, (size_t) np, work);
340 for (
int iq = 0; iq < ctl.
nq; iq++) {
341 aqtdm[iq] = gsl_stats_mad0(&aqtd[iq *
NP], 1, (
size_t) np, work);
342 rqtdm[iq] = gsl_stats_mad0(&rqtd[iq *
NP], 1, (
size_t) np, work);
343 }
344 } else
345 ERRMSG(
"Unknown parameter!");
346
347
348 fprintf(out, "%.2f %.2f %g %g %g %g", t, t - t0,
349 ahtdm, rhtdm, avtdm, rvtdm);
350 for (
int iq = 0; iq < ctl.
nq; iq++) {
351 fprintf(out, " ");
353 fprintf(out, " ");
355 }
356 fprintf(out, " %d\n", np);
357 }
358
359
360 fclose(out);
361
362
363 free(atm1);
364 free(atm2);
365 free(lon1_old);
366 free(lat1_old);
367 free(z1_old);
368 free(lh1);
369 free(lv1);
370 free(lon2_old);
371 free(lat2_old);
372 free(z2_old);
373 free(lh2);
374 free(lv2);
375 free(ahtd);
376 free(avtd);
377 free(aqtd);
378 free(rhtd);
379 free(rvtd);
380 free(rqtd);
381 free(work);
382
383 return EXIT_SUCCESS;
384}
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.
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
void read_ctl(const char *filename, int argc, char *argv[], ctl_t *ctl)
Reads control parameters from a configuration file and populates the given structure.
int read_atm(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a specified file into the given atmospheric structure.
void geo2cart(const double z, const double lon, const double lat, double *x)
Converts geographic coordinates (longitude, latitude, altitude) to Cartesian coordinates.
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
#define Z(p)
Convert pressure to altitude.
#define P(z)
Compute pressure at given altitude.
#define NQ
Maximum number of quantities per data point.
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
#define NP
Maximum number of atmospheric data points.
#define LOG(level,...)
Print a log message with a specified logging level.
#define DIST(a, b)
Calculate the distance between two points in Cartesian coordinates.
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].
char qnt_format[NQ][LEN]
Quantity output format.
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
char qnt_unit[NQ][LEN]
Quantity units.
char qnt_name[NQ][LEN]
Quantity names.
int qnt_ens
Quantity array index for ensemble IDs.
int qnt_idx
Quantity array index for air parcel IDs.
int nq
Number of quantities.