MPTRAC
atm_dist.c
Go to the documentation of this file.
1/*
2 This file is part of MPTRAC.
3
4 MPTRAC is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 MPTRAC is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with MPTRAC. If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright (C) 2013-2025 Forschungszentrum Juelich GmbH
18*/
19
25#include "mptrac.h"
26
27int main(
28 int argc,
29 char *argv[]) {
30
31 ctl_t ctl;
32
33 atm_t *atm1, *atm2;
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 /* Allocate... */
45 ALLOC(atm1, atm_t, 1);
46 ALLOC(atm2, atm_t, 1);
47 ALLOC(lon1_old, double,
48 NP);
49 ALLOC(lat1_old, double,
50 NP);
51 ALLOC(z1_old, double,
52 NP);
53 ALLOC(lh1, double,
54 NP);
55 ALLOC(lv1, double,
56 NP);
57 ALLOC(lon2_old, double,
58 NP);
59 ALLOC(lat2_old, double,
60 NP);
61 ALLOC(z2_old, double,
62 NP);
63 ALLOC(lh2, double,
64 NP);
65 ALLOC(lv2, double,
66 NP);
67 ALLOC(ahtd, double,
68 NP);
69 ALLOC(avtd, double,
70 NP);
71 ALLOC(aqtd, double,
72 NP * NQ);
73 ALLOC(rhtd, double,
74 NP);
75 ALLOC(rvtd, double,
76 NP);
77 ALLOC(rqtd, double,
78 NP * NQ);
79 ALLOC(work, double,
80 NP);
81
82 /* Check arguments... */
83 if (argc < 6)
84 ERRMSG("Give parameters: <ctl> <dist.tab> <param> <atm1a> <atm1b>"
85 " [<atm2a> <atm2b> ...]");
86
87 /* Read control parameters... */
88 mptrac_read_ctl(argv[1], argc, argv, &ctl);
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 /* Write info... */
107 LOG(1, "Write transport deviations: %s", argv[2]);
108
109 /* Create output file... */
110 if (!(out = fopen(argv[2], "w")))
111 ERRMSG("Cannot create file!");
112
113 /* Write header... */
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",
126 7 + 2 * iq, ctl.qnt_name[iq], argv[3], ctl.qnt_unit[iq],
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 /* Loop over file pairs... */
131 for (int f = 4; f < argc; f += 2) {
132
133 /* Read atmopheric data... */
134 if (!mptrac_read_atm(argv[f], &ctl, atm1)
135 || !mptrac_read_atm(argv[f + 1], &ctl, atm2))
136 continue;
137
138 /* Check if structs match... */
139 if (atm1->np != atm2->np)
140 ERRMSG("Different numbers of particles!");
141
142 /* Get time from filename... */
143 const double t = time_from_filename(argv[f], ctl.atm_type < 2 ? 20 : 19);
144
145 /* Save initial time... */
146 if (!init) {
147 init = 1;
148 t0 = t;
149 }
150
151 /* Init... */
152 np = 0;
153 for (int ip = 0; ip < atm1->np; ip++) {
154 ahtd[ip] = avtd[ip] = rhtd[ip] = rvtd[ip] = 0;
155 for (int iq = 0; iq < ctl.nq; iq++)
156 aqtd[iq * NP + ip] = rqtd[iq * NP + ip] = 0;
157 }
158
159 /* Loop over air parcels... */
160 for (int ip = 0; ip < atm1->np; ip++) {
161
162 /* Check air parcel index... */
163 if (ctl.qnt_idx > 0
164 && (atm1->q[ctl.qnt_idx][ip] != atm2->q[ctl.qnt_idx][ip]))
165 ERRMSG("Air parcel index does not match!");
166
167 /* Check ensemble index... */
168 if (ctl.qnt_ens > 0
169 && (atm1->q[ctl.qnt_ens][ip] != ens
170 || atm2->q[ctl.qnt_ens][ip] != ens))
171 continue;
172
173 /* Check time... */
174 if (!isfinite(atm1->time[ip]) || !isfinite(atm2->time[ip]))
175 continue;
176
177 /* Check spatial range... */
178 if (atm1->p[ip] > p0 || atm1->p[ip] < p1
179 || atm1->lon[ip] < lon0 || atm1->lon[ip] > lon1
180 || atm1->lat[ip] < lat0 || atm1->lat[ip] > lat1)
181 continue;
182 if (atm2->p[ip] > p0 || atm2->p[ip] < p1
183 || atm2->lon[ip] < lon0 || atm2->lon[ip] > lon1
184 || atm2->lat[ip] < lat0 || atm2->lat[ip] > lat1)
185 continue;
186
187 /* Convert coordinates... */
188 geo2cart(0, atm1->lon[ip], atm1->lat[ip], x1);
189 geo2cart(0, atm2->lon[ip], atm2->lat[ip], x2);
190 z1 = Z(atm1->p[ip]);
191 z2 = Z(atm2->p[ip]);
192
193 /* Calculate absolute transport deviations... */
194 ahtd[np] = DIST(x1, x2);
195 avtd[np] = z1 - z2;
196 for (int iq = 0; iq < ctl.nq; iq++)
197 aqtd[iq * NP + np] = atm1->q[iq][ip] - atm2->q[iq][ip];
198
199 /* Calculate relative transport deviations... */
200 if (f > 4) {
201
202 /* Get trajectory lengths... */
203 geo2cart(0, lon1_old[ip], lat1_old[ip], x0);
204 lh1[ip] += DIST(x0, x1);
205 lv1[ip] += fabs(z1_old[ip] - z1);
206
207 geo2cart(0, lon2_old[ip], lat2_old[ip], x0);
208 lh2[ip] += DIST(x0, x2);
209 lv2[ip] += fabs(z2_old[ip] - z2);
210
211 /* Get relative transport deviations... */
212 if (lh1[ip] + lh2[ip] > 0)
213 rhtd[np] = 200. * DIST(x1, x2) / (lh1[ip] + lh2[ip]);
214 if (lv1[ip] + lv2[ip] > 0)
215 rvtd[np] = 200. * (z1 - z2) / (lv1[ip] + lv2[ip]);
216 }
217
218 /* Get relative transport deviations... */
219 for (int iq = 0; iq < ctl.nq; iq++)
220 rqtd[iq * NP + np] = 200. * (atm1->q[iq][ip] - atm2->q[iq][ip])
221 / (fabs(atm1->q[iq][ip]) + fabs(atm2->q[iq][ip]));
222
223 /* Save positions of air parcels... */
224 lon1_old[ip] = atm1->lon[ip];
225 lat1_old[ip] = atm1->lat[ip];
226 z1_old[ip] = z1;
227
228 lon2_old[ip] = atm2->lon[ip];
229 lat2_old[ip] = atm2->lat[ip];
230 z2_old[ip] = z2;
231
232 /* Increment air parcel counter... */
233 np++;
234 }
235
236 /* Filter data... */
237 if (zscore > 0 && np > 1) {
238
239 /* Get means and standard deviations of transport deviations... */
240 const size_t n = (size_t) np;
241 const double muh = gsl_stats_mean(ahtd, 1, n);
242 const double muv = gsl_stats_mean(avtd, 1, n);
243 const double sigh = gsl_stats_sd(ahtd, 1, n);
244 const double sigv = gsl_stats_sd(avtd, 1, n);
245
246 /* Filter data... */
247 np = 0;
248 for (size_t i = 0; i < n; i++)
249 if (fabs((ahtd[i] - muh) / sigh) < zscore
250 && fabs((avtd[i] - muv) / sigv) < zscore) {
251 ahtd[np] = ahtd[i];
252 rhtd[np] = rhtd[i];
253 avtd[np] = avtd[i];
254 rvtd[np] = rvtd[i];
255 for (int iq = 0; iq < ctl.nq; iq++) {
256 aqtd[iq * NP + np] = aqtd[iq * NP + (int) i];
257 rqtd[iq * NP + np] = rqtd[iq * NP + (int) i];
258 }
259 np++;
260 }
261 }
262
263 /* Get statistics... */
264 if (strcasecmp(argv[3], "mean") == 0) {
265 ahtdm = gsl_stats_mean(ahtd, 1, (size_t) np);
266 rhtdm = gsl_stats_mean(rhtd, 1, (size_t) np);
267 avtdm = gsl_stats_mean(avtd, 1, (size_t) np);
268 rvtdm = gsl_stats_mean(rvtd, 1, (size_t) np);
269 for (int iq = 0; iq < ctl.nq; iq++) {
270 aqtdm[iq] = gsl_stats_mean(&aqtd[iq * NP], 1, (size_t) np);
271 rqtdm[iq] = gsl_stats_mean(&rqtd[iq * NP], 1, (size_t) np);
272 }
273 } else if (strcasecmp(argv[3], "stddev") == 0) {
274 ahtdm = gsl_stats_sd(ahtd, 1, (size_t) np);
275 rhtdm = gsl_stats_sd(rhtd, 1, (size_t) np);
276 avtdm = gsl_stats_sd(avtd, 1, (size_t) np);
277 rvtdm = gsl_stats_sd(rvtd, 1, (size_t) np);
278 for (int iq = 0; iq < ctl.nq; iq++) {
279 aqtdm[iq] = gsl_stats_sd(&aqtd[iq * NP], 1, (size_t) np);
280 rqtdm[iq] = gsl_stats_sd(&rqtd[iq * NP], 1, (size_t) np);
281 }
282 } else if (strcasecmp(argv[3], "min") == 0) {
283 ahtdm = gsl_stats_min(ahtd, 1, (size_t) np);
284 rhtdm = gsl_stats_min(rhtd, 1, (size_t) np);
285 avtdm = gsl_stats_min(avtd, 1, (size_t) np);
286 rvtdm = gsl_stats_min(rvtd, 1, (size_t) np);
287 for (int iq = 0; iq < ctl.nq; iq++) {
288 aqtdm[iq] = gsl_stats_min(&aqtd[iq * NP], 1, (size_t) np);
289 rqtdm[iq] = gsl_stats_min(&rqtd[iq * NP], 1, (size_t) np);
290 }
291 } else if (strcasecmp(argv[3], "max") == 0) {
292 ahtdm = gsl_stats_max(ahtd, 1, (size_t) np);
293 rhtdm = gsl_stats_max(rhtd, 1, (size_t) np);
294 avtdm = gsl_stats_max(avtd, 1, (size_t) np);
295 rvtdm = gsl_stats_max(rvtd, 1, (size_t) np);
296 for (int iq = 0; iq < ctl.nq; iq++) {
297 aqtdm[iq] = gsl_stats_max(&aqtd[iq * NP], 1, (size_t) np);
298 rqtdm[iq] = gsl_stats_max(&rqtd[iq * NP], 1, (size_t) np);
299 }
300 } else if (strcasecmp(argv[3], "skew") == 0) {
301 ahtdm = gsl_stats_skew(ahtd, 1, (size_t) np);
302 rhtdm = gsl_stats_skew(rhtd, 1, (size_t) np);
303 avtdm = gsl_stats_skew(avtd, 1, (size_t) np);
304 rvtdm = gsl_stats_skew(rvtd, 1, (size_t) np);
305 for (int iq = 0; iq < ctl.nq; iq++) {
306 aqtdm[iq] = gsl_stats_skew(&aqtd[iq * NP], 1, (size_t) np);
307 rqtdm[iq] = gsl_stats_skew(&rqtd[iq * NP], 1, (size_t) np);
308 }
309 } else if (strcasecmp(argv[3], "kurt") == 0) {
310 ahtdm = gsl_stats_kurtosis(ahtd, 1, (size_t) np);
311 rhtdm = gsl_stats_kurtosis(rhtd, 1, (size_t) np);
312 avtdm = gsl_stats_kurtosis(avtd, 1, (size_t) np);
313 rvtdm = gsl_stats_kurtosis(rvtd, 1, (size_t) np);
314 for (int iq = 0; iq < ctl.nq; iq++) {
315 aqtdm[iq] = gsl_stats_kurtosis(&aqtd[iq * NP], 1, (size_t) np);
316 rqtdm[iq] = gsl_stats_kurtosis(&rqtd[iq * NP], 1, (size_t) np);
317 }
318 } else if (strcasecmp(argv[3], "absdev") == 0) {
319 ahtdm = gsl_stats_absdev_m(ahtd, 1, (size_t) np, 0.0);
320 rhtdm = gsl_stats_absdev_m(rhtd, 1, (size_t) np, 0.0);
321 avtdm = gsl_stats_absdev_m(avtd, 1, (size_t) np, 0.0);
322 rvtdm = gsl_stats_absdev_m(rvtd, 1, (size_t) np, 0.0);
323 for (int iq = 0; iq < ctl.nq; iq++) {
324 aqtdm[iq] = gsl_stats_absdev_m(&aqtd[iq * NP], 1, (size_t) np, 0.0);
325 rqtdm[iq] = gsl_stats_absdev_m(&rqtd[iq * NP], 1, (size_t) np, 0.0);
326 }
327 } else if (strcasecmp(argv[3], "median") == 0) {
328 ahtdm = gsl_stats_median(ahtd, 1, (size_t) np);
329 rhtdm = gsl_stats_median(rhtd, 1, (size_t) np);
330 avtdm = gsl_stats_median(avtd, 1, (size_t) np);
331 rvtdm = gsl_stats_median(rvtd, 1, (size_t) np);
332 for (int iq = 0; iq < ctl.nq; iq++) {
333 aqtdm[iq] = gsl_stats_median(&aqtd[iq * NP], 1, (size_t) np);
334 rqtdm[iq] = gsl_stats_median(&rqtd[iq * NP], 1, (size_t) np);
335 }
336 } else if (strcasecmp(argv[3], "mad") == 0) {
337 ahtdm = gsl_stats_mad0(ahtd, 1, (size_t) np, work);
338 rhtdm = gsl_stats_mad0(rhtd, 1, (size_t) np, work);
339 avtdm = gsl_stats_mad0(avtd, 1, (size_t) np, work);
340 rvtdm = gsl_stats_mad0(rvtd, 1, (size_t) np, work);
341 for (int iq = 0; iq < ctl.nq; iq++) {
342 aqtdm[iq] = gsl_stats_mad0(&aqtd[iq * NP], 1, (size_t) np, work);
343 rqtdm[iq] = gsl_stats_mad0(&rqtd[iq * NP], 1, (size_t) np, work);
344 }
345 } else
346 ERRMSG("Unknown parameter!");
347
348 /* Write output... */
349 fprintf(out, "%.2f %.2f %g %g %g %g", t, t - t0,
350 ahtdm, rhtdm, avtdm, rvtdm);
351 for (int iq = 0; iq < ctl.nq; iq++) {
352 fprintf(out, " ");
353 fprintf(out, ctl.qnt_format[iq], aqtdm[iq]);
354 fprintf(out, " ");
355 fprintf(out, ctl.qnt_format[iq], rqtdm[iq]);
356 }
357 fprintf(out, " %d\n", np);
358 }
359
360 /* Close file... */
361 fclose(out);
362
363 /* Free... */
364 free(atm1);
365 free(atm2);
366 free(lon1_old);
367 free(lat1_old);
368 free(z1_old);
369 free(lh1);
370 free(lv1);
371 free(lon2_old);
372 free(lat2_old);
373 free(z2_old);
374 free(lh2);
375 free(lv2);
376 free(ahtd);
377 free(avtd);
378 free(aqtd);
379 free(rhtd);
380 free(rvtd);
381 free(rqtd);
382 free(work);
383
384 return EXIT_SUCCESS;
385}
int main(int argc, char *argv[])
Definition: atm_dist.c:27
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:8846
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:9159
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.
Definition: mptrac.c:4400
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.
Definition: mptrac.c:4531
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:985
MPTRAC library declarations.
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:1904
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:1741
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1304
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:251
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:349
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:246
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:1834
#define DIST(a, b)
Calculate the distance between two points in Cartesian coordinates.
Definition: mptrac.h:578
Air parcel data.
Definition: mptrac.h:3136
double time[NP]
Time [s].
Definition: mptrac.h:3142
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3151
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3148
int np
Number of air parcels.
Definition: mptrac.h:3139
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3154
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3145
Control parameters.
Definition: mptrac.h:2158
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2177
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:2921
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2174
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2168
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2183
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2180
int nq
Number of quantities.
Definition: mptrac.h:2165