MPTRAC
mptrac.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-2024 Forschungszentrum Juelich GmbH
18*/
19
25#include "mptrac.h"
26
27#ifdef KPP
28#include "kpp_chem.h"
29#endif
30
32static gsl_rng *rng[NTHREADS];
33
35static uint64_t rng_ctr;
36
38#ifdef CURAND
39static curandGenerator_t rng_curand;
40#endif
41
42/*****************************************************************************/
43
44#ifdef MPI
46 void *data,
47 size_t N) {
48
49#define CHUNK_SIZE 2147483647
50
51 /* Broadcast the size of the data first... */
52 MPI_Bcast(&N, 1, MPI_UINT64_T, 0, MPI_COMM_WORLD);
53
54 /* Calculate the number of chunks... */
55 size_t num_chunks = (N + CHUNK_SIZE - 1) / CHUNK_SIZE;
56
57 /* Loop over chunks... */
58 for (size_t i = 0; i < num_chunks; i++) {
59
60 /* Determine the start and end indices for the current chunk... */
61 size_t start = i * CHUNK_SIZE;
62 size_t end = (start + CHUNK_SIZE > N) ? N : start + CHUNK_SIZE;
63 size_t chunk_size = end - start;
64
65 /* Broadcast the current chunk... */
66 MPI_Bcast((char *) data + start, (int) chunk_size, MPI_BYTE, 0,
67 MPI_COMM_WORLD);
68 }
69}
70#endif
71
72/*****************************************************************************/
73
75 const double *x,
76 double *z,
77 double *lon,
78 double *lat) {
79
80 double radius = NORM(x);
81 *lat = asin(x[2] / radius) * 180. / M_PI;
82 *lon = atan2(x[1], x[0]) * 180. / M_PI;
83 *z = radius - RE;
84}
85
86/*****************************************************************************/
87
88double clim_oh(
89 const ctl_t * ctl,
90 const clim_t * clim,
91 const double t,
92 const double lon,
93 const double lat,
94 const double p) {
95
96 /* Get OH data from climatology... */
97 double oh = clim_zm(&clim->oh, t, lat, p);
98
99 /* Apply diurnal correction... */
100 if (ctl->oh_chem_beta > 0) {
101 double sza = sza_calc(t, lon, lat);
102 if (sza <= M_PI / 2. * 85. / 90.)
103 return oh * exp(-ctl->oh_chem_beta / cos(sza));
104 else
105 return oh * exp(-ctl->oh_chem_beta / cos(M_PI / 2. * 85. / 90.));
106 } else
107 return oh;
108}
109
110/*****************************************************************************/
111
113 ctl_t * ctl,
114 clim_t * clim) {
115
116 /* Loop over climatology data points... */
117 for (int it = 0; it < clim->oh.ntime; it++)
118 for (int iz = 0; iz < clim->oh.np; iz++)
119 for (int iy = 0; iy < clim->oh.nlat; iy++) {
120
121 /* Init... */
122 int n = 0;
123 double sum = 0;
124
125 /* Integrate day/night correction factor over longitude... */
126 for (double lon = -180; lon < 180; lon += 1.0) {
127 double sza = sza_calc(clim->oh.time[it], lon, clim->oh.lat[iy]);
128 if (sza <= M_PI / 2. * 85. / 90.)
129 sum += exp(-ctl->oh_chem_beta / cos(sza));
130 else
131 sum += exp(-ctl->oh_chem_beta / cos(M_PI / 2. * 85. / 90.));
132 n++;
133 }
134
135 /* Apply scaling factor to OH data... */
136 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
137 }
138}
139
140/*****************************************************************************/
141
143 double rate[CP][CSZA][CO3],
144 clim_photo_t * photo,
145 double p,
146 double sza,
147 double o3c) {
148
149 /* Check pressure range... */
150 double p_help = p;
151 if (p < photo->p[photo->np - 1])
152 p_help = photo->p[photo->np - 1];
153 else if (p > photo->p[0])
154 p_help = photo->p[0];
155
156 /* Check sza range... */
157 double sza_help = sza;
158 if (sza < photo->sza[0])
159 sza_help = photo->sza[0];
160 else if (sza > photo->sza[photo->nsza - 1])
161 sza_help = photo->sza[photo->nsza - 1];
162
163 /* Check ozone column range... */
164 double o3c_help = o3c;
165 if (o3c < photo->o3c[0])
166 o3c_help = photo->o3c[0];
167 else if (o3c > photo->o3c[photo->no3c - 1])
168 o3c_help = photo->o3c[photo->no3c - 1];
169
170 /* Get indices... */
171 int ip = locate_irr(photo->p, photo->np, p_help);
172 int isza = locate_reg(photo->sza, photo->nsza, sza_help);
173 int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
174
175 /* Interpolate photolysis rate... */
176 double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
177 photo->p[ip + 1], rate[ip + 1][isza][io3c], p_help);
178 double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
179 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1], p_help);
180 double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
181 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c], p_help);
182 double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
183 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
184 p_help);
185 aux00 = LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
186 aux11 = LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
187 aux00 = LIN(photo->sza[isza], aux00, photo->sza[isza + 1], aux11, sza_help);
188 return MAX(aux00, 0.0);
189}
190
191/*****************************************************************************/
192
194 const clim_t * clim,
195 const double t,
196 const double lat) {
197
198 /* Get seconds since begin of year... */
199 double sec = FMOD(t, 365.25 * 86400.);
200 while (sec < 0)
201 sec += 365.25 * 86400.;
202
203 /* Get indices... */
204 int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
205 int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
206
207 /* Interpolate tropopause pressure... */
208 double p0 = LIN(clim->tropo_lat[ilat],
209 clim->tropo[isec][ilat],
210 clim->tropo_lat[ilat + 1],
211 clim->tropo[isec][ilat + 1], lat);
212 double p1 = LIN(clim->tropo_lat[ilat],
213 clim->tropo[isec + 1][ilat],
214 clim->tropo_lat[ilat + 1],
215 clim->tropo[isec + 1][ilat + 1], lat);
216 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
217}
218
219/*****************************************************************************/
220
222 clim_t * clim) {
223
224 /* Write info... */
225 LOG(1, "Initialize tropopause data...");
226
227 /* Set time [s]... */
228 clim->tropo_ntime = 12;
229 double tropo_time[12] = {
230 1209600.00, 3888000.00, 6393600.00,
231 9072000.00, 11664000.00, 14342400.00,
232 16934400.00, 19612800.00, 22291200.00,
233 24883200.00, 27561600.00, 30153600.00
234 };
235 memcpy(clim->tropo_time, tropo_time, sizeof(clim->tropo_time));
236
237 /* Set latitudes [deg]... */
238 clim->tropo_nlat = 73;
239 double tropo_lat[73] = {
240 -90, -87.5, -85, -82.5, -80, -77.5, -75, -72.5, -70, -67.5,
241 -65, -62.5, -60, -57.5, -55, -52.5, -50, -47.5, -45, -42.5,
242 -40, -37.5, -35, -32.5, -30, -27.5, -25, -22.5, -20, -17.5,
243 -15, -12.5, -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10, 12.5,
244 15, 17.5, 20, 22.5, 25, 27.5, 30, 32.5, 35, 37.5, 40, 42.5,
245 45, 47.5, 50, 52.5, 55, 57.5, 60, 62.5, 65, 67.5, 70, 72.5,
246 75, 77.5, 80, 82.5, 85, 87.5, 90
247 };
248 memcpy(clim->tropo_lat, tropo_lat, sizeof(clim->tropo_lat));
249
250 /* Set tropopause pressure [hPa] (NCEP/NCAR Reanalysis 1)... */
251 double tropo[12][73] = {
252 {324.1, 325.6, 325, 324.3, 322.5, 319.7, 314, 307.2, 301.8, 299.6,
253 297.1, 292.2, 285.6, 276.1, 264, 248.9, 231.9, 213.5, 194.4,
254 175.3, 157, 140.4, 126.7, 116.3, 109.5, 105.4, 103, 101.4, 100.4,
255 99.69, 99.19, 98.84, 98.56, 98.39, 98.39, 98.42, 98.44, 98.54,
256 98.68, 98.81, 98.89, 98.96, 99.12, 99.65, 101.4, 105.4, 113.5, 128,
257 152.1, 184.7, 214, 234.1, 247.3, 255.8, 262.6, 267.7, 271.7, 275,
258 277.2, 279, 280.1, 280.4, 280.6, 280.1, 279.3, 278.3, 276.8, 275.8,
259 275.3, 275.6, 275.4, 274.1, 273.5},
260 {337.3, 338.7, 337.8, 336.4, 333, 328.8, 321.1, 312.6, 306.6, 303.7,
261 300.2, 293.8, 285.4, 273.8, 259.6, 242.7, 224.4, 205.2, 186, 167.5,
262 150.3, 135, 122.8, 113.9, 108.2, 104.7, 102.5, 101.1, 100.2, 99.42,
263 98.88, 98.52, 98.25, 98.09, 98.07, 98.1, 98.12, 98.2, 98.25, 98.27,
264 98.26, 98.27, 98.36, 98.79, 100.2, 104.2, 113.7, 131.2, 159.5, 193,
265 220.4, 238.1, 250.2, 258.1, 264.7, 269.7, 273.7, 277.3, 280.2, 282.8,
266 284.9, 286.5, 288.1, 288.8, 289, 288.5, 287.2, 286.3, 286.1, 287.2,
267 287.5, 286.2, 285.8},
268 {335, 336, 335.7, 335.1, 332.3, 328.1, 320.6, 311.8, 305.1, 301.9,
269 297.6, 290, 280.4, 268.3, 254.6, 239.6, 223.9, 207.9, 192.2, 176.9,
270 161.7, 146.4, 132.2, 120.6, 112.3, 107.2, 104.3, 102.4, 101.3,
271 100.4, 99.86, 99.47, 99.16, 98.97, 98.94, 98.97, 99, 99.09, 99.2,
272 99.31, 99.35, 99.41, 99.51, 99.86, 101.1, 104.9, 114.3, 131, 156.8,
273 186.3, 209.3, 224.6, 236.8, 246.3, 254.9, 262.3, 268.8, 274.8,
274 279.9, 284.6, 288.6, 291.6, 294.9, 297.5, 299.8, 301.8, 303.1,
275 304.3, 304.9, 306, 306.6, 306.2, 306},
276 {306.2, 306.7, 305.7, 307.1, 307.3, 306.4, 301.8, 296.2, 292.4,
277 290.3, 287.1, 280.9, 273.4, 264.3, 254.1, 242.8, 231, 219, 207.2,
278 195.5, 183.3, 169.7, 154.7, 138.7, 124.1, 113.6, 107.8, 104.7,
279 102.8, 101.7, 100.9, 100.4, 100, 99.79, 99.7, 99.66, 99.68, 99.79,
280 99.94, 100.2, 100.5, 100.9, 101.4, 102.1, 103.4, 107, 115.2, 129.1,
281 148.7, 171, 190.8, 205.6, 218.4, 229.4, 239.6, 248.6, 256.5,
282 263.7, 270.3, 276.6, 282.6, 288.1, 294.5, 300.4, 306.3, 311.4,
283 315.1, 318.3, 320.3, 322.2, 322.8, 321.5, 321.1},
284 {266.5, 264.9, 260.8, 261, 262, 263, 261.3, 259.7, 259.2, 259.8,
285 260.1, 258.6, 256.7, 253.6, 249.5, 243.9, 237.4, 230, 222.1, 213.9,
286 205, 194.4, 180.4, 161.8, 140.7, 122.9, 112.1, 106.7, 104.1, 102.7,
287 101.8, 101.4, 101.1, 101, 101, 101, 101.1, 101.2, 101.5, 101.9,
288 102.4, 103, 103.8, 104.9, 106.8, 110.1, 115.6, 124, 135.2, 148.9,
289 165.2, 181.3, 198, 211.8, 223.5, 233.8, 242.9, 251.5, 259, 266.2,
290 273.1, 279.2, 286.2, 292.8, 299.6, 306, 311.1, 315.5, 318.8, 322.6,
291 325.3, 325.8, 325.8},
292 {220.1, 218.1, 210.8, 207.2, 207.6, 210.5, 211.4, 213.5, 217.3,
293 222.4, 227.9, 232.8, 237.4, 240.8, 242.8, 243, 241.5, 238.6, 234.2,
294 228.5, 221, 210.7, 195.1, 172.9, 147.8, 127.6, 115.6, 109.9, 107.1,
295 105.7, 105, 104.8, 104.8, 104.9, 105, 105.1, 105.3, 105.5, 105.8,
296 106.4, 107, 107.6, 108.1, 108.8, 110, 111.8, 114.2, 117.4, 121.6,
297 127.9, 137.3, 151.2, 169.5, 189, 205.8, 218.9, 229.1, 237.8, 245,
298 251.5, 257.1, 262.3, 268.2, 274, 280.4, 286.7, 292.4, 297.9, 302.9,
299 308.5, 312.2, 313.1, 313.3},
300 {187.4, 184.5, 173.3, 166.1, 165.4, 167.8, 169.6, 173.6, 179.6,
301 187.9, 198.9, 210, 220.5, 229.2, 235.7, 239.9, 241.8, 241.6, 239.6,
302 235.8, 229.4, 218.6, 200.9, 175.9, 149.4, 129.4, 118.3, 113.1,
303 110.8, 109.7, 109.3, 109.4, 109.7, 110, 110.2, 110.4, 110.5, 110.7,
304 111, 111.4, 111.8, 112.1, 112.3, 112.7, 113.2, 113.9, 115, 116.4,
305 117.9, 120.4, 124.1, 130.9, 142.2, 159.6, 179.6, 198.5, 212.9,
306 224.2, 232.7, 239.1, 243.8, 247.7, 252.4, 257.3, 263.2, 269.5,
307 275.4, 281.1, 286.3, 292, 296.3, 298.2, 298.8},
308 {166, 166.4, 155.7, 148.3, 147.1, 149, 152.1, 157, 163.6, 172.4,
309 185.3, 199.2, 212.6, 224, 233.2, 239.6, 243.3, 244.6, 243.6, 240.3,
310 233.9, 222.6, 203.7, 177, 149.5, 129.7, 119, 114, 111.7, 110.7,
311 110.3, 110.3, 110.6, 110.9, 111.1, 111.3, 111.5, 111.6, 111.9,
312 112.2, 112.5, 112.6, 112.8, 113, 113.4, 114, 115.1, 116.5, 118.3,
313 120.9, 124.4, 130.2, 139.4, 154.6, 173.8, 193.1, 208.1, 220.4,
314 230.1, 238.2, 244.7, 249.5, 254.5, 259.3, 264.5, 269.4, 273.7,
315 278.2, 282.6, 287.4, 290.9, 292.5, 293},
316 {171.9, 172.8, 166.2, 162.3, 161.4, 162.5, 165.2, 169.6, 175.3,
317 183.1, 193.8, 205.9, 218.3, 229.6, 238.5, 244.3, 246.9, 246.7,
318 243.8, 238.4, 230.2, 217.9, 199.6, 174.9, 148.9, 129.8, 119.5,
319 114.8, 112.3, 110.9, 110.3, 110.1, 110.2, 110.3, 110.4, 110.5,
320 110.6, 110.8, 111, 111.4, 111.8, 112, 112.2, 112.4, 112.9, 113.6,
321 114.7, 116.3, 118.4, 121.9, 127.1, 136.1, 149.8, 168.4, 186.9,
322 203.3, 217, 229.1, 238.7, 247, 254, 259.3, 264.3, 268.3, 272.5,
323 276.6, 280.4, 284.4, 288.4, 293.3, 297.2, 298.7, 299.1},
324 {191.6, 192.2, 189, 188.1, 190.2, 193.7, 197.8, 202.9, 208.5,
325 215.6, 224.2, 233.1, 241.2, 247.3, 250.8, 251.3, 248.9, 244.2,
326 237.3, 228.4, 217.2, 202.9, 184.5, 162.5, 140.7, 124.8, 116.2,
327 111.8, 109.4, 107.9, 107, 106.7, 106.6, 106.6, 106.7, 106.7,
328 106.8, 107, 107.4, 108, 108.7, 109.3, 109.8, 110.4, 111.2,
329 112.4, 114.2, 116.9, 121.1, 127.9, 139.3, 155.2, 173.6, 190.7,
330 206.1, 220.1, 232.3, 243, 251.8, 259.2, 265.7, 270.6, 275.3,
331 279.3, 283.3, 286.9, 289.7, 292.8, 296.1, 300.5, 303.9, 304.8,
332 305.1},
333 {241.5, 239.6, 236.8, 237.4, 239.4, 242.3, 244.2, 246.4, 249.2,
334 253.6, 258.6, 262.7, 264.8, 264.2, 260.6, 254.1, 245.5, 235.3,
335 223.9, 211.7, 198.3, 183.1, 165.6, 147.1, 130.5, 118.7, 111.9,
336 108.1, 105.8, 104.3, 103.4, 102.8, 102.5, 102.4, 102.5, 102.5,
337 102.5, 102.7, 103.1, 103.8, 104.6, 105.4, 106.1, 107, 108.2,
338 109.9, 112.8, 117.5, 126, 140.4, 161, 181.9, 201.2, 216.8, 230.4,
339 241.8, 251.4, 259.9, 266.9, 272.8, 277.4, 280.4, 282.9, 284.6,
340 286.1, 287.4, 288.3, 289.5, 290.9, 294.2, 296.9, 297.5, 297.6},
341 {301.2, 300.3, 296.6, 295.4, 295, 294.3, 291.2, 287.4, 284.9, 284.7,
342 284.1, 281.5, 277.1, 270.4, 261.7, 250.6, 237.6, 223.1, 207.9, 192,
343 175.8, 158.8, 142.1, 127.6, 116.8, 109.9, 106, 103.6, 102.1, 101.1,
344 100.4, 99.96, 99.6, 99.37, 99.32, 99.32, 99.31, 99.46, 99.77, 100.2,
345 100.7, 101.3, 101.8, 102.7, 104.1, 106.8, 111.9, 121, 136.7, 160,
346 186.9, 209.9, 228.1, 241.2, 251.5, 259.5, 265.7, 270.9, 274.8, 278,
347 280.3, 281.8, 283, 283.3, 283.7, 283.8, 283, 282.2, 281.2, 281.4,
348 281.7, 281.1, 281.2}
349 };
350 memcpy(clim->tropo, tropo, sizeof(clim->tropo));
351
352 /* Get range... */
353 double tropomin = 1e99, tropomax = -1e99;
354 for (int it = 0; it < clim->tropo_ntime; it++)
355 for (int iy = 0; iy < clim->tropo_nlat; iy++) {
356 tropomin = MIN(tropomin, clim->tropo[it][iy]);
357 tropomax = MAX(tropomax, clim->tropo[it][iy]);
358 }
359
360 /* Write info... */
361 LOG(2, "Number of time steps: %d", clim->tropo_ntime);
362 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
363 clim->tropo_time[0], clim->tropo_time[1],
364 clim->tropo_time[clim->tropo_ntime - 1]);
365 LOG(2, "Number of latitudes: %d", clim->tropo_nlat);
366 LOG(2, "Latitudes: %g, %g ... %g deg",
367 clim->tropo_lat[0], clim->tropo_lat[1],
368 clim->tropo_lat[clim->tropo_nlat - 1]);
369 LOG(2, "Tropopause altitude range: %g ... %g hPa", Z(tropomax),
370 Z(tropomin));
371 LOG(2, "Tropopause pressure range: %g ... %g hPa", tropomin, tropomax);
372}
373
374/*****************************************************************************/
375
376double clim_ts(
377 const clim_ts_t * ts,
378 const double t) {
379
380 /* Interpolate... */
381 if (t <= ts->time[0])
382 return ts->vmr[0];
383 else if (t >= ts->time[ts->ntime - 1])
384 return ts->vmr[ts->ntime - 1];
385 else {
386 int idx = locate_irr(ts->time, ts->ntime, t);
387 return LIN(ts->time[idx], ts->vmr[idx],
388 ts->time[idx + 1], ts->vmr[idx + 1], t);
389 }
390}
391
392/*****************************************************************************/
393
394double clim_zm(
395 const clim_zm_t * zm,
396 const double t,
397 const double lat,
398 const double p) {
399
400 /* Get seconds since begin of year... */
401 double sec = FMOD(t, 365.25 * 86400.);
402 while (sec < 0)
403 sec += 365.25 * 86400.;
404
405 /* Check pressure range... */
406 double p_help = p;
407 if (p < zm->p[zm->np - 1])
408 p_help = zm->p[zm->np - 1];
409 else if (p > zm->p[0])
410 p_help = zm->p[0];
411
412 /* Check latitude range... */
413 double lat_help = lat;
414 if (lat < zm->lat[0])
415 lat_help = zm->lat[0];
416 else if (lat > zm->lat[zm->nlat - 1])
417 lat_help = zm->lat[zm->nlat - 1];
418
419 /* Get indices... */
420 int isec = locate_irr(zm->time, zm->ntime, sec);
421 int ilat = locate_reg(zm->lat, zm->nlat, lat_help);
422 int ip = locate_irr(zm->p, zm->np, p_help);
423
424 /* Interpolate climatology data... */
425 double aux00 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat],
426 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat], p_help);
427 double aux01 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat + 1],
428 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat + 1], p_help);
429 double aux10 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat],
430 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat], p_help);
431 double aux11 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat + 1],
432 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat + 1],
433 p_help);
434 aux00 = LIN(zm->lat[ilat], aux00, zm->lat[ilat + 1], aux01, lat_help);
435 aux11 = LIN(zm->lat[ilat], aux10, zm->lat[ilat + 1], aux11, lat_help);
436 aux00 = LIN(zm->time[isec], aux00, zm->time[isec + 1], aux11, sec);
437
438 return MAX(aux00, 0.0);
439}
440
441/*****************************************************************************/
442
443#ifdef CMS
444void compress_cms(
445 ctl_t * ctl,
446 char *varname,
447 float *array,
448 size_t nx,
449 size_t ny,
450 size_t np,
451 int decompress,
452 FILE * inout) {
453
454 /* Set lon-lat grid... */
455 double lon[EX], lat[EY];
456 for (size_t ix = 0; ix < nx; ix++)
457 lon[ix] = 360. * (double) ix / ((double) nx - 1.);
458 for (size_t iy = 0; iy < ny; iy++)
459 lat[iy] = -(180. * (double) iy / ((double) ny - 1.) - 90);
460
461 /* Set multiscale parameters... */
462 const char domain[] = "[0.0, 360.0]x[-90.0, 90.0]";
463 const int Nd0_x = 6;
464 const int Nd0_y = 3;
465 const int max_level_grid = 7;
466 cms_param_t *cms_param
467 = cms_set_parameters(nx, ny, max_level_grid, Nd0_x, Nd0_y, domain);
468
469 /* Read compressed stream and decompress array... */
470 if (decompress) {
471
472 /* Loop over levels... */
473 double cr = 0;
474 for (size_t ip = 0; ip < np; ip++) {
475
476 /* Initialize multiscale module... */
477 cms_module_t *cms_ptr = cms_init(cms_param);
478
479 /* Read binary data... */
480 cms_sol_t *cms_sol = cms_read_sol(cms_ptr, inout);
481
482 /* Evaluate... */
483#pragma omp parallel for default(shared)
484 for (size_t ix = 0; ix < nx; ix++)
485 for (size_t iy = 0; iy < ny; iy++) {
486 double val, x[] = { lon[ix], lat[iy] };
487 cms_eval(cms_ptr, cms_sol, x, &val);
488 array[ARRAY_3D(ix, iy, ny, ip, np)] = (float) val;
489 }
490
491 /* Calculate mean compression ratio... */
492 cr += cms_compression_rate(cms_ptr, cms_sol) / (double) np;
493
494 /* Free... */
495 cms_delete_module(cms_ptr);
496 cms_delete_sol(cms_sol);
497 }
498
499 /* Write info... */
500 LOG(2, "Read 3-D variable: %s (cms, RATIO= %g)", varname, cr);
501 }
502
503 /* Compress array and output compressed stream... */
504 else {
505
506 /* Init... */
507 cms_module_t *cms_ptr[EP];
508 cms_sol_t *cms_sol[EP];
509
510 /* Loop over levels... */
511#pragma omp parallel for default(shared)
512 for (size_t ip = 0; ip < np; ip++) {
513
514 /* Copy level data... */
515 float tmp_arr[nx * ny];
516 for (size_t ix = 0; ix < nx; ++ix)
517 for (size_t iy = 0; iy < ny; ++iy)
518 tmp_arr[ARRAY_2D(ix, iy, ny)] = array[ARRAY_3D(ix, iy, ny, ip, np)];
519
520 /* Initialize multiscale module... */
521 cms_ptr[ip] = cms_init(cms_param);
522
523 /* Create solution pointer... */
524 cms_sol[ip] = cms_read_arr(cms_ptr[ip], tmp_arr, lon, lat, nx, ny);
525
526 /* Set eps threshold value... */
527 if (strcasecmp(varname, "Z") == 0)
528 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_z);
529 else if (strcasecmp(varname, "T") == 0)
530 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_t);
531 else if (strcasecmp(varname, "U") == 0)
532 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_u);
533 else if (strcasecmp(varname, "V") == 0)
534 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_v);
535 else if (strcasecmp(varname, "W") == 0)
536 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_w);
537 else if (strcasecmp(varname, "PV") == 0)
538 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_pv);
539 else if (strcasecmp(varname, "H2O") == 0)
540 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_h2o);
541 else if (strcasecmp(varname, "O3") == 0)
542 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_o3);
543 else if (strcasecmp(varname, "LWC") == 0)
544 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_lwc);
545 else if (strcasecmp(varname, "RWC") == 0)
546 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_rwc);
547 else if (strcasecmp(varname, "IWC") == 0)
548 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_iwc);
549 else if (strcasecmp(varname, "SWC") == 0)
550 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_swc);
551 else if (strcasecmp(varname, "CC") == 0)
552 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_cc);
553 else
554 ERRMSG("Variable name unknown!");
555
556 /* Coarsening... */
557 cms_coarsening(cms_ptr[ip], cms_sol[ip],
558 (unsigned int) ctl->met_cms_heur);
559 }
560
561 /* Loop over levels... */
562 double cr = 0;
563 for (size_t ip = 0; ip < np; ip++) {
564
565 /* Evaluate... */
566 double tmp_cms[nx * ny], tmp_org[nx * ny], tmp_diff[nx * ny];
567#pragma omp parallel for default(shared)
568 for (size_t ix = 0; ix < nx; ix++)
569 for (size_t iy = 0; iy < ny; iy++) {
570 double val, x[] = { lon[ix], lat[iy] };
571 cms_eval(cms_ptr[ip], cms_sol[ip], x, &val);
572 tmp_cms[ARRAY_2D(ix, iy, ny)] = val;
573 tmp_org[ARRAY_2D(ix, iy, ny)] = array[ARRAY_3D(ix, iy, ny, ip, np)];
574 tmp_diff[ARRAY_2D(ix, iy, ny)] =
575 tmp_cms[ARRAY_2D(ix, iy, ny)] - tmp_org[ARRAY_2D(ix, iy, ny)];
576 }
577
578 /* Write info... */
579 LOG(2,
580 "cmultiscale: var= %s / lev= %lu / ratio= %g / rho= %g / mean= %g / sd= %g / min= %g / max= %g",
581 varname, ip, cms_compression_rate(cms_ptr[ip], cms_sol[ip]),
582 gsl_stats_correlation(tmp_cms, 1, tmp_org, 1, nx * ny),
583 gsl_stats_mean(tmp_diff, 1, nx * ny), gsl_stats_sd(tmp_diff, 1,
584 nx * ny),
585 gsl_stats_min(tmp_diff, 1, nx * ny), gsl_stats_max(tmp_diff, 1,
586 nx * ny)
587 );
588
589 /* Calculate mean compression ratio... */
590 cr += cms_compression_rate(cms_ptr[ip], cms_sol[ip]) / (double) np;
591
592 /* Save binary data... */
593 cms_save_sol(cms_sol[ip], cms_ptr[ip], inout);
594
595 /* Free... */
596 cms_delete_module(cms_ptr[ip]);
597 cms_delete_sol(cms_sol[ip]);
598 }
599
600 /* Write info... */
601 LOG(2, "Write 3-D variable: %s (cms, RATIO= %g)", varname, cr);
602 }
603
604 /* Free... */
605 cms_delete_param(cms_param);
606}
607#endif
608
609/*****************************************************************************/
610
612 char *varname,
613 float *array,
614 size_t nxy,
615 size_t nz,
616 int decompress,
617 FILE * inout) {
618
619 double min[EP], max[EP], off[EP], scl[EP];
620
621 unsigned short *sarray;
622
623 /* Allocate... */
624 ALLOC(sarray, unsigned short,
625 nxy * nz);
626
627 /* Read compressed stream and decompress array... */
628 if (decompress) {
629
630 /* Write info... */
631 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
632 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
633
634 /* Read data... */
635 FREAD(&scl, double,
636 nz,
637 inout);
638 FREAD(&off, double,
639 nz,
640 inout);
641 FREAD(sarray, unsigned short,
642 nxy * nz,
643 inout);
644
645 /* Convert to float... */
646#pragma omp parallel for default(shared)
647 for (size_t ixy = 0; ixy < nxy; ixy++)
648 for (size_t iz = 0; iz < nz; iz++)
649 array[ixy * nz + iz]
650 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
651 }
652
653 /* Compress array and output compressed stream... */
654 else {
655
656 /* Write info... */
657 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
658 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
659
660 /* Get range... */
661 for (size_t iz = 0; iz < nz; iz++) {
662 min[iz] = array[iz];
663 max[iz] = array[iz];
664 }
665 for (size_t ixy = 1; ixy < nxy; ixy++)
666 for (size_t iz = 0; iz < nz; iz++) {
667 if (array[ixy * nz + iz] < min[iz])
668 min[iz] = array[ixy * nz + iz];
669 if (array[ixy * nz + iz] > max[iz])
670 max[iz] = array[ixy * nz + iz];
671 }
672
673 /* Get offset and scaling factor... */
674 for (size_t iz = 0; iz < nz; iz++) {
675 scl[iz] = (max[iz] - min[iz]) / 65533.;
676 off[iz] = min[iz];
677 }
678
679 /* Convert to short... */
680#pragma omp parallel for default(shared)
681 for (size_t ixy = 0; ixy < nxy; ixy++)
682 for (size_t iz = 0; iz < nz; iz++)
683 if (scl[iz] != 0)
684 sarray[ixy * nz + iz] = (unsigned short)
685 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
686 else
687 sarray[ixy * nz + iz] = 0;
688
689 /* Write data... */
690 FWRITE(&scl, double,
691 nz,
692 inout);
693 FWRITE(&off, double,
694 nz,
695 inout);
696 FWRITE(sarray, unsigned short,
697 nxy * nz,
698 inout);
699 }
700
701 /* Free... */
702 free(sarray);
703}
704
705/*****************************************************************************/
706
707#ifdef ZFP
708void compress_zfp(
709 char *varname,
710 float *array,
711 int nx,
712 int ny,
713 int nz,
714 int precision,
715 double tolerance,
716 int decompress,
717 FILE * inout) {
718
719 zfp_type type; /* array scalar type */
720 zfp_field *field; /* array meta data */
721 zfp_stream *zfp; /* compressed stream */
722 void *buffer; /* storage for compressed stream */
723 size_t bufsize; /* byte size of compressed buffer */
724 bitstream *stream; /* bit stream to write to or read from */
725 size_t zfpsize; /* byte size of compressed stream */
726
727 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
728 type = zfp_type_float;
729 field = zfp_field_3d(array, type, (uint) nx, (uint) ny, (uint) nz);
730
731 /* Allocate meta data for a compressed stream... */
732 zfp = zfp_stream_open(NULL);
733
734 /* Set compression mode... */
735 int actual_prec = 0;
736 double actual_tol = 0;
737 if (precision > 0)
738 actual_prec = (int) zfp_stream_set_precision(zfp, (uint) precision);
739 else if (tolerance > 0)
740 actual_tol = zfp_stream_set_accuracy(zfp, tolerance);
741 else
742 ERRMSG("Set precision or tolerance!");
743
744 /* Allocate buffer for compressed data... */
745 bufsize = zfp_stream_maximum_size(zfp, field);
746 buffer = malloc(bufsize);
747
748 /* Associate bit stream with allocated buffer... */
749 stream = stream_open(buffer, bufsize);
750 zfp_stream_set_bit_stream(zfp, stream);
751 zfp_stream_rewind(zfp);
752
753 /* Read compressed stream and decompress array... */
754 if (decompress) {
755 FREAD(&zfpsize, size_t,
756 1,
757 inout);
758 if (fread(buffer, 1, zfpsize, inout) != zfpsize)
759 ERRMSG("Error while reading zfp data!");
760 if (!zfp_decompress(zfp, field)) {
761 ERRMSG("Decompression failed!");
762 }
763 LOG(2, "Read 3-D variable: %s "
764 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
765 varname, actual_prec, actual_tol,
766 ((double) (nx * ny * nz)) / (double) zfpsize);
767 }
768
769 /* Compress array and output compressed stream... */
770 else {
771 zfpsize = zfp_compress(zfp, field);
772 if (!zfpsize) {
773 ERRMSG("Compression failed!");
774 } else {
775 FWRITE(&zfpsize, size_t,
776 1,
777 inout);
778 if (fwrite(buffer, 1, zfpsize, inout) != zfpsize)
779 ERRMSG("Error while writing zfp data!");
780 }
781 LOG(2, "Write 3-D variable: %s "
782 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
783 varname, actual_prec, actual_tol,
784 ((double) (nx * ny * nz)) / (double) zfpsize);
785 }
786
787 /* Free... */
788 zfp_field_free(field);
789 zfp_stream_close(zfp);
790 stream_close(stream);
791 free(buffer);
792}
793#endif
794
795/*****************************************************************************/
796
797#ifdef ZSTD
798void compress_zstd(
799 char *varname,
800 float *array,
801 size_t n,
802 int decompress,
803 FILE * inout) {
804
805 /* Get buffer sizes... */
806 size_t uncomprLen = n * sizeof(float);
807 size_t comprLen = ZSTD_compressBound(uncomprLen);
808 size_t compsize;
809
810 /* Allocate... */
811 char *compr = (char *) calloc((uint) comprLen, 1);
812 char *uncompr = (char *) array;
813
814 /* Read compressed stream and decompress array... */
815 if (decompress) {
816 FREAD(&comprLen, size_t,
817 1,
818 inout);
819 if (fread(compr, 1, comprLen, inout) != comprLen)
820 ERRMSG("Error while reading zstd data!");
821 compsize = ZSTD_decompress(uncompr, uncomprLen, compr, comprLen);
822 if (ZSTD_isError(compsize)) {
823 ERRMSG("Decompression failed!");
824 }
825 LOG(2, "Read 3-D variable: %s (zstd, RATIO= %g)",
826 varname, ((double) uncomprLen) / (double) comprLen);
827 }
828
829 /* Compress array and output compressed stream... */
830 else {
831 compsize = ZSTD_compress(compr, comprLen, uncompr, uncomprLen, 0);
832 if (ZSTD_isError(compsize)) {
833 ERRMSG("Compression failed!");
834 } else {
835 FWRITE(&compsize, size_t,
836 1,
837 inout);
838 if (fwrite(compr, 1, compsize, inout) != compsize)
839 ERRMSG("Error while writing zstd data!");
840 }
841 LOG(2, "Write 3-D variable: %s (zstd, RATIO= %g)",
842 varname, ((double) uncomprLen) / (double) compsize);
843 }
844
845 /* Free... */
846 free(compr);
847}
848#endif
849
850/*****************************************************************************/
851
853 const int year,
854 const int mon,
855 const int day,
856 int *doy) {
857
858 const int
859 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
860 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
861
862 /* Get day of year... */
863 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
864 *doy = d0l[mon - 1] + day - 1;
865 else
866 *doy = d0[mon - 1] + day - 1;
867}
868
869/*****************************************************************************/
870
872 const int year,
873 const int doy,
874 int *mon,
875 int *day) {
876
877 const int
878 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
879 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
880
881 int i;
882
883 /* Get month and day... */
884 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
885 for (i = 11; i > 0; i--)
886 if (d0l[i] <= doy)
887 break;
888 *mon = i + 1;
889 *day = doy - d0l[i] + 1;
890 } else {
891 for (i = 11; i > 0; i--)
892 if (d0[i] <= doy)
893 break;
894 *mon = i + 1;
895 *day = doy - d0[i] + 1;
896 }
897}
898
899/*****************************************************************************/
900
902 double *fcReal,
903 double *fcImag,
904 int n) {
905
906 gsl_fft_complex_wavetable *wavetable;
907 gsl_fft_complex_workspace *workspace;
908
909 double data[2 * EX];
910
911 /* Check size... */
912 if (n > EX)
913 ERRMSG("Too many data points!");
914
915 /* Allocate... */
916 wavetable = gsl_fft_complex_wavetable_alloc((size_t) n);
917 workspace = gsl_fft_complex_workspace_alloc((size_t) n);
918
919 /* Set data (real, complex)... */
920 for (int i = 0; i < n; i++) {
921 data[2 * i] = fcReal[i];
922 data[2 * i + 1] = fcImag[i];
923 }
924
925 /* Calculate FFT... */
926 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
927
928 /* Copy data... */
929 for (int i = 0; i < n; i++) {
930 fcReal[i] = data[2 * i];
931 fcImag[i] = data[2 * i + 1];
932 }
933
934 /* Free... */
935 gsl_fft_complex_wavetable_free(wavetable);
936 gsl_fft_complex_workspace_free(workspace);
937}
938
939/*****************************************************************************/
940
942 const double z,
943 const double lon,
944 const double lat,
945 double *x) {
946
947 double radius = z + RE;
948 x[0] = radius * cos(lat / 180. * M_PI) * cos(lon / 180. * M_PI);
949 x[1] = radius * cos(lat / 180. * M_PI) * sin(lon / 180. * M_PI);
950 x[2] = radius * sin(lat / 180. * M_PI);
951}
952
953/*****************************************************************************/
954
956 ctl_t * ctl,
957 clim_t * clim,
958 double t,
959 met_t ** met0,
960 met_t ** met1) {
961
962 static int init;
963
964 met_t *mets;
965
966 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
967
968 /* Set timer... */
969 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
970
971 /* Init... */
972 if (t == ctl->t_start || !init) {
973 init = 1;
974
975 /* Read meteo data... */
976 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
977 ctl->metbase, ctl->dt_met, filename);
978 if (!read_met(filename, ctl, clim, *met0))
979 ERRMSG("Cannot open file!");
980
981 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
982 ctl->metbase, ctl->dt_met, filename);
983 if (!read_met(filename, ctl, clim, *met1))
984 ERRMSG("Cannot open file!");
985
986 /* Update GPU... */
987#ifdef _OPENACC
988 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
989 met_t *met0up = *met0;
990 met_t *met1up = *met1;
991#ifdef ASYNCIO
992#pragma acc update device(met0up[:1],met1up[:1]) async(5)
993#else
994#pragma acc update device(met0up[:1],met1up[:1])
995#endif
996 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
997#endif
998
999 /* Caching... */
1000 if (ctl->met_cache && t != ctl->t_stop) {
1001 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
1002 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
1003 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1004 LOG(1, "Caching: %s", cachefile);
1005 if (system(cmd) != 0)
1006 WARN("Caching command failed!");
1007 }
1008 }
1009
1010 /* Read new data for forward trajectories... */
1011 if (t > (*met1)->time) {
1012
1013 /* Pointer swap... */
1014 mets = *met1;
1015 *met1 = *met0;
1016 *met0 = mets;
1017
1018 /* Read new meteo data... */
1019 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
1020 if (!read_met(filename, ctl, clim, *met1))
1021 ERRMSG("Cannot open file!");
1022
1023 /* Update GPU... */
1024#ifdef _OPENACC
1025 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
1026 met_t *met1up = *met1;
1027#ifdef ASYNCIO
1028#pragma acc update device(met1up[:1]) async(5)
1029#else
1030#pragma acc update device(met1up[:1])
1031#endif
1032 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1033#endif
1034
1035 /* Caching... */
1036 if (ctl->met_cache && t != ctl->t_stop) {
1037 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
1038 cachefile);
1039 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1040 LOG(1, "Caching: %s", cachefile);
1041 if (system(cmd) != 0)
1042 WARN("Caching command failed!");
1043 }
1044 }
1045
1046 /* Read new data for backward trajectories... */
1047 if (t < (*met0)->time) {
1048
1049 /* Pointer swap... */
1050 mets = *met1;
1051 *met1 = *met0;
1052 *met0 = mets;
1053
1054 /* Read new meteo data... */
1055 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
1056 if (!read_met(filename, ctl, clim, *met0))
1057 ERRMSG("Cannot open file!");
1058
1059 /* Update GPU... */
1060#ifdef _OPENACC
1061 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
1062 met_t *met0up = *met0;
1063#ifdef ASYNCIO
1064#pragma acc update device(met0up[:1]) async(5)
1065#else
1066#pragma acc update device(met0up[:1])
1067#endif
1068 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1069#endif
1070
1071 /* Caching... */
1072 if (ctl->met_cache && t != ctl->t_stop) {
1073 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
1074 cachefile);
1075 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1076 LOG(1, "Caching: %s", cachefile);
1077 if (system(cmd) != 0)
1078 WARN("Caching command failed!");
1079 }
1080 }
1081
1082 /* Check that grids are consistent... */
1083 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
1084 if ((*met0)->nx != (*met1)->nx
1085 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
1086 ERRMSG("Meteo grid dimensions do not match!");
1087 for (int ix = 0; ix < (*met0)->nx; ix++)
1088 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
1089 ERRMSG("Meteo grid longitudes do not match!");
1090 for (int iy = 0; iy < (*met0)->ny; iy++)
1091 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
1092 ERRMSG("Meteo grid latitudes do not match!");
1093 for (int ip = 0; ip < (*met0)->np; ip++)
1094 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
1095 ERRMSG("Meteo grid pressure levels do not match!");
1096 }
1097}
1098
1099/*****************************************************************************/
1100
1102 ctl_t * ctl,
1103 double t,
1104 int direct,
1105 char *metbase,
1106 double dt_met,
1107 char *filename) {
1108
1109 char repl[LEN];
1110
1111 double t6, r;
1112
1113 int year, mon, day, hour, min, sec;
1114
1115 /* Round time to fixed intervals... */
1116 if (direct == -1)
1117 t6 = floor(t / dt_met) * dt_met;
1118 else
1119 t6 = ceil(t / dt_met) * dt_met;
1120
1121 /* Decode time... */
1122 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1123
1124 /* Set filename of MPTRAC meteo files... */
1125 if (ctl->met_clams == 0) {
1126 if (ctl->met_type == 0)
1127 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1128 else if (ctl->met_type == 1)
1129 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1130 else if (ctl->met_type == 2)
1131 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1132 else if (ctl->met_type == 3)
1133 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1134 else if (ctl->met_type == 4)
1135 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1136 else if (ctl->met_type == 5)
1137 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1138 sprintf(repl, "%d", year);
1139 get_met_replace(filename, "YYYY", repl);
1140 sprintf(repl, "%02d", mon);
1141 get_met_replace(filename, "MM", repl);
1142 sprintf(repl, "%02d", day);
1143 get_met_replace(filename, "DD", repl);
1144 sprintf(repl, "%02d", hour);
1145 get_met_replace(filename, "HH", repl);
1146 }
1147
1148 /* Set filename of CLaMS meteo files... */
1149 else {
1150 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1151 sprintf(repl, "%d", year);
1152 get_met_replace(filename, "YYYY", repl);
1153 sprintf(repl, "%02d", year % 100);
1154 get_met_replace(filename, "YY", repl);
1155 sprintf(repl, "%02d", mon);
1156 get_met_replace(filename, "MM", repl);
1157 sprintf(repl, "%02d", day);
1158 get_met_replace(filename, "DD", repl);
1159 sprintf(repl, "%02d", hour);
1160 get_met_replace(filename, "HH", repl);
1161 }
1162}
1163
1164/*****************************************************************************/
1165
1167 char *orig,
1168 char *search,
1169 char *repl) {
1170
1171 char buffer[LEN];
1172
1173 /* Iterate... */
1174 for (int i = 0; i < 3; i++) {
1175
1176 /* Replace sub-string... */
1177 char *ch;
1178 if (!(ch = strstr(orig, search)))
1179 return;
1180 strncpy(buffer, orig, (size_t) (ch - orig));
1181 buffer[ch - orig] = 0;
1182 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1183 orig[0] = 0;
1184 strcpy(orig, buffer);
1185 }
1186}
1187
1188/*****************************************************************************/
1189
1191 int met_tropo,
1192 ctl_t * ctl,
1193 clim_t * clim,
1194 met_t * met,
1195 double *lons,
1196 int nx,
1197 double *lats,
1198 int ny,
1199 double *pt,
1200 double *zt,
1201 double *tt,
1202 double *qt,
1203 double *o3t,
1204 double *ps,
1205 double *zs) {
1206
1208
1209 ctl->met_tropo = met_tropo;
1210 read_met_tropo(ctl, clim, met);
1211#pragma omp parallel for default(shared) private(ci,cw)
1212 for (int ix = 0; ix < nx; ix++)
1213 for (int iy = 0; iy < ny; iy++) {
1214 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1215 &pt[iy * nx + ix], ci, cw, 1);
1216 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1217 &ps[iy * nx + ix], ci, cw, 0);
1218 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1219 &zs[iy * nx + ix], ci, cw, 0);
1220 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1221 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1222 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1223 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1224 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1225 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1226 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1227 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1228 }
1229}
1230
1231/*****************************************************************************/
1232
1234 met_t * met0,
1235 float heights0[EX][EY][EP],
1236 float array0[EX][EY][EP],
1237 met_t * met1,
1238 float heights1[EX][EY][EP],
1239 float array1[EX][EY][EP],
1240 double ts,
1241 double height,
1242 double lon,
1243 double lat,
1244 double *var,
1245 int *ci,
1246 double *cw,
1247 int init) {
1248
1249 if (init) {
1250
1251 /* Restrict positions to coordinate range... */
1252 lon = FMOD(lon, 360.);
1253 if (met0->lon[met0->nx - 1] > 180 && lon < 0)
1254 lon += 360;
1255
1256 /* Get horizontal indizes... */
1257 ci[0] = locate_irr(met0->lon, met0->nx, lon);
1258 ci[1] = locate_irr(met0->lat, met0->ny, lat);
1259
1260 /* Locate the vertical indizes for each edge of the column... */
1261 int ind[2][4];
1262 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1263 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1264
1265 /* Find minimum and maximum indizes... */
1266 ci[2] = ind[0][0];
1267 int k_max = ind[0][0];
1268 for (int i = 0; i < 2; i++)
1269 for (int j = 0; j < 4; j++) {
1270 if (ci[2] > ind[i][j])
1271 ci[2] = ind[i][j];
1272 if (k_max < ind[i][j])
1273 k_max = ind[i][j];
1274 }
1275
1276 /* Get weighting factors for time, longitude and latitude... */
1277 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1278 cw[0] = (lon - met0->lon[ci[0]]) /
1279 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1280 cw[1] = (lat - met0->lat[ci[1]]) /
1281 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1282
1283 /* Start determiniation of the altitude weighting factor... */
1284 double height_top, height_bot;
1285 double height00, height01, height10, height11, height0, height1;
1286
1287 /* Interpolate in time at the lowest level... */
1288 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1289 - heights0[ci[0]][ci[1]][ci[2]])
1290 + heights0[ci[0]][ci[1]][ci[2]];
1291 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1292 - heights0[ci[0]][ci[1] + 1][ci[2]])
1293 + heights0[ci[0]][ci[1] + 1][ci[2]];
1294 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1295 - heights0[ci[0] + 1][ci[1]][ci[2]])
1296 + heights0[ci[0] + 1][ci[1]][ci[2]];
1297 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1298 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1299 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1300
1301 /* Interpolate in latitude direction... */
1302 height0 = cw[1] * (height01 - height00) + height00;
1303 height1 = cw[1] * (height11 - height10) + height10;
1304
1305 /* Interpolate in longitude direction... */
1306 height_bot = cw[0] * (height1 - height0) + height0;
1307
1308 /* Interpolate in time at the upper level... */
1309 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1310 - heights0[ci[0]][ci[1]][ci[2] + 1])
1311 + heights0[ci[0]][ci[1]][ci[2] + 1];
1312 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1313 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1314 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1315 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1316 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1317 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1318 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1319 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1320 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1321
1322 /* Interpolate in latitude direction... */
1323 height0 = cw[1] * (height01 - height00) + height00;
1324 height1 = cw[1] * (height11 - height10) + height10;
1325
1326 /* Interpolate in longitude direction... */
1327 height_top = cw[0] * (height1 - height0) + height0;
1328
1329 /* Search at higher levels if height is not in box... */
1330 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1331 ((height_bot <= height) || (height_top > height))
1332 && (height_bot >= height) && (ci[2] < k_max))
1333 ||
1334 ((heights0[0][0][0] < heights0[0][0][1]) &&
1335 ((height_bot >= height) || (height_top < height))
1336 && (height_bot <= height) && (ci[2] < k_max))
1337 ) {
1338
1339 ci[2]++;
1340 height_bot = height_top;
1341
1342 /* Interpolate in time at the next level... */
1343 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1344 - heights0[ci[0]][ci[1]][ci[2] + 1])
1345 + heights0[ci[0]][ci[1]][ci[2] + 1];
1346 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1347 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1348 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1349 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1350 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1351 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1352 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1353 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1354 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1355
1356 /* Interpolate in latitude direction... */
1357 height0 = cw[1] * (height01 - height00) + height00;
1358 height1 = cw[1] * (height11 - height10) + height10;
1359
1360 /* Interpolate in longitude direction... */
1361 height_top = cw[0] * (height1 - height0) + height0;
1362 }
1363
1364 /* Get vertical weighting factors... */
1365 cw[2] = (height - height_bot)
1366 / (height_top - height_bot);
1367 }
1368
1369 /* Calculate the needed array values... */
1370 double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1371 - array0[ci[0]][ci[1]][ci[2]])
1372 + array0[ci[0]][ci[1]][ci[2]];
1373 double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1374 - array0[ci[0] + 1][ci[1]][ci[2]])
1375 + array0[ci[0] + 1][ci[1]][ci[2]];
1376 double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1377 - array0[ci[0]][ci[1] + 1][ci[2]])
1378 + array0[ci[0]][ci[1] + 1][ci[2]];
1379 double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1380 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1381 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1382 double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1383 - array0[ci[0]][ci[1]][ci[2] + 1])
1384 + array0[ci[0]][ci[1]][ci[2] + 1];
1385 double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
1386 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
1387 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
1388 double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
1389 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
1390 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
1391 double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1392 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1393 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1394
1395 double array00 = cw[0] * (array100 - array000) + array000;
1396 double array10 = cw[0] * (array110 - array010) + array010;
1397 double array01 = cw[0] * (array101 - array001) + array001;
1398 double array11 = cw[0] * (array111 - array011) + array011;
1399
1400 double aux0 = cw[1] * (array10 - array00) + array00;
1401 double aux1 = cw[1] * (array11 - array01) + array01;
1402
1403 /* Interpolate vertically... */
1404 *var = cw[2] * (aux1 - aux0) + aux0;
1405}
1406
1407/*****************************************************************************/
1408
1410 met_t * met,
1411 float array[EX][EY][EP],
1412 double p,
1413 double lon,
1414 double lat,
1415 double *var,
1416 int *ci,
1417 double *cw,
1418 int init) {
1419
1420 /* Initialize interpolation... */
1421 if (init) {
1422
1423 /* Check longitude... */
1424 if (met->lon[met->nx - 1] > 180 && lon < 0)
1425 lon += 360;
1426
1427 /* Get interpolation indices... */
1428 ci[0] = locate_irr(met->p, met->np, p);
1429 ci[1] = locate_reg(met->lon, met->nx, lon);
1430 ci[2] = locate_reg(met->lat, met->ny, lat);
1431
1432 /* Get interpolation weights... */
1433 cw[0] = (met->p[ci[0] + 1] - p)
1434 / (met->p[ci[0] + 1] - met->p[ci[0]]);
1435 cw[1] = (met->lon[ci[1] + 1] - lon)
1436 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1437 cw[2] = (met->lat[ci[2] + 1] - lat)
1438 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1439 }
1440
1441 /* Interpolate vertically... */
1442 double aux00 =
1443 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
1444 + array[ci[1]][ci[2]][ci[0] + 1];
1445 double aux01 =
1446 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
1447 array[ci[1]][ci[2] + 1][ci[0] + 1])
1448 + array[ci[1]][ci[2] + 1][ci[0] + 1];
1449 double aux10 =
1450 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
1451 array[ci[1] + 1][ci[2]][ci[0] + 1])
1452 + array[ci[1] + 1][ci[2]][ci[0] + 1];
1453 double aux11 =
1454 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
1455 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
1456 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
1457
1458 /* Interpolate horizontally... */
1459 aux00 = cw[2] * (aux00 - aux01) + aux01;
1460 aux11 = cw[2] * (aux10 - aux11) + aux11;
1461 *var = cw[1] * (aux00 - aux11) + aux11;
1462}
1463
1464/*****************************************************************************/
1465
1467 met_t * met,
1468 float array[EX][EY][EP],
1469 double p,
1470 double lon,
1471 double lat,
1472 double *var) {
1473
1474 /* Check longitude... */
1475 if (met->lon[met->nx - 1] > 180 && lon < 0)
1476 lon += 360;
1477
1478 /* Get horizontal indices... */
1479 int ix = locate_reg(met->lon, met->nx, lon);
1480 int iy = locate_reg(met->lat, met->ny, lat);
1481
1482 /* Interpolate vertically... */
1483 int iz = locate_irr_float(met->pl[ix][iy], met->npl, p, 0);
1484 double aux00;
1485 if (p >= met->pl[ix][iy][iz + 1])
1486 aux00 = array[ix][iy][iz + 1];
1487 else if (p <= met->pl[ix][iy][iz])
1488 aux00 = array[ix][iy][iz];
1489 else
1490 aux00 = LIN(met->pl[ix][iy][iz],
1491 array[ix][iy][iz],
1492 met->pl[ix][iy][iz + 1], array[ix][iy][iz + 1], p);
1493
1494 iz = locate_irr_float(met->pl[ix][iy + 1], met->npl, p, iz);
1495 double aux01;
1496 if (p >= met->pl[ix][iy + 1][iz + 1])
1497 aux01 = array[ix][iy + 1][iz + 1];
1498 else if (p <= met->pl[ix][iy + 1][iz])
1499 aux01 = array[ix][iy + 1][iz];
1500 else
1501 aux01 = LIN(met->pl[ix][iy + 1][iz],
1502 array[ix][iy + 1][iz],
1503 met->pl[ix][iy + 1][iz + 1], array[ix][iy + 1][iz + 1], p);
1504
1505 iz = locate_irr_float(met->pl[ix + 1][iy], met->npl, p, iz);
1506 double aux10;
1507 if (p >= met->pl[ix + 1][iy][iz + 1])
1508 aux10 = array[ix + 1][iy][iz + 1];
1509 else if (p <= met->pl[ix + 1][iy][iz])
1510 aux10 = array[ix + 1][iy][iz];
1511 else
1512 aux10 = LIN(met->pl[ix + 1][iy][iz],
1513 array[ix + 1][iy][iz],
1514 met->pl[ix + 1][iy][iz + 1], array[ix + 1][iy][iz + 1], p);
1515
1516 iz = locate_irr_float(met->pl[ix + 1][iy + 1], met->npl, p, iz);
1517 double aux11;
1518 if (p >= met->pl[ix + 1][iy + 1][iz + 1])
1519 aux11 = array[ix + 1][iy + 1][iz + 1];
1520 else if (p <= met->pl[ix + 1][iy + 1][iz])
1521 aux11 = array[ix + 1][iy + 1][iz];
1522 else
1523 aux11 = LIN(met->pl[ix + 1][iy + 1][iz],
1524 array[ix + 1][iy + 1][iz],
1525 met->pl[ix + 1][iy + 1][iz + 1],
1526 array[ix + 1][iy + 1][iz + 1], p);
1527
1528 /* Interpolate horizontally... */
1529 double aux0 = LIN(met->lat[iy], aux00, met->lat[iy + 1], aux01, lat);
1530 double aux1 = LIN(met->lat[iy], aux10, met->lat[iy + 1], aux11, lat);
1531 *var = LIN(met->lon[ix], aux0, met->lon[ix + 1], aux1, lon);
1532}
1533
1534/*****************************************************************************/
1535
1537 met_t * met,
1538 float array[EX][EY],
1539 double lon,
1540 double lat,
1541 double *var,
1542 int *ci,
1543 double *cw,
1544 int init) {
1545
1546 /* Initialize interpolation... */
1547 if (init) {
1548
1549 /* Check longitude... */
1550 if (met->lon[met->nx - 1] > 180 && lon < 0)
1551 lon += 360;
1552
1553 /* Get interpolation indices... */
1554 ci[1] = locate_reg(met->lon, met->nx, lon);
1555 ci[2] = locate_reg(met->lat, met->ny, lat);
1556
1557 /* Get interpolation weights... */
1558 cw[1] = (met->lon[ci[1] + 1] - lon)
1559 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1560 cw[2] = (met->lat[ci[2] + 1] - lat)
1561 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1562 }
1563
1564 /* Set variables... */
1565 double aux00 = array[ci[1]][ci[2]];
1566 double aux01 = array[ci[1]][ci[2] + 1];
1567 double aux10 = array[ci[1] + 1][ci[2]];
1568 double aux11 = array[ci[1] + 1][ci[2] + 1];
1569
1570 /* Interpolate horizontally... */
1571 if (isfinite(aux00) && isfinite(aux01)
1572 && isfinite(aux10) && isfinite(aux11)) {
1573 aux00 = cw[2] * (aux00 - aux01) + aux01;
1574 aux11 = cw[2] * (aux10 - aux11) + aux11;
1575 *var = cw[1] * (aux00 - aux11) + aux11;
1576 } else {
1577 if (cw[2] < 0.5) {
1578 if (cw[1] < 0.5)
1579 *var = aux11;
1580 else
1581 *var = aux01;
1582 } else {
1583 if (cw[1] < 0.5)
1584 *var = aux10;
1585 else
1586 *var = aux00;
1587 }
1588 }
1589}
1590
1591/*****************************************************************************/
1592
1594 met_t * met0,
1595 float array0[EX][EY][EP],
1596 met_t * met1,
1597 float array1[EX][EY][EP],
1598 double ts,
1599 double p,
1600 double lon,
1601 double lat,
1602 double *var,
1603 int *ci,
1604 double *cw,
1605 int init) {
1606
1607 double var0, var1, wt;
1608
1609 /* Spatial interpolation... */
1610 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
1611 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
1612
1613 /* Get weighting factor... */
1614 wt = (met1->time - ts) / (met1->time - met0->time);
1615
1616 /* Interpolate... */
1617 *var = wt * (var0 - var1) + var1;
1618}
1619
1620/*****************************************************************************/
1621
1623 met_t * met0,
1624 float array0[EX][EY][EP],
1625 met_t * met1,
1626 float array1[EX][EY][EP],
1627 double ts,
1628 double p,
1629 double lon,
1630 double lat,
1631 double *var) {
1632
1633 double var0, var1;
1634
1635 /* Spatial interpolation... */
1636 intpol_met_space_3d_ml(met0, array0, p, lon, lat, &var0);
1637 intpol_met_space_3d_ml(met1, array1, p, lon, lat, &var1);
1638
1639 /* Interpolate... */
1640 *var = LIN(met0->time, var0, met1->time, var1, ts);
1641}
1642
1643/*****************************************************************************/
1644
1646 met_t * met0,
1647 float array0[EX][EY],
1648 met_t * met1,
1649 float array1[EX][EY],
1650 double ts,
1651 double lon,
1652 double lat,
1653 double *var,
1654 int *ci,
1655 double *cw,
1656 int init) {
1657
1658 double var0, var1, wt;
1659
1660 /* Spatial interpolation... */
1661 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
1662 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
1663
1664 /* Get weighting factor... */
1665 wt = (met1->time - ts) / (met1->time - met0->time);
1666
1667 /* Interpolate... */
1668 if (isfinite(var0) && isfinite(var1))
1669 *var = wt * (var0 - var1) + var1;
1670 else if (wt < 0.5)
1671 *var = var1;
1672 else
1673 *var = var0;
1674}
1675
1676/*****************************************************************************/
1677
1679 double time0,
1680 float array0[EX][EY],
1681 double time1,
1682 float array1[EX][EY],
1683 double lons[EX],
1684 double lats[EY],
1685 int nlon,
1686 int nlat,
1687 double time,
1688 double lon,
1689 double lat,
1690 int method,
1691 double *var,
1692 double *sigma) {
1693
1694 double aux0, aux1, aux00, aux01, aux10, aux11, mean = 0;
1695
1696 int n = 0;
1697
1698 /* Adjust longitude... */
1699 if (lon < lons[0])
1700 lon += 360;
1701 else if (lon > lons[nlon - 1])
1702 lon -= 360;
1703
1704 /* Get indices... */
1705 int ix = locate_reg(lons, (int) nlon, lon);
1706 int iy = locate_reg(lats, (int) nlat, lat);
1707
1708 /* Calculate standard deviation... */
1709 *sigma = 0;
1710 for (int dx = 0; dx < 2; dx++)
1711 for (int dy = 0; dy < 2; dy++) {
1712 if (isfinite(array0[ix + dx][iy + dy])) {
1713 mean += array0[ix + dx][iy + dy];
1714 *sigma += SQR(array0[ix + dx][iy + dy]);
1715 n++;
1716 }
1717 if (isfinite(array1[ix + dx][iy + dy])) {
1718 mean += array1[ix + dx][iy + dy];
1719 *sigma += SQR(array1[ix + dx][iy + dy]);
1720 n++;
1721 }
1722 }
1723 if (n > 0)
1724 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
1725
1726 /* Linear interpolation... */
1727 if (method == 1 && isfinite(array0[ix][iy])
1728 && isfinite(array0[ix][iy + 1])
1729 && isfinite(array0[ix + 1][iy])
1730 && isfinite(array0[ix + 1][iy + 1])
1731 && isfinite(array1[ix][iy])
1732 && isfinite(array1[ix][iy + 1])
1733 && isfinite(array1[ix + 1][iy])
1734 && isfinite(array1[ix + 1][iy + 1])) {
1735
1736 aux00 = LIN(lons[ix], array0[ix][iy],
1737 lons[ix + 1], array0[ix + 1][iy], lon);
1738 aux01 = LIN(lons[ix], array0[ix][iy + 1],
1739 lons[ix + 1], array0[ix + 1][iy + 1], lon);
1740 aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat);
1741
1742 aux10 = LIN(lons[ix], array1[ix][iy],
1743 lons[ix + 1], array1[ix + 1][iy], lon);
1744 aux11 = LIN(lons[ix], array1[ix][iy + 1],
1745 lons[ix + 1], array1[ix + 1][iy + 1], lon);
1746 aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat);
1747
1748 *var = LIN(time0, aux0, time1, aux1, time);
1749 }
1750
1751 /* Nearest neighbor interpolation... */
1752 else {
1753 aux00 = NN(lons[ix], array0[ix][iy],
1754 lons[ix + 1], array0[ix + 1][iy], lon);
1755 aux01 = NN(lons[ix], array0[ix][iy + 1],
1756 lons[ix + 1], array0[ix + 1][iy + 1], lon);
1757 aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat);
1758
1759 aux10 = NN(lons[ix], array1[ix][iy],
1760 lons[ix + 1], array1[ix + 1][iy], lon);
1761 aux11 = NN(lons[ix], array1[ix][iy + 1],
1762 lons[ix + 1], array1[ix + 1][iy + 1], lon);
1763 aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat);
1764
1765 *var = NN(time0, aux0, time1, aux1, time);
1766 }
1767}
1768
1769/*****************************************************************************/
1770
1772 const double jsec,
1773 int *year,
1774 int *mon,
1775 int *day,
1776 int *hour,
1777 int *min,
1778 int *sec,
1779 double *remain) {
1780
1781 struct tm t0, *t1;
1782
1783 t0.tm_year = 100;
1784 t0.tm_mon = 0;
1785 t0.tm_mday = 1;
1786 t0.tm_hour = 0;
1787 t0.tm_min = 0;
1788 t0.tm_sec = 0;
1789
1790 time_t jsec0 = (time_t) jsec + timegm(&t0);
1791 t1 = gmtime(&jsec0);
1792
1793 *year = t1->tm_year + 1900;
1794 *mon = t1->tm_mon + 1;
1795 *day = t1->tm_mday;
1796 *hour = t1->tm_hour;
1797 *min = t1->tm_min;
1798 *sec = t1->tm_sec;
1799 *remain = jsec - floor(jsec);
1800}
1801
1802/*****************************************************************************/
1803
1805 const double kz[EP],
1806 const double kw[EP],
1807 const int nk,
1808 const double p) {
1809
1810 /* Check number of data points... */
1811 if (nk < 2)
1812 return 1.0;
1813
1814 /* Get altitude... */
1815 double z = Z(p);
1816
1817 /* Get weighting factor... */
1818 if (z < kz[0])
1819 return kw[0];
1820 else if (z > kz[nk - 1])
1821 return kw[nk - 1];
1822 else {
1823 int idx = locate_irr(kz, nk, z);
1824 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
1825 }
1826}
1827
1828/*****************************************************************************/
1829
1831 const double t,
1832 const double h2o) {
1833
1834 /*
1835 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
1836 and water vapor volume mixing ratio [1].
1837
1838 Reference: https://en.wikipedia.org/wiki/Lapse_rate
1839 */
1840
1841 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
1842
1843 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
1844}
1845
1846/*****************************************************************************/
1847
1849 ctl_t * ctl) {
1850
1851
1852 if (0 == ctl->met_press_level_def) {
1853
1854 ctl->met_np = 138;
1855
1856 const double press[138] = {
1857 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1858 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1859 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1860 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1861 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1862 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1863 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1864 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1865 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1866 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1867 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1868 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1869 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1870 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1871 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1872 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1873 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1874 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1875 1010.8487, 1013.2500, 1044.45
1876 };
1877
1878 for (int ip = 0; ip < ctl->met_np; ip++)
1879 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1880
1881 } else if (1 == ctl->met_press_level_def) {
1882
1883 ctl->met_np = 92;
1884
1885 const double press[92] = {
1886 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1887 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1888 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1889 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1890 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1891 113.6382,
1892 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1893 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1894 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1895 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1896 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1897 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1898 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1899 1007.4431, 1010.8487, 1013.2500, 1044.45
1900 };
1901
1902 for (int ip = 0; ip < ctl->met_np; ip++)
1903 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1904
1905 } else if (2 == ctl->met_press_level_def) {
1906
1907 ctl->met_np = 60;
1908
1909 const double press[60] = {
1910 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1911 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1912 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1913 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1914 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1915 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1916 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1917 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1044.45
1918 };
1919
1920 for (int ip = 0; ip < ctl->met_np; ip++)
1921 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1922
1923 } else if (3 == ctl->met_press_level_def) {
1924
1925 ctl->met_np = 147;
1926
1927 const double press[147] = {
1928 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1929 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1930 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1931 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1932 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1933 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1934 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1935 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1936 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1937 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1938 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1939 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1940 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1941 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1942 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1943 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1944 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1945 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1946 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
1947 1031.97,
1948 1035.09, 1038.21, 1041.33, 1044.45
1949 };
1950
1951 for (int ip = 0; ip < ctl->met_np; ip++)
1952 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1953
1954 } else if (4 == ctl->met_press_level_def) {
1955
1956 ctl->met_np = 101;
1957
1958 const double press[101] = {
1959 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1960 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1961 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1962 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1963 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1964 113.6382,
1965 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1966 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1967 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1968 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1969 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1970 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1971 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1972 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
1973 1028.85, 1031.97,
1974 1035.09, 1038.21, 1041.33, 1044.45
1975 };
1976
1977 for (int ip = 0; ip < ctl->met_np; ip++)
1978 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1979
1980 } else if (5 == ctl->met_press_level_def) {
1981
1982 ctl->met_np = 62;
1983
1984 const double press[62] = {
1985 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1986 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1987 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1988 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1989 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1990 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1991 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1992 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
1993 1044.45
1994 };
1995
1996 for (int ip = 0; ip < ctl->met_np; ip++)
1997 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1998
1999 } else if (6 == ctl->met_press_level_def) {
2000
2001 ctl->met_np = 137;
2002
2003 const double press[137] = {
2004 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
2005 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
2006 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
2007 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
2008 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
2009 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2010 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
2011 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
2012 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
2013 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
2014 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
2015 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
2016 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
2017 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
2018 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
2019 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
2020 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
2021 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
2022 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
2023 1030.06, 1037.25, 1044.45
2024 };
2025
2026 for (int ip = 0; ip < ctl->met_np; ip++)
2027 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2028
2029 } else if (7 == ctl->met_press_level_def) {
2030
2031 ctl->met_np = 59;
2032
2033 const double press[59] = {
2034 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2035 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2036 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2037 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2038 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2039 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2040 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2041 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2042 1028.53, 1046.13
2043 };
2044
2045 for (int ip = 0; ip < ctl->met_np; ip++)
2046 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2047
2048 } else {
2049 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.")
2050 }
2051}
2052
2053/*****************************************************************************/
2054
2056 const double *xx,
2057 const int n,
2058 const double x) {
2059
2060 int ilo = 0;
2061 int ihi = n - 1;
2062 int i = (ihi + ilo) >> 1;
2063
2064 if (xx[i] < xx[i + 1])
2065 while (ihi > ilo + 1) {
2066 i = (ihi + ilo) >> 1;
2067 if (xx[i] > x)
2068 ihi = i;
2069 else
2070 ilo = i;
2071 } else
2072 while (ihi > ilo + 1) {
2073 i = (ihi + ilo) >> 1;
2074 if (xx[i] <= x)
2075 ihi = i;
2076 else
2077 ilo = i;
2078 }
2079
2080 return ilo;
2081}
2082
2083/*****************************************************************************/
2084
2086 const float *xx,
2087 const int n,
2088 const double x,
2089 const int ig) {
2090
2091 int ilo = 0;
2092 int ihi = n - 1;
2093 int i = (ihi + ilo) >> 1;
2094
2095 if (x >= xx[ig] && x < xx[ig + 1])
2096 return ig;
2097
2098 if (xx[i] < xx[i + 1])
2099 while (ihi > ilo + 1) {
2100 i = (ihi + ilo) >> 1;
2101 if (xx[i] > x)
2102 ihi = i;
2103 else
2104 ilo = i;
2105 } else
2106 while (ihi > ilo + 1) {
2107 i = (ihi + ilo) >> 1;
2108 if (xx[i] <= x)
2109 ihi = i;
2110 else
2111 ilo = i;
2112 }
2113
2114 return ilo;
2115}
2116
2117/*****************************************************************************/
2118
2120 float profiles[EX][EY][EP],
2121 int np,
2122 int ind_lon,
2123 int ind_lat,
2124 double x) {
2125
2126 int ilo = 0;
2127 int ihi = np - 1;
2128 int i = (ihi + ilo) >> 1;
2129
2130 if (profiles[ind_lon][ind_lat][i] < profiles[ind_lon][ind_lat][i + 1])
2131 while (ihi > ilo + 1) {
2132 i = (ihi + ilo) >> 1;
2133 if (profiles[ind_lon][ind_lat][i] > x) {
2134 ihi = i;
2135 } else {
2136 ilo = i;
2137 }
2138 } else
2139 while (ihi > ilo + 1) {
2140 i = (ihi + ilo) >> 1;
2141 if (profiles[ind_lon][ind_lat][i] <= x) {
2142 ihi = i;
2143 } else {
2144 ilo = i;
2145 }
2146 }
2147
2148 return ilo;
2149}
2150
2151/*****************************************************************************/
2152
2154 const double *xx,
2155 const int n,
2156 const double x) {
2157
2158 /* Calculate index... */
2159 int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2160
2161 /* Check range... */
2162 if (i < 0)
2163 return 0;
2164 else if (i > n - 2)
2165 return n - 2;
2166 else
2167 return i;
2168}
2169
2170/*****************************************************************************/
2171
2173 float profiles[EX][EY][EP],
2174 int np,
2175 int lon_ap_ind,
2176 int lat_ap_ind,
2177 double height_ap,
2178 int *ind) {
2179
2180 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2181 np, height_ap, 0);
2182 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2183 np, height_ap, ind[0]);
2184 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2185 np, height_ap, ind[1]);
2186 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2187 np, height_ap, ind[2]);
2188}
2189
2190/*****************************************************************************/
2191
2193 ctl_t * ctl,
2194 met_t * met0,
2195 met_t * met1,
2196 atm_t * atm,
2197 double *dt) {
2198
2199 /* Set timer... */
2200 SELECT_TIMER("MODULE_ADVECTION", "PHYSICS", NVTX_GPU);
2201
2202 /* Pressure coordinate... */
2203 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2204
2205 /* Loop over particles... */
2206 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
2207
2208 /* Init... */
2210 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2211 x[3] = { 0, 0, 0 };
2212
2213 /* Loop over integration nodes... */
2214 for (int i = 0; i < ctl->advect; i++) {
2215
2216 /* Set position... */
2217 if (i == 0) {
2218 dts = 0.0;
2219 x[0] = atm->lon[ip];
2220 x[1] = atm->lat[ip];
2221 x[2] = atm->p[ip];
2222 } else {
2223 dts = (i == 3 ? 1.0 : 0.5) * dt[ip];
2224 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2225 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2226 x[2] = atm->p[ip] + dts * w[i - 1];
2227 }
2228 double tm = atm->time[ip] + dts;
2229
2230 /* Interpolate meteo data on pressure levels... */
2231 if (ctl->advect_vert_coord == 0) {
2232 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2233 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2234 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2235 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2236 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2237 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2238 }
2239
2240 /* Interpolate meteo data on model levels... */
2241 else {
2242 intpol_met_time_3d_ml(met0, met0->ul, met1, met1->ul, tm, x[2],
2243 x[0], x[1], &u[i]);
2244 intpol_met_time_3d_ml(met0, met0->vl, met1, met1->vl, tm, x[2],
2245 x[0], x[1], &v[i]);
2246 intpol_met_time_3d_ml(met0, met0->wl, met1, met1->wl, tm, x[2],
2247 x[0], x[1], &w[i]);
2248 }
2249
2250 /* Get mean wind... */
2251 double k = 1.0;
2252 if (ctl->advect == 2)
2253 k = (i == 0 ? 0.0 : 1.0);
2254 else if (ctl->advect == 4)
2255 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2256 um += k * u[i];
2257 vm += k * v[i];
2258 wm += k * w[i];
2259 }
2260
2261 /* Set new position... */
2262 atm->time[ip] += dt[ip];
2263 atm->lon[ip] += DX2DEG(dt[ip] * um / 1000.,
2264 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2265 atm->lat[ip] += DY2DEG(dt[ip] * vm / 1000.);
2266 atm->p[ip] += dt[ip] * wm;
2267 }
2268 }
2269
2270 /* Zeta coordinate... */
2271 else if (ctl->advect_vert_coord == 1) {
2272
2273 /* Loop over particles... */
2274 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
2275
2276 /* If other modules have changed p translate it into a zeta... */
2277 if (ctl->advect_cpl_zeta_and_press_modules > 0) {
2279 intpol_met_4d_coord(met0, met0->pl, met0->zetal, met1,
2280 met1->pl, met1->zetal, atm->time[ip], atm->p[ip],
2281 atm->lon[ip], atm->lat[ip],
2282 &atm->q[ctl->qnt_zeta][ip], ci, cw, 1);
2283 }
2284
2285 /* Init... */
2286 double dts, u[4], um = 0, v[4], vm = 0, zeta_dot[4], zeta_dotm = 0,
2287 x[3] = { 0, 0, 0 };
2288
2289 /* Loop over integration nodes... */
2290 for (int i = 0; i < ctl->advect; i++) {
2291
2292 /* Set position... */
2293 if (i == 0) {
2294 dts = 0.0;
2295 x[0] = atm->lon[ip];
2296 x[1] = atm->lat[ip];
2297 x[2] = atm->q[ctl->qnt_zeta][ip];
2298 } else {
2299 dts = (i == 3 ? 1.0 : 0.5) * dt[ip];
2300 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2301 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2302 x[2] = atm->q[ctl->qnt_zeta][ip] + dts * zeta_dot[i - 1];
2303 }
2304 double tm = atm->time[ip] + dts;
2305
2306 /* Interpolate meteo data... */
2308 intpol_met_4d_coord(met0, met0->zetal, met0->ul, met1, met1->zetal,
2309 met1->ul, tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2310 intpol_met_4d_coord(met0, met0->zetal, met0->vl, met1, met0->zetal,
2311 met1->vl, tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2312 intpol_met_4d_coord(met0, met0->zetal, met0->zeta_dotl, met1,
2313 met1->zetal, met1->zeta_dotl, tm, x[2], x[0],
2314 x[1], &zeta_dot[i], ci, cw, 0);
2315
2316 /* Get mean wind... */
2317 double k = 1.0;
2318 if (ctl->advect == 2)
2319 k = (i == 0 ? 0.0 : 1.0);
2320 else if (ctl->advect == 4)
2321 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2322 um += k * u[i];
2323 vm += k * v[i];
2324 zeta_dotm += k * zeta_dot[i];
2325 }
2326
2327 /* Set new position... */
2328 atm->time[ip] += dt[ip];
2329 atm->lon[ip] += DX2DEG(dt[ip] * um / 1000.,
2330 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2331 atm->lat[ip] += DY2DEG(dt[ip] * vm / 1000.);
2332 atm->q[ctl->qnt_zeta][ip] += dt[ip] * zeta_dotm;
2333
2334 /* Check if zeta is below zero... */
2335 if (atm->q[ctl->qnt_zeta][ip] < 0) {
2336 atm->q[ctl->qnt_zeta][ip] = 0;
2337 }
2338
2339 /* Set new position also in pressure coordinates... */
2341 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2342 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2343 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2344 }
2345 }
2346}
2347
2348/*****************************************************************************/
2349
2351 ctl_t * ctl,
2352 met_t * met0,
2353 met_t * met1,
2354 atm_t * atm) {
2355
2356 /* Initialize pressure consistent with zeta... */
2357 if (ctl->advect_vert_coord == 1) {
2358#pragma omp parallel for default(shared)
2359 for (int ip = 0; ip < atm->np; ip++) {
2361 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2362 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2363 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2364 }
2365 }
2366}
2367
2368/*****************************************************************************/
2369
2371 ctl_t * ctl,
2372 clim_t * clim,
2373 met_t * met0,
2374 met_t * met1,
2375 atm_t * atm,
2376 double *dt) {
2377
2378 /* Set timer... */
2379 SELECT_TIMER("MODULE_BOUNDCOND", "PHYSICS", NVTX_GPU);
2380
2381 /* Check quantity flags... */
2382 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2383 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2384 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2385 return;
2386
2387 /* Loop over particles... */
2388 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,met0,met1,atm,dt)") {
2389
2390 /* Check latitude and pressure range... */
2391 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2392 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2393 continue;
2394
2395 /* Check surface layer... */
2396 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2397 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2398
2399 /* Get surface pressure... */
2400 double ps;
2402 INTPOL_2D(ps, 1);
2403
2404 /* Check pressure... */
2405 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2406 continue;
2407
2408 /* Check height... */
2409 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2410 continue;
2411
2412 /* Check zeta range... */
2413 if (ctl->bound_zetas > 0) {
2414 double t;
2415 INTPOL_3D(t, 1);
2416 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2417 continue;
2418 }
2419
2420 /* Check planetary boundary layer... */
2421 if (ctl->bound_pbl) {
2422 double pbl;
2423 INTPOL_2D(pbl, 0);
2424 if (atm->p[ip] < pbl)
2425 continue;
2426 }
2427 }
2428
2429 /* Set mass and volume mixing ratio... */
2430 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2431 atm->q[ctl->qnt_m][ip] =
2432 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2433 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2434 atm->q[ctl->qnt_vmr][ip] =
2435 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2436
2437 /* Set CFC-10 volume mixing ratio... */
2438 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2439 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2440
2441 /* Set CFC-11 volume mixing ratio... */
2442 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2443 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2444
2445 /* Set CFC-12 volume mixing ratio... */
2446 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2447 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2448
2449 /* Set N2O volume mixing ratio... */
2450 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2451 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2452
2453 /* Set SF6 volume mixing ratio... */
2454 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2455 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2456
2457 /* Set age of air... */
2458 if (ctl->qnt_aoa >= 0)
2459 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2460 }
2461}
2462
2463/*****************************************************************************/
2464
2466 ctl_t * ctl,
2467 met_t * met0,
2468 met_t * met1,
2469 atm_t * atm,
2470 double tt) {
2471
2472 /* Check quantities... */
2473 if (ctl->molmass <= 0)
2474 ERRMSG("Molar mass is not defined!");
2475 if (ctl->qnt_m < 0)
2476 ERRMSG("Module needs quantity mass!");
2477 if (ctl->qnt_Cx < 0)
2478 ERRMSG("Module needs quantity Cx!");
2479
2480 /* Set timer... */
2481 SELECT_TIMER("MODULE_CHEMGRID", "PHYSICS", NVTX_GPU);
2482
2483 /* Allocate... */
2484 const int np = atm->np;
2485 const int nz = ctl->chemgrid_nz;
2486 const int nx = ctl->chemgrid_nx;
2487 const int ny = ctl->chemgrid_ny;
2488 const int ngrid = nx * ny * nz;
2489
2490 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2491 double *restrict const press =
2492 (double *) malloc((size_t) nz * sizeof(double));
2493 double *restrict const mass =
2494 (double *) calloc((size_t) ngrid, sizeof(double));
2495 double *restrict const area =
2496 (double *) malloc((size_t) ny * sizeof(double));
2497 double *restrict const lon =
2498 (double *) malloc((size_t) nx * sizeof(double));
2499 double *restrict const lat =
2500 (double *) malloc((size_t) ny * sizeof(double));
2501
2502 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2503 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2504 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2505
2506 /* Set grid box size... */
2507 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2508 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2509 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2510
2511 /* Set vertical coordinates... */
2512#ifdef _OPENACC
2513#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np],z[0:nz],press[0:nz],mass[0:ngrid],area[0:ny],lon[0:nx],lat[0:ny])
2514#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2515#pragma acc parallel loop independent gang vector
2516#else
2517#pragma omp parallel for default(shared)
2518#endif
2519 for (int iz = 0; iz < nz; iz++) {
2520 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2521 press[iz] = P(z[iz]);
2522 }
2523
2524 /* Set time interval for output... */
2525 const double t0 = tt - 0.5 * ctl->dt_mod;
2526 const double t1 = tt + 0.5 * ctl->dt_mod;
2527
2528 /* Get indices... */
2529#ifdef _OPENACC
2530#pragma acc parallel loop independent gang vector
2531#else
2532#pragma omp parallel for default(shared)
2533#endif
2534 for (int ip = 0; ip < np; ip++) {
2535 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2536 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2537 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2538 if (atm->time[ip] < t0 || atm->time[ip] > t1
2539 || ixs[ip] < 0 || ixs[ip] >= nx
2540 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2541 izs[ip] = -1;
2542 }
2543
2544 /* Set horizontal coordinates... */
2545#ifdef _OPENACC
2546#pragma acc parallel loop independent gang vector
2547#else
2548#pragma omp parallel for default(shared)
2549#endif
2550 for (int ix = 0; ix < nx; ix++)
2551 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
2552#ifdef _OPENACC
2553#pragma acc parallel loop independent gang vector
2554#else
2555#pragma omp parallel for default(shared)
2556#endif
2557 for (int iy = 0; iy < ny; iy++) {
2558 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
2559 area[iy] =
2560 dlat * dlon * SQR(RE * M_PI / 180.) * cos(lat[iy] * M_PI / 180.);
2561 }
2562
2563 /* Get mass per grid box... */
2564#ifdef _OPENACC
2565#pragma acc parallel loop independent gang vector
2566#endif
2567 for (int ip = 0; ip < np; ip++)
2568 if (izs[ip] >= 0)
2569#ifdef _OPENACC
2570#pragma acc atomic update
2571#endif
2572 mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)]
2573 += atm->q[ctl->qnt_m][ip];
2574
2575 /* Assign grid data to air parcels ... */
2576#ifdef _OPENACC
2577#pragma acc parallel loop independent gang vector
2578#else
2579#pragma omp parallel for default(shared)
2580#endif
2581 for (int ip = 0; ip < np; ip++)
2582 if (izs[ip] >= 0) {
2583
2584 /* Interpolate temperature... */
2585 double temp;
2587 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt, press[izs[ip]],
2588 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
2589
2590 /* Set mass... */
2591 double m = mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)];
2592
2593 /* Calculate volume mixing ratio... */
2594 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
2595 / (1e9 * RHO(press[izs[ip]], temp) * area[iys[ip]] * dz);
2596 }
2597#ifdef _OPENACC
2598#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
2599#endif
2600
2601 /* Free... */
2602 free(mass);
2603 free(lon);
2604 free(lat);
2605 free(area);
2606 free(z);
2607 free(press);
2608 free(ixs);
2609 free(iys);
2610 free(izs);
2611}
2612
2613/*****************************************************************************/
2614
2616 ctl_t * ctl,
2617 clim_t * clim,
2618 met_t * met0,
2619 met_t * met1,
2620 atm_t * atm) {
2621
2622#pragma omp parallel for default(shared)
2623 for (int ip = 0; ip < atm->np; ip++) {
2624
2625 /* Set H2O and O3 using meteo data... */
2627 if (ctl->qnt_Ch2o >= 0) {
2628 double h2o;
2629 INTPOL_3D(h2o, 1);
2630 SET_ATM(qnt_Ch2o, h2o);
2631 }
2632 if (ctl->qnt_Co3 >= 0) {
2633 double o3;
2634 INTPOL_3D(o3, 1);
2635 SET_ATM(qnt_Co3, o3);
2636 }
2637
2638 /* Set radical species... */
2639 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
2640 atm->lon[ip], atm->lat[ip], atm->p[ip]));
2641 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
2642 atm->lat[ip], atm->p[ip]));
2643 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
2644 atm->lat[ip], atm->p[ip]));
2645 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
2646 atm->lat[ip], atm->p[ip]));
2647 }
2648}
2649
2650/*****************************************************************************/
2651
2653 ctl_t * ctl,
2654 met_t * met0,
2655 met_t * met1,
2656 atm_t * atm,
2657 double *dt,
2658 double *rs) {
2659
2660 /* Set timer... */
2661 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
2662
2663 /* Create random numbers... */
2664 module_rng(ctl, rs, (size_t) atm->np, 0);
2665
2666 /* Loop over particles... */
2667 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt,rs)") {
2668
2669 /* Interpolate CAPE... */
2670 double cape;
2672 INTPOL_2D(cape, 1);
2673
2674 /* Check threshold... */
2675 if (isfinite(cape) && cape >= ctl->conv_cape) {
2676
2677 /* Check CIN... */
2678 if (ctl->conv_cin > 0) {
2679 double cin;
2680 INTPOL_2D(cin, 0);
2681 if (isfinite(cin) && cin >= ctl->conv_cin)
2682 continue;
2683 }
2684
2685 /* Interpolate equilibrium level... */
2686 double pel;
2687 INTPOL_2D(pel, 0);
2688
2689 /* Check whether particle is above cloud top... */
2690 if (!isfinite(pel) || atm->p[ip] < pel)
2691 continue;
2692
2693 /* Set pressure range for vertical mixing... */
2694 double pbot = atm->p[ip];
2695 double ptop = atm->p[ip];
2696 if (ctl->conv_mix_bot == 1) {
2697 double ps;
2698 INTPOL_2D(ps, 0);
2699 pbot = ps;
2700 }
2701 if (ctl->conv_mix_top == 1)
2702 ptop = pel;
2703
2704 /* Get density range... */
2705 double tbot, ttop;
2706 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2707 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
2708 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2709 ptop, atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
2710 double rhobot = pbot / tbot;
2711 double rhotop = ptop / ttop;
2712
2713 /* Get new density... */
2714 double rho = rhobot + (rhotop - rhobot) * rs[ip];
2715
2716 /* Get pressure... */
2717 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
2718 }
2719 }
2720}
2721
2722/*****************************************************************************/
2723
2725 ctl_t * ctl,
2726 clim_t * clim,
2727 atm_t * atm,
2728 double *dt) {
2729
2730 /* Set timer... */
2731 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
2732
2733 /* Check quantity flags... */
2734 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2735 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2736
2737 /* Loop over particles... */
2738 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,atm,dt)") {
2739
2740 /* Get weighting factor... */
2741 double w = tropo_weight(clim, atm->time[ip], atm->lat[ip], atm->p[ip]);
2742
2743 /* Set lifetime... */
2744 double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
2745
2746 /* Calculate exponential decay... */
2747 double aux = exp(-dt[ip] / tdec);
2748 if (ctl->qnt_m >= 0) {
2749 if (ctl->qnt_mloss_decay >= 0)
2750 atm->q[ctl->qnt_mloss_decay][ip]
2751 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2752 atm->q[ctl->qnt_m][ip] *= aux;
2753 if (ctl->qnt_loss_rate >= 0)
2754 atm->q[ctl->qnt_loss_rate][ip] += 1 / tdec;
2755 }
2756 if (ctl->qnt_vmr >= 0)
2757 atm->q[ctl->qnt_vmr][ip] *= aux;
2758 }
2759}
2760
2761/*****************************************************************************/
2762
2764 ctl_t * ctl,
2765 met_t * met0,
2766 met_t * met1,
2767 atm_t * atm,
2768 cache_t * cache,
2769 double *dt,
2770 double *rs) {
2771
2772 /* Set timer... */
2773 SELECT_TIMER("MODULE_TURBMESO", "PHYSICS", NVTX_GPU);
2774
2775 /* Create random numbers... */
2776 module_rng(ctl, rs, 3 * (size_t) atm->np, 1);
2777
2778 /* Loop over particles... */
2779 PARTICLE_LOOP(0, atm->np, 1,
2780 "acc data present(ctl,met0,met1,atm,cache,dt,rs)") {
2781
2782 /* Get indices... */
2783 int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
2784 int iy = locate_reg(met0->lat, met0->ny, atm->lat[ip]);
2785 int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
2786
2787 /* Get standard deviations of local wind data... */
2788 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
2789 for (int i = 0; i < 2; i++)
2790 for (int j = 0; j < 2; j++)
2791 for (int k = 0; k < 2; k++) {
2792 umean += met0->u[ix + i][iy + j][iz + k];
2793 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
2794 vmean += met0->v[ix + i][iy + j][iz + k];
2795 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
2796 wmean += met0->w[ix + i][iy + j][iz + k];
2797 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
2798
2799 umean += met1->u[ix + i][iy + j][iz + k];
2800 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
2801 vmean += met1->v[ix + i][iy + j][iz + k];
2802 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
2803 wmean += met1->w[ix + i][iy + j][iz + k];
2804 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
2805 }
2806 usig = usig / 16.f - SQR(umean / 16.f);
2807 usig = (usig > 0 ? sqrtf(usig) : 0);
2808 vsig = vsig / 16.f - SQR(vmean / 16.f);
2809 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
2810 wsig = wsig / 16.f - SQR(wmean / 16.f);
2811 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
2812
2813 /* Set temporal correlations for mesoscale fluctuations... */
2814 double r = 1 - 2 * fabs(dt[ip]) / ctl->dt_met;
2815 double r2 = sqrt(1 - r * r);
2816
2817 /* Calculate horizontal mesoscale wind fluctuations... */
2818 if (ctl->turb_mesox > 0) {
2819 cache->uvwp[ip][0] =
2820 (float) (r * cache->uvwp[ip][0] +
2821 r2 * rs[3 * ip] * ctl->turb_mesox * usig);
2822 atm->lon[ip] +=
2823 DX2DEG(cache->uvwp[ip][0] * dt[ip] / 1000., atm->lat[ip]);
2824
2825 cache->uvwp[ip][1] =
2826 (float) (r * cache->uvwp[ip][1] +
2827 r2 * rs[3 * ip + 1] * ctl->turb_mesox * vsig);
2828 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * dt[ip] / 1000.);
2829 }
2830
2831 /* Calculate vertical mesoscale wind fluctuations... */
2832 if (ctl->turb_mesoz > 0) {
2833 cache->uvwp[ip][2] =
2834 (float) (r * cache->uvwp[ip][2] +
2835 r2 * rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
2836 atm->p[ip] += cache->uvwp[ip][2] * dt[ip];
2837 }
2838 }
2839}
2840
2841/*****************************************************************************/
2842
2844 ctl_t * ctl,
2845 clim_t * clim,
2846 atm_t * atm,
2847 double *dt,
2848 double *rs) {
2849
2850 /* Set timer... */
2851 SELECT_TIMER("MODULE_TURBDIFF", "PHYSICS", NVTX_GPU);
2852
2853 /* Create random numbers... */
2854 module_rng(ctl, rs, 3 * (size_t) atm->np, 1);
2855
2856 /* Loop over particles... */
2857 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,atm,dt,rs)") {
2858
2859 /* Get weighting factor... */
2860 double w = tropo_weight(clim, atm->time[ip], atm->lat[ip], atm->p[ip]);
2861
2862 /* Set diffusivity... */
2863 double dx = w * ctl->turb_dx_trop + (1 - w) * ctl->turb_dx_strat;
2864 double dz = w * ctl->turb_dz_trop + (1 - w) * ctl->turb_dz_strat;
2865
2866 /* Horizontal turbulent diffusion... */
2867 if (dx > 0) {
2868 double sigma = sqrt(2.0 * dx * fabs(dt[ip]));
2869 atm->lon[ip] += DX2DEG(rs[3 * ip] * sigma / 1000., atm->lat[ip]);
2870 atm->lat[ip] += DY2DEG(rs[3 * ip + 1] * sigma / 1000.);
2871 }
2872
2873 /* Vertical turbulent diffusion... */
2874 if (dz > 0) {
2875 double sigma = sqrt(2.0 * dz * fabs(dt[ip]));
2876 atm->p[ip] += DZ2DP(rs[3 * ip + 2] * sigma / 1000., atm->p[ip]);
2877 }
2878 }
2879}
2880
2881/*****************************************************************************/
2882
2884 ctl_t * ctl,
2885 met_t * met0,
2886 met_t * met1,
2887 atm_t * atm,
2888 double *dt) {
2889
2890 /* Set timer... */
2891 SELECT_TIMER("MODULE_DRYDEPO", "PHYSICS", NVTX_GPU);
2892
2893 /* Check quantity flags... */
2894 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2895 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2896
2897 /* Loop over particles... */
2898 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
2899
2900 /* Get surface pressure... */
2901 double ps;
2903 INTPOL_2D(ps, 1);
2904
2905 /* Check whether particle is above the surface layer... */
2906 if (atm->p[ip] < ps - ctl->dry_depo_dp)
2907 continue;
2908
2909 /* Set depth of surface layer... */
2910 double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
2911
2912 /* Calculate sedimentation velocity for particles... */
2913 double v_dep;
2914 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
2915
2916 /* Get temperature... */
2917 double t;
2918 INTPOL_3D(t, 1);
2919
2920 /* Set deposition velocity... */
2921 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
2922 atm->q[ctl->qnt_rhop][ip]);
2923 }
2924
2925 /* Use explicit sedimentation velocity for gases... */
2926 else
2927 v_dep = ctl->dry_depo_vdep;
2928
2929 /* Calculate loss of mass based on deposition velocity... */
2930 double aux = exp(-dt[ip] * v_dep / dz);
2931 if (ctl->qnt_m >= 0) {
2932 if (ctl->qnt_mloss_dry >= 0)
2933 atm->q[ctl->qnt_mloss_dry][ip]
2934 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2935 atm->q[ctl->qnt_m][ip] *= aux;
2936 if (ctl->qnt_loss_rate >= 0)
2937 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
2938 }
2939 if (ctl->qnt_vmr >= 0)
2940 atm->q[ctl->qnt_vmr][ip] *= aux;
2941 }
2942}
2943
2944/*****************************************************************************/
2945
2947 ctl_t * ctl,
2948 clim_t * clim,
2949 met_t * met0,
2950 met_t * met1,
2951 atm_t * atm,
2952 double *dt) {
2953
2954 /* Set timer... */
2955 SELECT_TIMER("MODULE_H2O2CHEM", "PHYSICS", NVTX_GPU);
2956
2957 /* Check quantity flags... */
2958 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2959 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2960
2961 /* Parameter of SO2 correction... */
2962 const double a = 3.12541941e-06;
2963 const double b = -5.72532259e-01;
2964 const double low = pow(1 / a, 1 / b);
2965
2966 /* Loop over particles... */
2967 PARTICLE_LOOP(0, atm->np, 1, "acc data present(clim,ctl,met0,met1,atm,dt)") {
2968
2969 /* Check whether particle is inside cloud... */
2970 double lwc, rwc;
2972 INTPOL_3D(lwc, 1);
2973 INTPOL_3D(rwc, 0);
2974 if (!(lwc > 0 || rwc > 0))
2975 continue;
2976
2977 /* Get temperature... */
2978 double t;
2979 INTPOL_3D(t, 0);
2980
2981 /* Get molecular density... */
2982 double M = MOLEC_DENS(atm->p[ip], t);
2983
2984 /* Reaction rate (Berglen et al., 2004)... */
2985 double k = 9.1e7 * exp(-29700 / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
2986
2987 /* Henry constant of SO2... */
2988 double H_SO2 = 1.3e-2 * exp(2900 * (1. / t - 1. / 298.15)) * RI * t;
2989 double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
2990
2991 /* Henry constant of H2O2... */
2992 double H_h2o2 = 8.3e2 * exp(7600 * (1 / t - 1 / 298.15)) * RI * t;
2993
2994 /* Correction factor for high SO2 concentration
2995 (if qnt_Cx is defined, the correction is switched on)... */
2996 double cor = 1;
2997 if (ctl->qnt_Cx >= 0)
2998 cor = atm->q[ctl->qnt_Cx][ip] >
2999 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3000
3001 double h2o2 = H_h2o2
3002 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3003 * M * cor * 1000 / AVO; /* unit: mol/L */
3004
3005 /* Volume water content in cloud [m^3 m^(-3)]... */
3006 double rho_air = 100 * atm->p[ip] / (RI * t) * MA / 1000;
3007 double CWC = (lwc + rwc) * rho_air / 1000;
3008
3009 /* Calculate exponential decay (Rolph et al., 1992)... */
3010 double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3011 double aux = exp(-dt[ip] * rate_coef);
3012 if (ctl->qnt_m >= 0) {
3013 if (ctl->qnt_mloss_h2o2 >= 0)
3014 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3015 atm->q[ctl->qnt_m][ip] *= aux;
3016 if (ctl->qnt_loss_rate >= 0)
3017 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3018 }
3019 if (ctl->qnt_vmr >= 0)
3020 atm->q[ctl->qnt_vmr][ip] *= aux;
3021 }
3022}
3023
3024/*****************************************************************************/
3025
3027 ctl_t * ctl,
3028 met_t * met0,
3029 met_t * met1,
3030 atm_t * atm,
3031 cache_t * cache) {
3032
3033 double t;
3034
3035 /* Set timer... */
3036 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3037
3038 /* Init... */
3040
3041 /* Save pressure... */
3042 if (ctl->isosurf == 1)
3043 for (int ip = 0; ip < atm->np; ip++)
3044 cache->iso_var[ip] = atm->p[ip];
3045
3046 /* Save density... */
3047 else if (ctl->isosurf == 2)
3048 for (int ip = 0; ip < atm->np; ip++) {
3049 INTPOL_3D(t, 1);
3050 cache->iso_var[ip] = atm->p[ip] / t;
3051 }
3052
3053 /* Save potential temperature... */
3054 else if (ctl->isosurf == 3)
3055 for (int ip = 0; ip < atm->np; ip++) {
3056 INTPOL_3D(t, 1);
3057 cache->iso_var[ip] = THETA(atm->p[ip], t);
3058 }
3059
3060 /* Read balloon pressure data... */
3061 else if (ctl->isosurf == 4) {
3062
3063 /* Write info... */
3064 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3065
3066 /* Open file... */
3067 FILE *in;
3068 if (!(in = fopen(ctl->balloon, "r")))
3069 ERRMSG("Cannot open file!");
3070
3071 /* Read pressure time series... */
3072 char line[LEN];
3073 while (fgets(line, LEN, in))
3074 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3075 &(cache->iso_ps[cache->iso_n])) == 2)
3076 if ((++cache->iso_n) > NP)
3077 ERRMSG("Too many data points!");
3078
3079 /* Check number of points... */
3080 if (cache->iso_n < 1)
3081 ERRMSG("Could not read any data!");
3082
3083 /* Close file... */
3084 fclose(in);
3085 }
3086}
3087
3088/*****************************************************************************/
3089
3091 ctl_t * ctl,
3092 met_t * met0,
3093 met_t * met1,
3094 atm_t * atm,
3095 cache_t * cache,
3096 double *dt) {
3097
3098 /* Set timer... */
3099 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3100
3101 /* Loop over particles... */
3102 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm,cache,dt)") {
3103
3104 /* Init... */
3105 double t;
3107
3108 /* Restore pressure... */
3109 if (ctl->isosurf == 1)
3110 atm->p[ip] = cache->iso_var[ip];
3111
3112 /* Restore density... */
3113 else if (ctl->isosurf == 2) {
3114 INTPOL_3D(t, 1);
3115 atm->p[ip] = cache->iso_var[ip] * t;
3116 }
3117
3118 /* Restore potential temperature... */
3119 else if (ctl->isosurf == 3) {
3120 INTPOL_3D(t, 1);
3121 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3122 }
3123
3124 /* Interpolate pressure... */
3125 else if (ctl->isosurf == 4) {
3126 if (atm->time[ip] <= cache->iso_ts[0])
3127 atm->p[ip] = cache->iso_ps[0];
3128 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3129 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3130 else {
3131 int idx = locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3132 atm->p[ip] = LIN(cache->iso_ts[idx], cache->iso_ps[idx],
3133 cache->iso_ts[idx + 1], cache->iso_ps[idx + 1],
3134 atm->time[ip]);
3135 }
3136 }
3137 }
3138}
3139
3140/*****************************************************************************/
3141
3142#ifdef KPP
3143void module_kpp_chem(
3144 ctl_t * ctl,
3145 clim_t * clim,
3146 met_t * met0,
3147 met_t * met1,
3148 atm_t * atm,
3149 double *dt) {
3150
3151 /* Set timer... */
3152 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS", NVTX_GPU);
3153
3154 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
3155 double rtol[1] = { 1.0e-3 };
3156 double atol[1] = { 1.0 };
3157
3158 /* Loop over particles... */
3159#ifdef _OPENACC
3160#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
3161#endif
3162 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,met0,met1,atm,dt) ") {
3163
3164 double var[nvar], fix[nfix], rconst[nreact];
3165 for (int i = 0; i < nvar; i++) {
3166 var[i] = 0.0;
3167 }
3168 for (int i = 0; i < nfix; i++) {
3169 fix[i] = 0.0;
3170 }
3171 for (int i = 0; i < nreact; i++) {
3172 rconst[i] = 0.0;
3173 }
3174 /* Initialize... */
3175 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
3176
3177 /* Integrate... */
3178 double rpar[20];
3179 int ipar[20];
3180
3181 for (int i = 0; i < 20; i++) {
3182 ipar[i] = 0;
3183 rpar[i] = 0.0;
3184 } /* for */
3185
3186 ipar[0] = 0; /* 0: F=F(y), i.e. independent of t (autonomous); 0:F=F(t,y), i.e. depends on t (non-autonomous) */
3187 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
3188 ipar[3] = 4; /* choice of the method:Rodas3 */
3189
3190 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
3191 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
3192
3193 /* Output to air parcel.. */
3194 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
3195
3196 }
3197}
3198#endif
3199
3200/*****************************************************************************/
3201
3203 ctl_t * ctl,
3204 clim_t * clim,
3205 met_t * met0,
3206 met_t * met1,
3207 atm_t * atm,
3208 double *dt) {
3209
3210 /* Set timer... */
3211 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
3212
3213 /* Check quantity flags... */
3214 if (ctl->qnt_tsts >= 0)
3215 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3216 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3217
3218 /* Loop over particles... */
3219 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,clim,met0,met1,atm,dt)") {
3220
3221 double ps, ts, zs, us, vs, lsm, sst, pbl, pt, pct, pcb, cl, plcl, plfc,
3222 pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot, o3,
3223 lwc, rwc, iwc, swc, cc, z, zt;
3224
3225 /* Interpolate meteo data... */
3227 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3228
3229 /* Set quantities... */
3230 SET_ATM(qnt_ps, ps);
3231 SET_ATM(qnt_ts, ts);
3232 SET_ATM(qnt_zs, zs);
3233 SET_ATM(qnt_us, us);
3234 SET_ATM(qnt_vs, vs);
3235 SET_ATM(qnt_lsm, lsm);
3236 SET_ATM(qnt_sst, sst);
3237 SET_ATM(qnt_pbl, pbl);
3238 SET_ATM(qnt_pt, pt);
3239 SET_ATM(qnt_tt, tt);
3240 SET_ATM(qnt_zt, zt);
3241 SET_ATM(qnt_h2ot, h2ot);
3242 SET_ATM(qnt_zg, z);
3243 SET_ATM(qnt_p, atm->p[ip]);
3244 SET_ATM(qnt_t, t);
3245 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3246 SET_ATM(qnt_u, u);
3247 SET_ATM(qnt_v, v);
3248 SET_ATM(qnt_w, w);
3249 SET_ATM(qnt_h2o, h2o);
3250 SET_ATM(qnt_o3, o3);
3251 SET_ATM(qnt_lwc, lwc);
3252 SET_ATM(qnt_rwc, rwc);
3253 SET_ATM(qnt_iwc, iwc);
3254 SET_ATM(qnt_swc, swc);
3255 SET_ATM(qnt_cc, cc);
3256 SET_ATM(qnt_pct, pct);
3257 SET_ATM(qnt_pcb, pcb);
3258 SET_ATM(qnt_cl, cl);
3259 SET_ATM(qnt_plcl, plcl);
3260 SET_ATM(qnt_plfc, plfc);
3261 SET_ATM(qnt_pel, pel);
3262 SET_ATM(qnt_cape, cape);
3263 SET_ATM(qnt_cin, cin);
3264 SET_ATM(qnt_o3c, o3c);
3265 SET_ATM(qnt_hno3,
3266 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3267 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3268 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3269 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3270 atm->lat[ip], atm->p[ip]));
3271 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3272 atm->lat[ip], atm->p[ip]));
3273 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3274 atm->lat[ip], atm->p[ip]));
3275 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3276 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3277 SET_ATM(qnt_psat, PSAT(t));
3278 SET_ATM(qnt_psice, PSICE(t));
3279 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3280 SET_ATM(qnt_sh, SH(h2o));
3281 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3282 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3283 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3284 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3285 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3286 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3287 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3288 SET_ATM(qnt_pv, pv);
3289 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3290 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3291 SET_ATM(qnt_tnat,
3292 nat_temperature(atm->p[ip], h2o,
3293 clim_zm(&clim->hno3, atm->time[ip],
3294 atm->lat[ip], atm->p[ip])));
3295 SET_ATM(qnt_tsts,
3296 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3297 }
3298}
3299
3300/*****************************************************************************/
3301
3303 ctl_t * ctl,
3304 clim_t * clim,
3305 atm_t * atm,
3306 double t) {
3307
3308 /* Set timer... */
3309 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
3310
3311 /* Allocate... */
3312 const int np = atm->np;
3313 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3314 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3315 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3316
3317 /* Set grid box size... */
3318 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3319 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3320 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3321
3322 /* Set time interval... */
3323 const double t0 = t - 0.5 * ctl->dt_mod;
3324 const double t1 = t + 0.5 * ctl->dt_mod;
3325
3326 /* Get indices... */
3327#ifdef _OPENACC
3328#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3329#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3330#pragma acc parallel loop independent gang vector
3331#else
3332#pragma omp parallel for default(shared)
3333#endif
3334 for (int ip = 0; ip < np; ip++) {
3335 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3336 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3337 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3338 if (atm->time[ip] < t0 || atm->time[ip] > t1
3339 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3340 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3341 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3342 izs[ip] = -1;
3343 }
3344
3345 /* Calculate interparcel mixing... */
3346 if (ctl->qnt_m >= 0)
3347 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_m);
3348 if (ctl->qnt_vmr >= 0)
3349 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_vmr);
3350 if (ctl->qnt_Ch2o >= 0)
3351 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o);
3352 if (ctl->qnt_Co3 >= 0)
3353 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3);
3354 if (ctl->qnt_Cco >= 0)
3355 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cco);
3356 if (ctl->qnt_Coh >= 0)
3357 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Coh);
3358 if (ctl->qnt_Ch >= 0)
3359 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch);
3360 if (ctl->qnt_Cho2 >= 0)
3361 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cho2);
3362 if (ctl->qnt_Ch2o2 >= 0)
3363 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o2);
3364 if (ctl->qnt_Co1d >= 0)
3365 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co1d);
3366 if (ctl->qnt_Co3p >= 0)
3367 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3p);
3368 if (ctl->qnt_Cccl4 >= 0)
3369 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl4);
3370 if (ctl->qnt_Cccl3f >= 0)
3371 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl3f);
3372 if (ctl->qnt_Cccl2f2 >= 0)
3373 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl2f2);
3374 if (ctl->qnt_Cn2o >= 0)
3375 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cn2o);
3376 if (ctl->qnt_Csf6 >= 0)
3377 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Csf6);
3378 if (ctl->qnt_aoa >= 0)
3379 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_aoa);
3380
3381 /* Free... */
3382#ifdef _OPENACC
3383#pragma acc exit data delete(ixs,iys,izs)
3384#endif
3385 free(ixs);
3386 free(iys);
3387 free(izs);
3388}
3389
3390/*****************************************************************************/
3391
3393 ctl_t * ctl,
3394 clim_t * clim,
3395 atm_t * atm,
3396 const int *ixs,
3397 const int *iys,
3398 const int *izs,
3399 int qnt_idx) {
3400
3401 /* Allocate... */
3402 const int np = atm->np;
3403 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
3404 double *restrict const cmean =
3405 (double *) malloc((size_t) ngrid * sizeof(double));
3406 int *restrict const count = (int *) malloc((size_t) ngrid * sizeof(int));
3407
3408 /* Init... */
3409#ifdef _OPENACC
3410#pragma acc enter data create(cmean[0:ngrid],count[0:ngrid])
3411#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
3412#pragma acc parallel loop independent gang vector
3413#else
3414#ifdef __NVCOMPILER
3415#pragma novector
3416#endif
3417#pragma omp parallel for
3418#endif
3419 for (int i = 0; i < ngrid; i++) {
3420 count[i] = 0;
3421 cmean[i] = 0;
3422 }
3423
3424 /* Loop over particles... */
3425#ifdef _OPENACC
3426#pragma acc parallel loop independent gang vector
3427#endif
3428 for (int ip = 0; ip < np; ip++)
3429 if (izs[ip] >= 0) {
3430 int idx = ARRAY_3D
3431 (ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz);
3432#ifdef _OPENACC
3433#pragma acc atomic update
3434#endif
3435 cmean[idx] += atm->q[qnt_idx][ip];
3436#ifdef _OPENACC
3437#pragma acc atomic update
3438#endif
3439 count[idx]++;
3440 }
3441#ifdef _OPENACC
3442#pragma acc parallel loop independent gang vector
3443#else
3444#ifdef __NVCOMPILER
3445#pragma novector
3446#endif
3447#pragma omp parallel for
3448#endif
3449 for (int i = 0; i < ngrid; i++)
3450 if (count[i] > 0)
3451 cmean[i] /= count[i];
3452
3453 /* Calculate interparcel mixing... */
3454#ifdef _OPENACC
3455#pragma acc parallel loop independent gang vector
3456#else
3457#pragma omp parallel for
3458#endif
3459 for (int ip = 0; ip < np; ip++)
3460 if (izs[ip] >= 0) {
3461
3462 /* Set mixing parameter... */
3463 double mixparam = 1.0;
3464 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
3465 double w =
3466 tropo_weight(clim, atm->time[ip], atm->lat[ip], atm->p[ip]);
3467 mixparam = w * ctl->mixing_trop + (1 - w) * ctl->mixing_strat;
3468 }
3469
3470 /* Adjust quantity... */
3471 atm->q[qnt_idx][ip] +=
3472 (cmean
3473 [ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz)]
3474 - atm->q[qnt_idx][ip]) * mixparam;
3475 }
3476
3477 /* Free... */
3478#ifdef _OPENACC
3479#pragma acc exit data delete(cmean,count)
3480#endif
3481 free(cmean);
3482 free(count);
3483}
3484
3485/*****************************************************************************/
3486
3488 ctl_t * ctl,
3489 clim_t * clim,
3490 met_t * met0,
3491 met_t * met1,
3492 atm_t * atm,
3493 double *dt) {
3494
3495 /* Set timer... */
3496 SELECT_TIMER("MODULE_OHCHEM", "PHYSICS", NVTX_GPU);
3497
3498 /* Check quantity flags... */
3499 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3500 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3501
3502 /* Parameter of SO2 correction... */
3503 const double a = 4.71572206e-08;
3504 const double b = -8.28782867e-01;
3505 const double low = pow(1 / a, 1 / b);
3506
3507 /* Loop over particles... */
3508 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,met0,met1,atm,dt)") {
3509
3510 /* Get temperature... */
3511 double t;
3513 INTPOL_3D(t, 1);
3514
3515 /* Calculate molecular density... */
3516 double M = MOLEC_DENS(atm->p[ip], t);
3517
3518 /* Use constant reaction rate... */
3519 double k = NAN;
3520 if (ctl->oh_chem_reaction == 1)
3521 k = ctl->oh_chem[0];
3522
3523 /* Calculate bimolecular reaction rate... */
3524 else if (ctl->oh_chem_reaction == 2)
3525 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
3526
3527 /* Calculate termolecular reaction rate... */
3528 if (ctl->oh_chem_reaction == 3) {
3529
3530 /* Calculate rate coefficient for X + OH + M -> XOH + M
3531 (JPL Publication 19-05) ... */
3532 double k0 =
3533 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
3534 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
3535 double ki =
3536 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
3537 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
3538 double c = log10(k0 * M / ki);
3539 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
3540 }
3541
3542 /* Correction factor for high SO2 concentration
3543 (if qnt_Cx is defined, the correction is switched on)... */
3544 double cor = 1;
3545 if (ctl->qnt_Cx >= 0)
3546 cor =
3547 atm->q[ctl->qnt_Cx][ip] >
3548 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3549
3550 /* Calculate exponential decay... */
3551 double rate_coef = k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
3552 atm->lat[ip], atm->p[ip]) * M * cor;
3553 double aux = exp(-dt[ip] * rate_coef);
3554 if (ctl->qnt_m >= 0) {
3555 if (ctl->qnt_mloss_oh >= 0)
3556 atm->q[ctl->qnt_mloss_oh][ip]
3557 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3558 atm->q[ctl->qnt_m][ip] *= aux;
3559 if (ctl->qnt_loss_rate >= 0)
3560 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3561 }
3562 if (ctl->qnt_vmr >= 0)
3563 atm->q[ctl->qnt_vmr][ip] *= aux;
3564 }
3565}
3566
3567/*****************************************************************************/
3568
3570 ctl_t * ctl,
3571 met_t * met0,
3572 met_t * met1,
3573 atm_t * atm,
3574 double *dt) {
3575
3576 /* Set timer... */
3577 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
3578
3579 /* Loop over particles... */
3580 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
3581
3582 /* Init... */
3583 double ps;
3585
3586 /* Calculate modulo... */
3587 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
3588 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
3589
3590 /* Check latitude... */
3591 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
3592 if (atm->lat[ip] > 90) {
3593 atm->lat[ip] = 180 - atm->lat[ip];
3594 atm->lon[ip] += 180;
3595 }
3596 if (atm->lat[ip] < -90) {
3597 atm->lat[ip] = -180 - atm->lat[ip];
3598 atm->lon[ip] += 180;
3599 }
3600 }
3601
3602 /* Check longitude... */
3603 while (atm->lon[ip] < -180)
3604 atm->lon[ip] += 360;
3605 while (atm->lon[ip] >= 180)
3606 atm->lon[ip] -= 360;
3607
3608 /* Check pressure... */
3609 if (atm->p[ip] < met0->p[met0->np - 1]) {
3610 if (ctl->reflect)
3611 atm->p[ip] = 2. * met0->p[met0->np - 1] - atm->p[ip];
3612 else
3613 atm->p[ip] = met0->p[met0->np - 1];
3614 } else if (atm->p[ip] > 300.) {
3615 INTPOL_2D(ps, 1);
3616 if (atm->p[ip] > ps) {
3617 if (ctl->reflect)
3618 atm->p[ip] = 2. * ps - atm->p[ip];
3619 else
3620 atm->p[ip] = ps;
3621 }
3622 }
3623 }
3624}
3625
3626/*****************************************************************************/
3627
3629 int ntask) {
3630
3631 /* Initialize GSL random number generators... */
3632 gsl_rng_env_setup();
3633 if (omp_get_max_threads() > NTHREADS)
3634 ERRMSG("Too many threads!");
3635 for (int i = 0; i < NTHREADS; i++) {
3636 rng[i] = gsl_rng_alloc(gsl_rng_default);
3637 gsl_rng_set(rng[i], gsl_rng_default_seed
3638 + (long unsigned) (ntask * NTHREADS + i));
3639 }
3640
3641 /* Initialize cuRAND random number generators... */
3642#ifdef CURAND
3643 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
3644 CURAND_STATUS_SUCCESS)
3645 ERRMSG("Cannot create random number generator!");
3646 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
3647 CURAND_STATUS_SUCCESS)
3648 ERRMSG("Cannot set seed for random number generator!");
3649 if (curandSetStream
3650 (rng_curand,
3651 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
3652 CURAND_STATUS_SUCCESS)
3653 ERRMSG("Cannot set stream for random number generator!");
3654#endif
3655}
3656
3657/*****************************************************************************/
3658
3660 ctl_t * ctl,
3661 double *rs,
3662 size_t n,
3663 int method) {
3664
3665 /* Use GSL random number generators... */
3666 if (ctl->rng_type == 0) {
3667
3668 /* Uniform distribution... */
3669 if (method == 0) {
3670#pragma omp parallel for default(shared)
3671 for (size_t i = 0; i < n; ++i)
3672 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
3673 }
3674
3675 /* Normal distribution... */
3676 else if (method == 1) {
3677#pragma omp parallel for default(shared)
3678 for (size_t i = 0; i < n; ++i)
3679 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
3680 }
3681
3682 /* Update of random numbers on device... */
3683#ifdef _OPENACC
3684#pragma acc update device(rs[:n])
3685#endif
3686 }
3687
3688 /* Use Squares random number generator (Widynski, 2022)... */
3689 else if (ctl->rng_type == 1) {
3690
3691 /* Set key (don't change this!)... */
3692 const uint64_t key = 0xc8e4fd154ce32f6d;
3693
3694 /* Uniform distribution... */
3695#ifdef _OPENACC
3696#pragma acc data present(rs)
3697#pragma acc parallel loop independent gang vector
3698#else
3699#pragma omp parallel for default(shared)
3700#endif
3701 for (size_t i = 0; i < n + 1; ++i) {
3702 uint64_t r, t, x, y, z;
3703 y = x = (rng_ctr + i) * key;
3704 z = y + key;
3705 x = x * x + y;
3706 x = (x >> 32) | (x << 32);
3707 x = x * x + z;
3708 x = (x >> 32) | (x << 32);
3709 x = x * x + y;
3710 x = (x >> 32) | (x << 32);
3711 t = x = x * x + z;
3712 x = (x >> 32) | (x << 32);
3713 r = t ^ ((x * x + y) >> 32);
3714 rs[i] = (double) r / (double) UINT64_MAX;
3715 }
3716 rng_ctr += n + 1;
3717
3718 /* Normal distribution... */
3719 if (method == 1) {
3720#ifdef _OPENACC
3721#pragma acc parallel loop independent gang vector
3722#else
3723#pragma omp parallel for default(shared)
3724#endif
3725 for (size_t i = 0; i < n; i += 2) {
3726 double r = sqrt(-2.0 * log(rs[i]));
3727 double phi = 2.0 * M_PI * rs[i + 1];
3728 rs[i] = r * cosf((float) phi);
3729 rs[i + 1] = r * sinf((float) phi);
3730 }
3731 }
3732 }
3733
3734 /* Use cuRAND random number generators... */
3735 else if (ctl->rng_type == 2) {
3736#ifdef CURAND
3737#pragma acc host_data use_device(rs)
3738 {
3739
3740 /* Uniform distribution... */
3741 if (method == 0) {
3742 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
3743 CURAND_STATUS_SUCCESS)
3744 ERRMSG("Cannot create random numbers!");
3745 }
3746
3747 /* Normal distribution... */
3748 else if (method == 1) {
3749 if (curandGenerateNormalDouble
3750 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
3751 1.0) != CURAND_STATUS_SUCCESS)
3752 ERRMSG("Cannot create random numbers!");
3753 }
3754 }
3755#else
3756 ERRMSG("MPTRAC was compiled without cuRAND!");
3757#endif
3758 }
3759}
3760
3761/*****************************************************************************/
3762
3764 ctl_t * ctl,
3765 met_t * met0,
3766 met_t * met1,
3767 atm_t * atm,
3768 double *dt) {
3769
3770 /* Set timer... */
3771 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
3772
3773 /* Loop over particles... */
3774 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
3775
3776 /* Get temperature... */
3777 double t;
3779 INTPOL_3D(t, 1);
3780
3781 /* Sedimentation velocity... */
3782 double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3783 atm->q[ctl->qnt_rhop][ip]);
3784
3785 /* Calculate pressure change... */
3786 atm->p[ip] += DZ2DP(v_s * dt[ip] / 1000., atm->p[ip]);
3787 }
3788}
3789
3790/*****************************************************************************/
3791
3793 ctl_t * ctl,
3794 met_t * met0,
3795 atm_t * atm) {
3796
3797 /* Set timer... */
3798 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
3799
3800 /* Allocate... */
3801 const int np = atm->np;
3802 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
3803 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
3804
3805#ifdef _OPENACC
3806#pragma acc enter data create(a[0:np],p[0:np])
3807#pragma acc data present(ctl,met0,atm,a,p)
3808#endif
3809
3810 /* Get box index... */
3811#ifdef _OPENACC
3812#pragma acc parallel loop independent gang vector
3813#else
3814#pragma omp parallel for default(shared)
3815#endif
3816 for (int ip = 0; ip < np; ip++) {
3817 a[ip] =
3818 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
3819 locate_reg(met0->lat, met0->ny, atm->lat[ip]))
3820 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
3821 p[ip] = ip;
3822 }
3823
3824 /* Sorting... */
3825#ifdef _OPENACC
3826#pragma acc host_data use_device(a, p)
3827#endif
3828#ifdef THRUST
3829 thrustSortWrapper(a, np, p);
3830#else
3831 ERRMSG("MPTRAC was compiled without Thrust library!");
3832#endif
3833
3834 /* Sort data... */
3835 module_sort_help(atm->time, p, np);
3836 module_sort_help(atm->p, p, np);
3837 module_sort_help(atm->lon, p, np);
3838 module_sort_help(atm->lat, p, np);
3839 for (int iq = 0; iq < ctl->nq; iq++)
3840 module_sort_help(atm->q[iq], p, np);
3841
3842 /* Free... */
3843#ifdef _OPENACC
3844#pragma acc exit data delete(a,p)
3845#endif
3846 free(a);
3847 free(p);
3848}
3849
3850/*****************************************************************************/
3851
3853 double *a,
3854 const int *p,
3855 const int np) {
3856
3857 /* Allocate... */
3858 double *restrict const help =
3859 (double *) malloc((size_t) np * sizeof(double));
3860
3861 /* Reordering of array... */
3862#ifdef _OPENACC
3863#pragma acc enter data create(help[0:np])
3864#pragma acc data present(a,p,help)
3865#pragma acc parallel loop independent gang vector
3866#else
3867#pragma omp parallel for default(shared)
3868#endif
3869 for (int ip = 0; ip < np; ip++)
3870 help[ip] = a[p[ip]];
3871#ifdef _OPENACC
3872#pragma acc parallel loop independent gang vector
3873#else
3874#pragma omp parallel for default(shared)
3875#endif
3876 for (int ip = 0; ip < np; ip++)
3877 a[ip] = help[ip];
3878
3879 /* Free... */
3880#ifdef _OPENACC
3881#pragma acc exit data delete(help)
3882#endif
3883 free(help);
3884}
3885
3886/*****************************************************************************/
3887
3889 ctl_t * ctl,
3890 met_t * met0,
3891 atm_t * atm,
3892 double *dt,
3893 double t) {
3894
3895 /* Set timer... */
3896 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
3897
3898 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
3899 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
3900
3901 const int local =
3902 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
3903
3904 /* Loop over particles... */
3905 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,atm,met0,dt)") {
3906
3907 /* Set time step for each air parcel... */
3908 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
3909 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
3910 && ctl->direction * (atm->time[ip] - t) < 0))
3911 dt[ip] = t - atm->time[ip];
3912 else
3913 dt[ip] = 0.0;
3914
3915 /* Check horizontal boundaries of local meteo data... */
3916 if (local && (atm->lon[ip] <= met0->lon[0]
3917 || atm->lon[ip] >= met0->lon[met0->nx - 1]
3918 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
3919 dt[ip] = 0.0;
3920 }
3921}
3922
3923/*****************************************************************************/
3924
3926 ctl_t * ctl,
3927 atm_t * atm) {
3928
3929 /* Set timer... */
3930 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
3931
3932 /* Set start time... */
3933 if (ctl->direction == 1) {
3934 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3935 if (ctl->t_stop > 1e99)
3936 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3937 } else {
3938 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3939 if (ctl->t_stop > 1e99)
3940 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3941 }
3942
3943 /* Check time interval... */
3944 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
3945 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
3946
3947 /* Round start time... */
3948 if (ctl->direction == 1)
3949 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
3950 else
3951 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
3952}
3953
3954/*****************************************************************************/
3955
3957 ctl_t * ctl,
3958 clim_t * clim,
3959 met_t * met0,
3960 met_t * met1,
3961 atm_t * atm,
3962 double *dt) {
3963
3964 /* Set timer... */
3965 SELECT_TIMER("MODULE_TRACERCHEM", "PHYSICS", NVTX_GPU);
3966
3967 /* Loop over particles... */
3968 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,clim,met0,atm,met1,dt)") {
3969
3970 /* Get temperature... */
3971 double t;
3973 INTPOL_3D(t, 1);
3974
3975 /* Get molecular density... */
3976 double M = MOLEC_DENS(atm->p[ip], t);
3977
3978 /* Get total column ozone... */
3979 double o3c;
3980 INTPOL_2D(o3c, 1);
3981
3982 /* Get solar zenith angle... */
3983 double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
3984
3985 /* Get O(1D) volume mixing ratio... */
3986 double o1d = clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
3987
3988 /* Reactions for CFC-10... */
3989 if (ctl->qnt_Cccl4 >= 0) {
3990 double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
3991 double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
3992 atm->p[ip], sza, o3c);
3993 atm->q[ctl->qnt_Cccl4][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
3994 }
3995
3996 /* Reactions for CFC-11... */
3997 if (ctl->qnt_Cccl3f >= 0) {
3998 double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
3999 double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4000 atm->p[ip], sza, o3c);
4001 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
4002 }
4003
4004 /* Reactions for CFC-12... */
4005 if (ctl->qnt_Cccl2f2 >= 0) {
4006 double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4007 double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4008 atm->p[ip], sza, o3c);
4009 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
4010 }
4011
4012 /* Reactions for N2O... */
4013 if (ctl->qnt_Cn2o >= 0) {
4014 double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4015 double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4016 atm->p[ip], sza, o3c);
4017 atm->q[ctl->qnt_Cn2o][ip] *= exp(-dt[ip] * (K_hv + K_o1d));
4018 }
4019 }
4020}
4021
4022/*****************************************************************************/
4023
4025 ctl_t * ctl,
4026 met_t * met0,
4027 met_t * met1,
4028 atm_t * atm,
4029 double *dt) {
4030
4031 /* Set timer... */
4032 SELECT_TIMER("MODULE_WETDEPO", "PHYSICS", NVTX_GPU);
4033
4034 /* Check quantity flags... */
4035 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4036 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4037
4038 /* Loop over particles... */
4039 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,met0,met1,atm,dt)") {
4040
4041 /* Check whether particle is below cloud top... */
4042 double pct;
4044 INTPOL_2D(pct, 1);
4045 if (!isfinite(pct) || atm->p[ip] <= pct)
4046 continue;
4047
4048 /* Get cloud bottom pressure... */
4049 double pcb;
4050 INTPOL_2D(pcb, 0);
4051
4052 /* Estimate precipitation rate (Pisso et al., 2019)... */
4053 double cl;
4054 INTPOL_2D(cl, 0);
4055 double Is =
4056 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4057 if (Is < 0.01)
4058 continue;
4059
4060 /* Check whether particle is inside or below cloud... */
4061 double lwc, rwc, iwc, swc;
4062 INTPOL_3D(lwc, 1);
4063 INTPOL_3D(rwc, 0);
4064 INTPOL_3D(iwc, 0);
4065 INTPOL_3D(swc, 0);
4066 int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4067
4068 /* Get temperature... */
4069 double t;
4070 INTPOL_3D(t, 0);
4071
4072 /* Calculate in-cloud scavenging coefficient... */
4073 double lambda = 0;
4074 if (inside) {
4075
4076 /* Calculate retention factor... */
4077 double eta;
4078 if (t > 273.15)
4079 eta = 1;
4080 else if (t <= 238.15)
4081 eta = ctl->wet_depo_ic_ret_ratio;
4082 else
4083 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4084
4085 /* Use exponential dependency for particles ... */
4086 if (ctl->wet_depo_ic_a > 0)
4087 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4088
4089 /* Use Henry's law for gases... */
4090 else if (ctl->wet_depo_ic_h[0] > 0) {
4091
4092 /* Get Henry's constant (Sander, 2015)... */
4093 double h = ctl->wet_depo_ic_h[0]
4094 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4095
4096 /* Use effective Henry's constant for SO2
4097 (Berglen, 2004; Simpson, 2012)... */
4098 if (ctl->wet_depo_ic_h[2] > 0) {
4099 double H_ion = pow(10, ctl->wet_depo_ic_h[2] * (-1));
4100 double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4101 double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4102 h *= (1 + K_1 / H_ion + K_1 * K_2 / pow(H_ion, 2));
4103 }
4104
4105 /* Estimate depth of cloud layer... */
4106 double dz = 1e3 * (Z(pct) - Z(pcb));
4107
4108 /* Calculate scavenging coefficient (Draxler and Hess, 1997)... */
4109 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4110 }
4111 }
4112
4113 /* Calculate below-cloud scavenging coefficient... */
4114 else {
4115
4116 /* Calculate retention factor... */
4117 double eta;
4118 if (t > 270)
4119 eta = 1;
4120 else
4121 eta = ctl->wet_depo_bc_ret_ratio;
4122
4123 /* Use exponential dependency for particles... */
4124 if (ctl->wet_depo_bc_a > 0)
4125 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4126
4127 /* Use Henry's law for gases... */
4128 else if (ctl->wet_depo_bc_h[0] > 0) {
4129
4130 /* Get Henry's constant (Sander, 2015)... */
4131 double h = ctl->wet_depo_bc_h[0]
4132 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4133
4134 /* Estimate depth of cloud layer... */
4135 double dz = 1e3 * (Z(pct) - Z(pcb));
4136
4137 /* Calculate scavenging coefficient (Draxler and Hess, 1997)... */
4138 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4139 }
4140 }
4141
4142 /* Calculate exponential decay of mass... */
4143 double aux = exp(-dt[ip] * lambda);
4144 if (ctl->qnt_m >= 0) {
4145 if (ctl->qnt_mloss_wet >= 0)
4146 atm->q[ctl->qnt_mloss_wet][ip]
4147 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4148 atm->q[ctl->qnt_m][ip] *= aux;
4149 if (ctl->qnt_loss_rate >= 0)
4150 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4151 }
4152 if (ctl->qnt_vmr >= 0)
4153 atm->q[ctl->qnt_vmr][ip] *= aux;
4154 }
4155}
4156
4157/*****************************************************************************/
4158
4160 const double p,
4161 const double h2o,
4162 const double hno3) {
4163
4164 /* Check water vapor volume mixing ratio... */
4165 double h2o_help = MAX(h2o, 0.1e-6);
4166
4167 /* Calculate T_NAT... */
4168 double p_hno3 = hno3 * p / 1.333224;
4169 double p_h2o = h2o_help * p / 1.333224;
4170 double a = 0.009179 - 0.00088 * log10(p_h2o);
4171 double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
4172 double c = -11397.0 / a;
4173 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
4174 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
4175 if (x2 > 0)
4176 tnat = x2;
4177
4178 return tnat;
4179}
4180
4181/*****************************************************************************/
4182
4184 const char *filename,
4185 ctl_t * ctl,
4186 atm_t * atm) {
4187
4188 int result;
4189
4190 /* Set timer... */
4191 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
4192
4193 /* Init... */
4194 atm->np = 0;
4195
4196 /* Write info... */
4197 LOG(1, "Read atmospheric data: %s", filename);
4198
4199 /* Read ASCII data... */
4200 if (ctl->atm_type == 0)
4201 result = read_atm_asc(filename, ctl, atm);
4202
4203 /* Read binary data... */
4204 else if (ctl->atm_type == 1)
4205 result = read_atm_bin(filename, ctl, atm);
4206
4207 /* Read netCDF data... */
4208 else if (ctl->atm_type == 2)
4209 result = read_atm_nc(filename, ctl, atm);
4210
4211 /* Read CLaMS data... */
4212 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
4213 result = read_atm_clams(filename, ctl, atm);
4214
4215 /* Error... */
4216 else
4217 ERRMSG("Atmospheric data type not supported!");
4218
4219 /* Check result... */
4220 if (result != 1)
4221 return 0;
4222
4223 /* Check number of air parcels... */
4224 if (atm->np < 1)
4225 ERRMSG("Can not read any data!");
4226
4227 /* Write info... */
4228 double mini, maxi;
4229 LOG(2, "Number of particles: %d", atm->np);
4230 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
4231 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
4232 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
4233 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
4234 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
4235 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
4236 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
4237 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
4238 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
4239 for (int iq = 0; iq < ctl->nq; iq++) {
4240 char msg[5 * LEN];
4241 sprintf(msg, "Quantity %s range: %s ... %s %s",
4242 ctl->qnt_name[iq], ctl->qnt_format[iq],
4243 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
4244 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
4245 LOG(2, msg, mini, maxi);
4246 }
4247
4248 /* Return success... */
4249 return 1;
4250}
4251
4252/*****************************************************************************/
4253
4255 const char *filename,
4256 ctl_t * ctl,
4257 atm_t * atm) {
4258
4259 /* Open file... */
4260 FILE *in;
4261 if (!(in = fopen(filename, "r"))) {
4262 WARN("Cannot open file!");
4263 return 0;
4264 }
4265
4266 /* Read line... */
4267 char line[LEN];
4268 while (fgets(line, LEN, in)) {
4269
4270 /* Read data... */
4271 char *tok;
4272 TOK(line, tok, "%lg", atm->time[atm->np]);
4273 TOK(NULL, tok, "%lg", atm->p[atm->np]);
4274 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
4275 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
4276 for (int iq = 0; iq < ctl->nq; iq++)
4277 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
4278
4279 /* Convert altitude to pressure... */
4280 atm->p[atm->np] = P(atm->p[atm->np]);
4281
4282 /* Increment data point counter... */
4283 if ((++atm->np) > NP)
4284 ERRMSG("Too many data points!");
4285 }
4286
4287 /* Close file... */
4288 fclose(in);
4289
4290 /* Return success... */
4291 return 1;
4292}
4293
4294/*****************************************************************************/
4295
4297 const char *filename,
4298 ctl_t * ctl,
4299 atm_t * atm) {
4300
4301 /* Open file... */
4302 FILE *in;
4303 if (!(in = fopen(filename, "r")))
4304 return 0;
4305
4306 /* Check version of binary data... */
4307 int version;
4308 FREAD(&version, int,
4309 1,
4310 in);
4311 if (version != 100)
4312 ERRMSG("Wrong version of binary data!");
4313
4314 /* Read data... */
4315 FREAD(&atm->np, int,
4316 1,
4317 in);
4318 FREAD(atm->time, double,
4319 (size_t) atm->np,
4320 in);
4321 FREAD(atm->p, double,
4322 (size_t) atm->np,
4323 in);
4324 FREAD(atm->lon, double,
4325 (size_t) atm->np,
4326 in);
4327 FREAD(atm->lat, double,
4328 (size_t) atm->np,
4329 in);
4330 for (int iq = 0; iq < ctl->nq; iq++)
4331 FREAD(atm->q[iq], double,
4332 (size_t) atm->np,
4333 in);
4334
4335 /* Read final flag... */
4336 int final;
4337 FREAD(&final, int,
4338 1,
4339 in);
4340 if (final != 999)
4341 ERRMSG("Error while reading binary data!");
4342
4343 /* Close file... */
4344 fclose(in);
4345
4346 /* Return success... */
4347 return 1;
4348}
4349
4350/*****************************************************************************/
4351
4353 const char *filename,
4354 ctl_t * ctl,
4355 atm_t * atm) {
4356
4357 int ncid, varid;
4358
4359 /* Open file... */
4360 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
4361 return 0;
4362
4363 /* Get dimensions... */
4364 NC_INQ_DIM("NPARTS", &atm->np, 1, NP);
4365
4366 /* Get time... */
4367 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
4368 NC(nc_get_var_double(ncid, varid, atm->time));
4369 } else {
4370 WARN("TIME_INIT not found use time instead!");
4371 double time_init;
4372 NC_GET_DOUBLE("time", &time_init, 1);
4373 for (int ip = 0; ip < atm->np; ip++) {
4374 atm->time[ip] = time_init;
4375 }
4376 }
4377
4378 /* Read zeta coordinate, pressure is optional... */
4379 if (ctl->advect_vert_coord == 1) {
4380 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
4381 NC_GET_DOUBLE("PRESS", atm->p, 0);
4382 }
4383
4384 /* Read pressure, zeta coordinate is optional... */
4385 else {
4386 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
4387 NC(nc_get_var_double(ncid, varid, atm->p));
4388 } else {
4389 WARN("PRESS_INIT not found use PRESS instead!");
4390 nc_inq_varid(ncid, "PRESS", &varid);
4391 NC(nc_get_var_double(ncid, varid, atm->p));
4392 }
4393 }
4394
4395 /* Read longitude and latitude... */
4396 NC_GET_DOUBLE("LON", atm->lon, 1);
4397 NC_GET_DOUBLE("LAT", atm->lat, 1);
4398
4399 /* Close file... */
4400 NC(nc_close(ncid));
4401
4402 /* Return success... */
4403 return 1;
4404}
4405
4406/*****************************************************************************/
4407
4409 const char *filename,
4410 ctl_t * ctl,
4411 atm_t * atm) {
4412
4413 int ncid, varid;
4414
4415 /* Open file... */
4416 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
4417 return 0;
4418
4419 /* Get dimensions... */
4420 NC_INQ_DIM("obs", &atm->np, 1, NP);
4421
4422 /* Read geolocations... */
4423 NC_GET_DOUBLE("time", atm->time, 1);
4424 NC_GET_DOUBLE("press", atm->p, 1);
4425 NC_GET_DOUBLE("lon", atm->lon, 1);
4426 NC_GET_DOUBLE("lat", atm->lat, 1);
4427
4428 /* Read variables... */
4429 for (int iq = 0; iq < ctl->nq; iq++)
4430 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
4431
4432 /* Close file... */
4433 NC(nc_close(ncid));
4434
4435 /* Return success... */
4436 return 1;
4437}
4438
4439/*****************************************************************************/
4440
4442 ctl_t * ctl,
4443 clim_t * clim) {
4444
4445 /* Set timer... */
4446 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
4447
4448 /* Init tropopause climatology... */
4449 clim_tropo_init(clim);
4450
4451 /* Read photolysis rates... */
4452 if (ctl->clim_photo[0] != '-')
4453 read_clim_photo(ctl->clim_photo, &clim->photo);
4454
4455 /* Read HNO3 climatology... */
4456 if (ctl->clim_hno3_filename[0] != '-')
4457 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
4458
4459 /* Read OH climatology... */
4460 if (ctl->clim_oh_filename[0] != '-') {
4461 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
4462 if (ctl->oh_chem_beta > 0)
4463 clim_oh_diurnal_correction(ctl, clim);
4464 }
4465
4466 /* Read H2O2 climatology... */
4467 if (ctl->clim_h2o2_filename[0] != '-')
4468 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
4469
4470 /* Read HO2 climatology... */
4471 if (ctl->clim_ho2_filename[0] != '-')
4472 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
4473
4474 /* Read O(1D) climatology... */
4475 if (ctl->clim_o1d_filename[0] != '-')
4476 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
4477
4478 /* Read CFC-10 time series... */
4479 if (ctl->clim_ccl4_timeseries[0] != '-')
4481
4482 /* Read CFC-11 time series... */
4483 if (ctl->clim_ccl3f_timeseries[0] != '-')
4485
4486 /* Read CFC-12 time series... */
4487 if (ctl->clim_ccl2f2_timeseries[0] != '-')
4489
4490 /* Read N2O time series... */
4491 if (ctl->clim_n2o_timeseries[0] != '-')
4492 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
4493
4494 /* Read SF6 time series... */
4495 if (ctl->clim_sf6_timeseries[0] != '-')
4496 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
4497}
4498
4499/*****************************************************************************/
4500
4502 const char *filename,
4503 clim_photo_t * photo) {
4504
4505 int ncid, varid, ip, is, io;
4506
4507 double *help1, *help2, *help3, *help4;
4508
4509 /* Write info... */
4510 LOG(1, "Read photolysis rates: %s", filename);
4511
4512 /* Open netCDF file... */
4513 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
4514 WARN("Photolysis rate data are missing!");
4515 return;
4516 }
4517
4518 /* Read pressure data... */
4519 NC_INQ_DIM("press", &photo->np, 2, CP);
4520 NC_GET_DOUBLE("press", photo->p, 1);
4521 if (photo->p[0] < photo->p[1])
4522 ERRMSG("Pressure data are not descending!");
4523
4524 /* Read total column ozone data... */
4525 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3);
4526 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
4527 if (photo->o3c[0] > photo->o3c[1])
4528 ERRMSG("Total column ozone data are not ascending!");
4529
4530 /* Read solar zenith angle data... */
4531 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA);
4532 NC_GET_DOUBLE("sza", photo->sza, 1);
4533 if (photo->sza[0] > photo->sza[1])
4534 ERRMSG("Solar zenith angle data are not ascending!");
4535
4536 /* Read data... */
4537 ALLOC(help1, double,
4538 photo->np * photo->nsza * photo->no3c);
4539 ALLOC(help2, double,
4540 photo->np * photo->nsza * photo->no3c);
4541 ALLOC(help3, double,
4542 photo->np * photo->nsza * photo->no3c);
4543 ALLOC(help4, double,
4544 photo->np * photo->nsza * photo->no3c);
4545 NC_GET_DOUBLE("J_N2O", help1, 1);
4546 NC_GET_DOUBLE("J_CCl4", help2, 1);
4547 NC_GET_DOUBLE("J_CFC-11", help3, 1);
4548 NC_GET_DOUBLE("J_CFC-12", help4, 1);
4549 for (ip = 0; ip < photo->np; ip++)
4550 for (is = 0; is < photo->nsza; is++)
4551 for (io = 0; io < photo->no3c; io++) {
4552 photo->n2o[ip][is][io] =
4553 help1[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4554 photo->ccl4[ip][is][io] =
4555 help2[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4556 photo->ccl3f[ip][is][io] =
4557 help3[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4558 photo->ccl2f2[ip][is][io] =
4559 help4[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4560 }
4561
4562 NC_GET_DOUBLE("J_O2", help1, 1);
4563 NC_GET_DOUBLE("J_O3b", help2, 1);
4564 NC_GET_DOUBLE("J_O3a", help3, 1);
4565 NC_GET_DOUBLE("J_H2O2", help4, 1);
4566 for (ip = 0; ip < photo->np; ip++)
4567 for (is = 0; is < photo->nsza; is++)
4568 for (io = 0; io < photo->no3c; io++) {
4569 photo->o2[ip][is][io] =
4570 help1[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4571 photo->o3_1[ip][is][io] =
4572 help2[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4573 photo->o3_2[ip][is][io] =
4574 help3[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4575 photo->h2o2[ip][is][io] =
4576 help4[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4577 }
4578 NC_GET_DOUBLE("J_H2O", help1, 1);
4579 for (ip = 0; ip < photo->np; ip++)
4580 for (is = 0; is < photo->nsza; is++)
4581 for (io = 0; io < photo->no3c; io++)
4582 photo->h2o[ip][is][io] =
4583 help1[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4584 free(help1);
4585 free(help2);
4586 free(help3);
4587 free(help4);
4588
4589 /* Close netCDF file... */
4590 NC(nc_close(ncid));
4591
4592 /* Write info... */
4593 LOG(2, "Number of pressure levels: %d", photo->np);
4594 LOG(2, "Altitude levels: %g, %g ... %g km",
4595 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
4596 LOG(2, "Pressure levels: %g, %g ... %g hPa",
4597 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
4598 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
4599 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
4600 photo->sza[0] * 180. / M_PI, photo->sza[1] * 180. / M_PI,
4601 photo->sza[photo->nsza - 1] * 180. / M_PI);
4602 LOG(2, "Number of total column ozone values: %d", photo->no3c);
4603 LOG(2, "Total column ozone: %g, %g ... %g DU",
4604 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
4605 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
4606 photo->n2o[0][0][0], photo->n2o[1][0][0],
4607 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4608 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
4609 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
4610 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4611 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
4612 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
4613 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4614 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
4615 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
4616 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4617 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
4618 photo->o2[0][0][0], photo->o2[1][0][0],
4619 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4620 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
4621 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
4622 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4623 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
4624 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
4625 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4626 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
4627 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
4628 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4629 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
4630 photo->h2o[0][0][0], photo->h2o[1][0][0],
4631 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4632}
4633
4634/*****************************************************************************/
4635
4637 const char *filename,
4638 clim_ts_t * ts) {
4639
4640 /* Write info... */
4641 LOG(1, "Read climatological time series: %s", filename);
4642
4643 /* Open file... */
4644 FILE *in;
4645 if (!(in = fopen(filename, "r"))) {
4646 WARN("Cannot open file!");
4647 return 0;
4648 }
4649
4650 /* Read data... */
4651 char line[LEN];
4652 int nh = 0;
4653 while (fgets(line, LEN, in))
4654 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
4655
4656 /* Convert years to seconds... */
4657 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
4658
4659 /* Check data... */
4660 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
4661 ERRMSG("Time series must be ascending!");
4662
4663 /* Count time steps... */
4664 if ((++nh) >= CTS)
4665 ERRMSG("Too many data points!");
4666 }
4667
4668 /* Close file... */
4669 fclose(in);
4670
4671 /* Check number of data points... */
4672 ts->ntime = nh;
4673 if (nh < 2)
4674 ERRMSG("Not enough data points!");
4675
4676 /* Write info... */
4677 LOG(2, "Number of time steps: %d", ts->ntime);
4678 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
4679 ts->time[nh - 1]);
4680 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
4681 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
4682 (size_t) nh));
4683
4684 /* Exit success... */
4685 return 1;
4686}
4687
4688/*****************************************************************************/
4689
4691 const char *filename,
4692 char *varname,
4693 clim_zm_t * zm) {
4694
4695 int ncid, varid, it, iy, iz, iz2, nt;
4696
4697 double *help, varmin = 1e99, varmax = -1e99;
4698
4699 /* Write info... */
4700 LOG(1, "Read %s data: %s", varname, filename);
4701
4702 /* Open netCDF file... */
4703 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
4704 WARN("%s climatology data are missing!", varname);
4705 return;
4706 }
4707
4708 /* Read pressure data... */
4709 NC_INQ_DIM("press", &zm->np, 2, CP);
4710 NC_GET_DOUBLE("press", zm->p, 1);
4711 if (zm->p[0] < zm->p[1])
4712 ERRMSG("Pressure data are not descending!");
4713
4714 /* Read latitudes... */
4715 NC_INQ_DIM("lat", &zm->nlat, 2, CY);
4716 NC_GET_DOUBLE("lat", zm->lat, 1);
4717 if (zm->lat[0] > zm->lat[1])
4718 ERRMSG("Latitude data are not ascending!");
4719
4720 /* Set time data (for monthly means)... */
4721 zm->ntime = 12;
4722 zm->time[0] = 1209600.00;
4723 zm->time[1] = 3888000.00;
4724 zm->time[2] = 6393600.00;
4725 zm->time[3] = 9072000.00;
4726 zm->time[4] = 11664000.00;
4727 zm->time[5] = 14342400.00;
4728 zm->time[6] = 16934400.00;
4729 zm->time[7] = 19612800.00;
4730 zm->time[8] = 22291200.00;
4731 zm->time[9] = 24883200.00;
4732 zm->time[10] = 27561600.00;
4733 zm->time[11] = 30153600.00;
4734
4735 /* Check number of timesteps... */
4736 NC_INQ_DIM("time", &nt, 12, 12);
4737
4738 /* Read data... */
4739 ALLOC(help, double,
4740 zm->nlat * zm->np * zm->ntime);
4741 NC_GET_DOUBLE(varname, help, 1);
4742 for (it = 0; it < zm->ntime; it++)
4743 for (iz = 0; iz < zm->np; iz++)
4744 for (iy = 0; iy < zm->nlat; iy++)
4745 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
4746 free(help);
4747
4748 /* Fix data gaps... */
4749 for (it = 0; it < zm->ntime; it++)
4750 for (iy = 0; iy < zm->nlat; iy++)
4751 for (iz = 0; iz < zm->np; iz++) {
4752 if (zm->vmr[it][iz][iy] < 0) {
4753 for (iz2 = 0; iz2 < zm->np; iz2++)
4754 if (zm->vmr[it][iz2][iy] >= 0) {
4755 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
4756 break;
4757 }
4758 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
4759 if (zm->vmr[it][iz2][iy] >= 0) {
4760 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
4761 break;
4762 }
4763 }
4764 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
4765 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
4766 }
4767
4768 /* Close netCDF file... */
4769 NC(nc_close(ncid));
4770
4771 /* Write info... */
4772 LOG(2, "Number of time steps: %d", zm->ntime);
4773 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
4774 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
4775 LOG(2, "Number of pressure levels: %d", zm->np);
4776 LOG(2, "Altitude levels: %g, %g ... %g km",
4777 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
4778 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
4779 zm->p[1], zm->p[zm->np - 1]);
4780 LOG(2, "Number of latitudes: %d", zm->nlat);
4781 LOG(2, "Latitudes: %g, %g ... %g deg",
4782 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
4783 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
4784 varmax);
4785}
4786
4787/*****************************************************************************/
4788
4790 const char *filename,
4791 int argc,
4792 char *argv[],
4793 ctl_t * ctl) {
4794
4795 /* Set timer... */
4796 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
4797
4798 /* Write info... */
4799 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
4800 "(executable: %s | version: %s | compiled: %s, %s)\n",
4801 argv[0], VERSION, __DATE__, __TIME__);
4802
4803 /* Initialize quantity indices... */
4804 ctl->qnt_idx = -1;
4805 ctl->qnt_ens = -1;
4806 ctl->qnt_stat = -1;
4807 ctl->qnt_m = -1;
4808 ctl->qnt_vmr = -1;
4809 ctl->qnt_rp = -1;
4810 ctl->qnt_rhop = -1;
4811 ctl->qnt_ps = -1;
4812 ctl->qnt_ts = -1;
4813 ctl->qnt_zs = -1;
4814 ctl->qnt_us = -1;
4815 ctl->qnt_vs = -1;
4816 ctl->qnt_lsm = -1;
4817 ctl->qnt_sst = -1;
4818 ctl->qnt_pbl = -1;
4819 ctl->qnt_pt = -1;
4820 ctl->qnt_tt = -1;
4821 ctl->qnt_zt = -1;
4822 ctl->qnt_h2ot = -1;
4823 ctl->qnt_zg = -1;
4824 ctl->qnt_p = -1;
4825 ctl->qnt_t = -1;
4826 ctl->qnt_rho = -1;
4827 ctl->qnt_u = -1;
4828 ctl->qnt_v = -1;
4829 ctl->qnt_w = -1;
4830 ctl->qnt_h2o = -1;
4831 ctl->qnt_o3 = -1;
4832 ctl->qnt_lwc = -1;
4833 ctl->qnt_rwc = -1;
4834 ctl->qnt_iwc = -1;
4835 ctl->qnt_swc = -1;
4836 ctl->qnt_cc = -1;
4837 ctl->qnt_pct = -1;
4838 ctl->qnt_pcb = -1;
4839 ctl->qnt_cl = -1;
4840 ctl->qnt_plcl = -1;
4841 ctl->qnt_plfc = -1;
4842 ctl->qnt_pel = -1;
4843 ctl->qnt_cape = -1;
4844 ctl->qnt_cin = -1;
4845 ctl->qnt_o3c = -1;
4846 ctl->qnt_hno3 = -1;
4847 ctl->qnt_oh = -1;
4848 ctl->qnt_h2o2 = -1;
4849 ctl->qnt_ho2 = -1;
4850 ctl->qnt_o1d = -1;
4851 ctl->qnt_mloss_oh = -1;
4852 ctl->qnt_mloss_h2o2 = -1;
4853 ctl->qnt_mloss_kpp = -1;
4854 ctl->qnt_mloss_wet = -1;
4855 ctl->qnt_mloss_dry = -1;
4856 ctl->qnt_mloss_decay = -1;
4857 ctl->qnt_loss_rate = -1;
4858 ctl->qnt_psat = -1;
4859 ctl->qnt_psice = -1;
4860 ctl->qnt_pw = -1;
4861 ctl->qnt_sh = -1;
4862 ctl->qnt_rh = -1;
4863 ctl->qnt_rhice = -1;
4864 ctl->qnt_theta = -1;
4865 ctl->qnt_zeta = -1;
4866 ctl->qnt_zeta_d = -1;
4867 ctl->qnt_tvirt = -1;
4868 ctl->qnt_lapse = -1;
4869 ctl->qnt_vh = -1;
4870 ctl->qnt_vz = -1;
4871 ctl->qnt_pv = -1;
4872 ctl->qnt_tdew = -1;
4873 ctl->qnt_tice = -1;
4874 ctl->qnt_tsts = -1;
4875 ctl->qnt_tnat = -1;
4876 ctl->qnt_Cx = -1;
4877 ctl->qnt_Ch2o = -1;
4878 ctl->qnt_Co3 = -1;
4879 ctl->qnt_Cco = -1;
4880 ctl->qnt_Coh = -1;
4881 ctl->qnt_Ch = -1;
4882 ctl->qnt_Cho2 = -1;
4883 ctl->qnt_Ch2o2 = -1;
4884 ctl->qnt_Co1d = -1;
4885 ctl->qnt_Co3p = -1;
4886 ctl->qnt_Cccl4 = -1;
4887 ctl->qnt_Cccl3f = -1;
4888 ctl->qnt_Cccl2f2 = -1;
4889 ctl->qnt_Cn2o = -1;
4890 ctl->qnt_Csf6 = -1;
4891 ctl->qnt_aoa = -1;
4892
4893 /* Read quantities... */
4894 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
4895 if (ctl->nq > NQ)
4896 ERRMSG("Too many quantities!");
4897 for (int iq = 0; iq < ctl->nq; iq++) {
4898
4899 /* Read quantity name and format... */
4900 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
4901 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
4902 ctl->qnt_longname[iq]);
4903 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
4904 ctl->qnt_format[iq]);
4905 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
4906 sprintf(ctl->qnt_format[iq], "%%.2f");
4907
4908 /* Try to identify quantity... */
4909 SET_QNT(qnt_idx, "idx", "particle index", "-")
4910 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
4911 SET_QNT(qnt_stat, "stat", "station flag", "-")
4912 SET_QNT(qnt_m, "m", "mass", "kg")
4913 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
4914 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
4915 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
4916 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
4917 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
4918 SET_QNT(qnt_zs, "zs", "surface height", "km")
4919 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
4920 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
4921 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
4922 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
4923 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
4924 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
4925 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
4926 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
4927 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
4928 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
4929 SET_QNT(qnt_p, "p", "pressure", "hPa")
4930 SET_QNT(qnt_t, "t", "temperature", "K")
4931 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
4932 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
4933 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
4934 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
4935 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
4936 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
4937 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
4938 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
4939 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
4940 SET_QNT(qnt_swc, "iwc", "cloud snow water content", "kg/kg")
4941 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
4942 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
4943 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
4944 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
4945 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
4946 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
4947 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
4948 SET_QNT(qnt_cape, "cape", "convective available potential energy",
4949 "J/kg")
4950 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
4951 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
4952 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
4953 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
4954 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
4955 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
4956 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
4957 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
4958 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2", "mass loss due to H2O2 chemistry",
4959 "kg")
4960 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
4961 "kg")
4962 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
4963 "kg")
4964 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
4965 "kg")
4966 SET_QNT(qnt_mloss_decay, "mloss_decay",
4967 "mass loss due to exponential decay", "kg")
4968 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
4969 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
4970 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
4971 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
4972 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
4973 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
4974 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
4975 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
4976 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
4977 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
4978 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
4979 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
4980 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
4981 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
4982 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
4983 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
4984 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
4985 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
4986 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
4987 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
4988 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
4989 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
4990 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
4991 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
4992 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
4993 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
4994 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
4995 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
4996 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
4997 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
4998 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
4999 "ppv")
5000 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
5001 "ppv")
5002 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
5003 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
5004 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
5005 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
5006 }
5007
5008 /* Vertical coordinates and velocities... */
5009 ctl->advect_vert_coord =
5010 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
5011 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 2)
5012 ERRMSG("Set advect_vert_coord to 0, 1, or 2!");
5013 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
5014 ERRMSG("Please add zeta to your quantities for diabatic calculations!");
5015 ctl->met_vert_coord =
5016 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
5017 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord != 1)
5018 ERRMSG
5019 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
5020 ctl->met_clams =
5021 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
5023 (int) scan_ctl(filename, argc, argv, "ADVECT_ZETA_PRESS_MODULES", -1, "1",
5024 NULL);
5025
5026 /* Time steps of simulation... */
5027 ctl->direction =
5028 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
5029 if (ctl->direction != -1 && ctl->direction != 1)
5030 ERRMSG("Set DIRECTION to -1 or 1!");
5031 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
5032 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
5033
5034 /* Meteo data... */
5035 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
5036 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
5037 ctl->met_convention =
5038 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
5039 ctl->met_type =
5040 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
5041 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
5042 ERRMSG
5043 ("Please use meteorological files in netcdf format for diabatic calculations.");
5044 ctl->met_nc_scale =
5045 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
5046 ctl->met_zfp_prec =
5047 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", -1, "8", NULL);
5048 ctl->met_zfp_tol_t =
5049 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_T", -1, "5.0", NULL);
5050 ctl->met_zfp_tol_z =
5051 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_Z", -1, "0.5", NULL);
5052 ctl->met_cms_heur =
5053 (int) scan_ctl(filename, argc, argv, "MET_CMS_HEUR", -1, "1", NULL);
5054 ctl->met_cms_eps_z =
5055 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
5056 ctl->met_cms_eps_t =
5057 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
5058 ctl->met_cms_eps_u =
5059 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
5060 ctl->met_cms_eps_v =
5061 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
5062 ctl->met_cms_eps_w =
5063 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
5064 ctl->met_cms_eps_pv =
5065 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
5066 ctl->met_cms_eps_h2o =
5067 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
5068 ctl->met_cms_eps_o3 =
5069 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
5070 ctl->met_cms_eps_lwc =
5071 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
5072 ctl->met_cms_eps_rwc =
5073 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
5074 ctl->met_cms_eps_iwc =
5075 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
5076 ctl->met_cms_eps_swc =
5077 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
5078 ctl->met_cms_eps_cc =
5079 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
5080 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
5081 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
5082 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
5083 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
5084 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
5085 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
5086 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
5087 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
5088 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
5089 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
5090 ctl->met_detrend =
5091 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
5092 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
5093 if (ctl->met_np > EP)
5094 ERRMSG("Too many levels!");
5095 ctl->met_press_level_def =
5096 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
5097 NULL);
5098 if (ctl->met_press_level_def >= 0) {
5099 level_definitions(ctl);
5100 } else {
5101 if (ctl->met_np > 0) {
5102 for (int ip = 0; ip < ctl->met_np; ip++)
5103 ctl->met_p[ip] =
5104 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
5105 }
5106 }
5107 ctl->met_geopot_sx
5108 = (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
5109 ctl->met_geopot_sy
5110 = (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
5111 ctl->met_relhum
5112 = (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
5113 ctl->met_tropo =
5114 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
5115 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
5116 ERRMSG("Set MET_TROPO = 0 ... 5!");
5117 ctl->met_tropo_pv =
5118 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
5119 ctl->met_tropo_theta =
5120 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
5121 ctl->met_tropo_spline =
5122 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
5123 ctl->met_dt_out =
5124 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
5125 ctl->met_cache =
5126 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
5127 ctl->met_mpi_share =
5128 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
5129
5130 /* Sorting... */
5131 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
5132
5133 /* Isosurface parameters... */
5134 ctl->isosurf =
5135 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
5136 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
5137
5138 /* Random number generator... */
5139 ctl->rng_type =
5140 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "0", NULL);
5141 if (ctl->rng_type < 0 || ctl->rng_type > 2)
5142 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
5143
5144 /* Advection parameters... */
5145 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
5146 if (!(ctl->advect == 0 || ctl->advect == 1
5147 || ctl->advect == 2 || ctl->advect == 4))
5148 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
5149 ctl->reflect =
5150 (int) scan_ctl(filename, argc, argv, "REFLECT", -1, "0", NULL);
5151
5152 /* Diffusion parameters... */
5153 ctl->turb_dx_trop =
5154 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
5155 ctl->turb_dx_strat =
5156 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
5157 ctl->turb_dz_trop =
5158 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
5159 ctl->turb_dz_strat =
5160 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
5161 ctl->turb_mesox =
5162 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
5163 ctl->turb_mesoz =
5164 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5165
5166 /* Convection... */
5167 ctl->conv_cape
5168 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5169 ctl->conv_cin
5170 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5171 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5172 ctl->conv_mix_bot
5173 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_BOT", -1, "1", NULL);
5174 ctl->conv_mix_top
5175 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_TOP", -1, "1", NULL);
5176
5177 /* Boundary conditions... */
5178 ctl->bound_mass =
5179 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5180 ctl->bound_mass_trend =
5181 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5182 ctl->bound_vmr =
5183 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5184 ctl->bound_vmr_trend =
5185 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5186 ctl->bound_lat0 =
5187 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5188 ctl->bound_lat1 =
5189 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5190 ctl->bound_p0 =
5191 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5192 ctl->bound_p1 =
5193 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5194 ctl->bound_dps =
5195 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5196 ctl->bound_dzs =
5197 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
5198 ctl->bound_zetas =
5199 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
5200 ctl->bound_pbl =
5201 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
5202
5203 /* Species parameters... */
5204 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
5205 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
5206 ctl->molmass = 120.907;
5207 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
5208 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5209 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5210 ctl->molmass = 137.359;
5211 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5212 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5213 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5214 ctl->molmass = 16.043;
5215 ctl->oh_chem_reaction = 2;
5216 ctl->oh_chem[0] = 2.45e-12;
5217 ctl->oh_chem[1] = 1775;
5218 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5219 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5220 } else if (strcasecmp(ctl->species, "CO") == 0) {
5221 ctl->molmass = 28.01;
5222 ctl->oh_chem_reaction = 3;
5223 ctl->oh_chem[0] = 6.9e-33;
5224 ctl->oh_chem[1] = 2.1;
5225 ctl->oh_chem[2] = 1.1e-12;
5226 ctl->oh_chem[3] = -1.3;
5227 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5228 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5229 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5230 ctl->molmass = 44.009;
5231 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5232 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5233 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5234 ctl->molmass = 18.01528;
5235 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5236 ctl->molmass = 44.013;
5237 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5238 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5239 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5240 ctl->molmass = 17.031;
5241 ctl->oh_chem_reaction = 2;
5242 ctl->oh_chem[0] = 1.7e-12;
5243 ctl->oh_chem[1] = 710;
5244 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
5245 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
5246 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
5247 ctl->molmass = 63.012;
5248 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
5249 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
5250 } else if (strcasecmp(ctl->species, "NO") == 0) {
5251 ctl->molmass = 30.006;
5252 ctl->oh_chem_reaction = 3;
5253 ctl->oh_chem[0] = 7.1e-31;
5254 ctl->oh_chem[1] = 2.6;
5255 ctl->oh_chem[2] = 3.6e-11;
5256 ctl->oh_chem[3] = 0.1;
5257 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
5258 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5259 } else if (strcasecmp(ctl->species, "NO2") == 0) {
5260 ctl->molmass = 46.005;
5261 ctl->oh_chem_reaction = 3;
5262 ctl->oh_chem[0] = 1.8e-30;
5263 ctl->oh_chem[1] = 3.0;
5264 ctl->oh_chem[2] = 2.8e-11;
5265 ctl->oh_chem[3] = 0.0;
5266 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
5267 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5268 } else if (strcasecmp(ctl->species, "O3") == 0) {
5269 ctl->molmass = 47.997;
5270 ctl->oh_chem_reaction = 2;
5271 ctl->oh_chem[0] = 1.7e-12;
5272 ctl->oh_chem[1] = 940;
5273 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
5274 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
5275 } else if (strcasecmp(ctl->species, "SF6") == 0) {
5276 ctl->molmass = 146.048;
5277 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
5278 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
5279 } else if (strcasecmp(ctl->species, "SO2") == 0) {
5280 ctl->molmass = 64.066;
5281 ctl->oh_chem_reaction = 3;
5282 ctl->oh_chem[0] = 2.9e-31;
5283 ctl->oh_chem[1] = 4.1;
5284 ctl->oh_chem[2] = 1.7e-12;
5285 ctl->oh_chem[3] = -0.2;
5286 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
5287 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
5288 }
5289
5290 /* Molar mass... */
5291 char defstr[LEN];
5292 sprintf(defstr, "%g", ctl->molmass);
5293 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
5294
5295 /* OH chemistry... */
5296 sprintf(defstr, "%d", ctl->oh_chem_reaction);
5297 ctl->oh_chem_reaction =
5298 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
5299 NULL);
5300 for (int ip = 0; ip < 4; ip++) {
5301 sprintf(defstr, "%g", ctl->oh_chem[ip]);
5302 ctl->oh_chem[ip] =
5303 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
5304 }
5305 ctl->oh_chem_beta =
5306 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
5307
5308 /* H2O2 chemistry... */
5309 ctl->h2o2_chem_reaction =
5310 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
5311
5312 /* KPP chemistry... */
5313 ctl->kpp_chem =
5314 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
5315 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
5316
5317 /* First order tracer chemistry... */
5318 ctl->tracer_chem =
5319 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
5320
5321 /* Wet deposition... */
5322 for (int ip = 0; ip < 3; ip++) {
5323 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
5324 ctl->wet_depo_ic_h[ip] =
5325 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
5326 }
5327 for (int ip = 0; ip < 1; ip++) {
5328 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
5329 ctl->wet_depo_bc_h[ip] =
5330 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
5331 }
5332 ctl->wet_depo_ic_a =
5333 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
5334 ctl->wet_depo_ic_b =
5335 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
5336 ctl->wet_depo_bc_a =
5337 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
5338 ctl->wet_depo_bc_b =
5339 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
5340 ctl->wet_depo_pre[0] =
5341 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
5342 ctl->wet_depo_pre[1] =
5343 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
5345 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
5347 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
5348
5349 /* Dry deposition... */
5350 ctl->dry_depo_vdep =
5351 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
5352 ctl->dry_depo_dp =
5353 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
5354
5355 /* Climatological data... */
5356 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
5357 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
5358 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
5359 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
5360 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
5361 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
5362 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
5363 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
5364 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
5365 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
5366 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
5367 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
5368 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
5369 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
5370 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
5371 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
5372 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
5373 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
5374 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
5375 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
5376 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
5377 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
5378
5379 /* Mixing... */
5380 ctl->mixing_dt =
5381 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
5382 ctl->mixing_trop =
5383 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
5384 ctl->mixing_strat =
5385 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
5386 ctl->mixing_z0 =
5387 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
5388 ctl->mixing_z1 =
5389 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
5390 ctl->mixing_nz =
5391 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
5392 ctl->mixing_lon0 =
5393 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
5394 ctl->mixing_lon1 =
5395 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
5396 ctl->mixing_nx =
5397 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
5398 ctl->mixing_lat0 =
5399 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
5400 ctl->mixing_lat1 =
5401 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
5402 ctl->mixing_ny =
5403 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
5404
5405 /* Chemistry grid... */
5406 ctl->chemgrid_z0 =
5407 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
5408 ctl->chemgrid_z1 =
5409 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
5410 ctl->chemgrid_nz =
5411 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
5412 ctl->chemgrid_lon0 =
5413 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
5414 ctl->chemgrid_lon1 =
5415 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
5416 ctl->chemgrid_nx =
5417 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
5418 ctl->chemgrid_lat0 =
5419 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
5420 ctl->chemgrid_lat1 =
5421 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
5422 ctl->chemgrid_ny =
5423 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
5424
5425 /* Exponential decay... */
5426 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
5427 ctl->tdec_strat
5428 = scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
5429
5430 /* PSC analysis... */
5431 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
5432 ctl->psc_hno3 =
5433 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
5434
5435 /* Output of atmospheric data... */
5436 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
5437 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
5438 ctl->atm_dt_out =
5439 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
5440 ctl->atm_filter =
5441 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
5442 ctl->atm_stride =
5443 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
5444 ctl->atm_type =
5445 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
5446 ctl->atm_type_out =
5447 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
5448 if (ctl->atm_type_out == -1)
5449 ctl->atm_type_out = ctl->atm_type;
5450 ctl->obs_type =
5451 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
5452
5453 /* Output of CSI data... */
5454 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
5455 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
5456 ctl->csi_dt_out =
5457 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
5458 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
5459 ctl->csi_obsmin =
5460 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
5461 ctl->csi_modmin =
5462 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
5463 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
5464 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
5465 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
5466 ctl->csi_lon0 =
5467 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
5468 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
5469 ctl->csi_nx =
5470 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
5471 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
5472 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
5473 ctl->csi_ny =
5474 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
5475
5476 /* Output of ensemble data... */
5477 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
5478 ctl->ens_dt_out =
5479 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
5480
5481 /* Output of grid data... */
5482 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
5483 ctl->grid_basename);
5484 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
5485 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
5486 ctl->grid_dt_out =
5487 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
5488 ctl->grid_sparse =
5489 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
5490 ctl->grid_stddev =
5491 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
5492 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
5493 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
5494 ctl->grid_nz =
5495 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
5496 ctl->grid_lon0 =
5497 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
5498 ctl->grid_lon1 =
5499 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
5500 ctl->grid_nx =
5501 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
5502 ctl->grid_lat0 =
5503 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
5504 ctl->grid_lat1 =
5505 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
5506 ctl->grid_ny =
5507 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
5508 ctl->grid_type =
5509 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
5510
5511 /* Output of profile data... */
5512 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
5513 ctl->prof_basename);
5514 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
5515 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
5516 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
5517 ctl->prof_nz =
5518 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
5519 ctl->prof_lon0 =
5520 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
5521 ctl->prof_lon1 =
5522 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
5523 ctl->prof_nx =
5524 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
5525 ctl->prof_lat0 =
5526 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
5527 ctl->prof_lat1 =
5528 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
5529 ctl->prof_ny =
5530 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
5531
5532 /* Output of sample data... */
5533 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
5534 ctl->sample_basename);
5535 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
5536 ctl->sample_kernel);
5537 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
5538 ctl->sample_obsfile);
5539 ctl->sample_dx =
5540 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
5541 ctl->sample_dz =
5542 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
5543
5544 /* Output of station data... */
5545 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
5546 ctl->stat_basename);
5547 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
5548 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
5549 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
5550 ctl->stat_t0 =
5551 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
5552 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
5553
5554 /* Output of VTK data... */
5555 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
5556 ctl->vtk_dt_out =
5557 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
5558 ctl->vtk_stride =
5559 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
5560 ctl->vtk_scale =
5561 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
5562 ctl->vtk_offset =
5563 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
5564 ctl->vtk_sphere =
5565 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
5566}
5567
5568/*****************************************************************************/
5569
5571 const char *filename,
5572 double kz[EP],
5573 double kw[EP],
5574 int *nk) {
5575
5576 /* Write info... */
5577 LOG(1, "Read kernel function: %s", filename);
5578
5579 /* Open file... */
5580 FILE *in;
5581 if (!(in = fopen(filename, "r")))
5582 ERRMSG("Cannot open file!");
5583
5584 /* Read data... */
5585 char line[LEN];
5586 int n = 0;
5587 while (fgets(line, LEN, in))
5588 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
5589 if (n > 0 && kz[n] < kz[n - 1])
5590 ERRMSG("Height levels must be ascending!");
5591 if ((++n) >= EP)
5592 ERRMSG("Too many height levels!");
5593 }
5594
5595 /* Close file... */
5596 fclose(in);
5597
5598 /* Check number of data points... */
5599 *nk = n;
5600 if (n < 2)
5601 ERRMSG("Not enough height levels!");
5602
5603 /* Normalize kernel function... */
5604 double kmax = gsl_stats_max(kw, 1, (size_t) n);
5605 for (int iz = 0; iz < n; iz++)
5606 kw[iz] /= kmax;
5607}
5608
5609/*****************************************************************************/
5610
5612 const char *filename,
5613 ctl_t * ctl,
5614 clim_t * clim,
5615 met_t * met) {
5616
5617 /* Write info... */
5618 LOG(1, "Read meteo data: %s", filename);
5619
5620 /* Initialize rank... */
5621 int rank = 0;
5622#ifdef MPI
5623 if (ctl->met_mpi_share)
5624 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5625#endif
5626
5627 /* Read netCDF data... */
5628 if (!ctl->met_mpi_share || rank == 0) {
5629 if (ctl->met_type == 0) {
5630
5631 int ncid;
5632
5633 /* Open netCDF file... */
5634 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
5635 WARN("Cannot open file!");
5636 return 0;
5637 }
5638
5639 /* Read coordinates of meteo data... */
5640 read_met_grid(filename, ncid, ctl, met);
5641
5642 /* Read meteo data on vertical levels... */
5643 read_met_levels(ncid, ctl, met);
5644
5645 /* Extrapolate data for lower boundary... */
5647
5648 /* Read surface data... */
5649 read_met_surface(ncid, met, ctl);
5650
5651 /* Fix polar winds... */
5653
5654 /* Create periodic boundary conditions... */
5655 read_met_periodic(met);
5656
5657 /* Downsampling... */
5658 read_met_sample(ctl, met);
5659
5660 /* Calculate geopotential heights... */
5661 read_met_geopot(ctl, met);
5662
5663 /* Calculate potential vorticity... */
5664 read_met_pv(met);
5665
5666 /* Calculate boundary layer data... */
5667 read_met_pbl(met);
5668
5669 /* Calculate tropopause data... */
5670 read_met_tropo(ctl, clim, met);
5671
5672 /* Calculate cloud properties... */
5673 read_met_cloud(met);
5674
5675 /* Calculate convective available potential energy... */
5676 read_met_cape(clim, met);
5677
5678 /* Calculate total column ozone... */
5679 read_met_ozone(met);
5680
5681 /* Detrending... */
5682 read_met_detrend(ctl, met);
5683
5684 /* Check meteo data and smooth zeta profiles ... */
5685 if (ctl->advect_vert_coord == 1)
5687
5688 /* Close file... */
5689 NC(nc_close(ncid));
5690 }
5691
5692 /* Read binary data... */
5693 else if (ctl->met_type >= 1 && ctl->met_type <= 5) {
5694
5695 FILE *in;
5696
5697 double r;
5698
5699 int year, mon, day, hour, min, sec;
5700
5701 /* Set timer... */
5702 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
5703
5704 /* Open file... */
5705 if (!(in = fopen(filename, "r"))) {
5706 WARN("Cannot open file!");
5707 return 0;
5708 }
5709
5710 /* Check type of binary data... */
5711 int met_type;
5712 FREAD(&met_type, int,
5713 1,
5714 in);
5715 if (met_type != ctl->met_type)
5716 ERRMSG("Wrong MET_TYPE of binary data!");
5717
5718 /* Check version of binary data... */
5719 int version;
5720 FREAD(&version, int,
5721 1,
5722 in);
5723 if (version != 100 && version != 101 && version != 102)
5724 ERRMSG("Wrong version of binary data!");
5725
5726 /* Read time... */
5727 FREAD(&met->time, double,
5728 1,
5729 in);
5730 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
5731 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
5732 met->time, year, mon, day, hour, min);
5733 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
5734 || day < 1 || day > 31 || hour < 0 || hour > 23)
5735 ERRMSG("Error while reading time!");
5736
5737 /* Read dimensions... */
5738 FREAD(&met->nx, int,
5739 1,
5740 in);
5741 LOG(2, "Number of longitudes: %d", met->nx);
5742 if (met->nx < 2 || met->nx > EX)
5743 ERRMSG("Number of longitudes out of range!");
5744
5745 FREAD(&met->ny, int,
5746 1,
5747 in);
5748 LOG(2, "Number of latitudes: %d", met->ny);
5749 if (met->ny < 2 || met->ny > EY)
5750 ERRMSG("Number of latitudes out of range!");
5751
5752 FREAD(&met->np, int,
5753 1,
5754 in);
5755 LOG(2, "Number of levels: %d", met->np);
5756 if (met->np < 2 || met->np > EP)
5757 ERRMSG("Number of levels out of range!");
5758
5759 /* Read grid... */
5760 FREAD(met->lon, double,
5761 (size_t) met->nx,
5762 in);
5763 LOG(2, "Longitudes: %g, %g ... %g deg",
5764 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
5765
5766 FREAD(met->lat, double,
5767 (size_t) met->ny,
5768 in);
5769 LOG(2, "Latitudes: %g, %g ... %g deg",
5770 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
5771
5772 FREAD(met->p, double,
5773 (size_t) met->np,
5774 in);
5775 LOG(2, "Altitude levels: %g, %g ... %g km",
5776 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
5777 LOG(2, "Pressure levels: %g, %g ... %g hPa",
5778 met->p[0], met->p[1], met->p[met->np - 1]);
5779
5780 /* Read surface data... */
5781 read_met_bin_2d(in, met, met->ps, "PS");
5782 read_met_bin_2d(in, met, met->ts, "TS");
5783 read_met_bin_2d(in, met, met->zs, "ZS");
5784 read_met_bin_2d(in, met, met->us, "US");
5785 read_met_bin_2d(in, met, met->vs, "VS");
5786 if (version >= 101) {
5787 read_met_bin_2d(in, met, met->lsm, "LSM");
5788 read_met_bin_2d(in, met, met->sst, "SST");
5789 }
5790 read_met_bin_2d(in, met, met->pbl, "PBL");
5791 read_met_bin_2d(in, met, met->pt, "PT");
5792 read_met_bin_2d(in, met, met->tt, "TT");
5793 read_met_bin_2d(in, met, met->zt, "ZT");
5794 read_met_bin_2d(in, met, met->h2ot, "H2OT");
5795 read_met_bin_2d(in, met, met->pct, "PCT");
5796 read_met_bin_2d(in, met, met->pcb, "PCB");
5797 read_met_bin_2d(in, met, met->cl, "CL");
5798 read_met_bin_2d(in, met, met->plcl, "PLCL");
5799 read_met_bin_2d(in, met, met->plfc, "PLFC");
5800 read_met_bin_2d(in, met, met->pel, "PEL");
5801 read_met_bin_2d(in, met, met->cape, "CAPE");
5802 read_met_bin_2d(in, met, met->cin, "CIN");
5803
5804 /* Read level data... */
5805 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
5806 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
5807 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
5808 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
5809 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
5810 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
5811 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
5812 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
5813 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
5814 if (version >= 102)
5815 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
5816 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
5817 if (version >= 102)
5818 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
5819 if (version >= 101)
5820 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
5821
5822 /* Read final flag... */
5823 int final;
5824 FREAD(&final, int,
5825 1,
5826 in);
5827 if (final != 999)
5828 ERRMSG("Error while reading binary data!");
5829
5830 /* Close file... */
5831 fclose(in);
5832 }
5833
5834 /* Not implemented... */
5835 else
5836 ERRMSG("MET_TYPE not implemented!");
5837 }
5838
5839 /* Broadcast data via MPI... */
5840#ifdef MPI
5841 if (ctl->met_mpi_share) {
5842
5843 /* Set timer... */
5844 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
5845 LOG(2, "Broadcast data on rank %d...", rank);
5846
5847 /* Broadcast... */
5848 broadcast_large_data(met, sizeof(met_t));
5849 }
5850#endif
5851
5852 /* Return success... */
5853 return 1;
5854}
5855
5856/*****************************************************************************/
5857
5859 FILE * in,
5860 met_t * met,
5861 float var[EX][EY],
5862 char *varname) {
5863
5864 float *help;
5865
5866 /* Allocate... */
5867 ALLOC(help, float,
5868 EX * EY);
5869
5870 /* Read uncompressed... */
5871 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
5872 FREAD(help, float,
5873 (size_t) (met->nx * met->ny),
5874 in);
5875
5876 /* Copy data... */
5877 for (int ix = 0; ix < met->nx; ix++)
5878 for (int iy = 0; iy < met->ny; iy++)
5879 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
5880
5881 /* Free... */
5882 free(help);
5883}
5884
5885/*****************************************************************************/
5886
5888 FILE * in,
5889 ctl_t * ctl,
5890 met_t * met,
5891 float var[EX][EY][EP],
5892 char *varname,
5893 float bound_min,
5894 float bound_max) {
5895
5896 float *help;
5897
5898 /* Allocate... */
5899 ALLOC(help, float,
5900 EX * EY * EP);
5901
5902 /* Read uncompressed data... */
5903 if (ctl->met_type == 1) {
5904 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
5905 FREAD(help, float,
5906 (size_t) (met->nx * met->ny * met->np),
5907 in);
5908 }
5909
5910 /* Read packed data... */
5911 else if (ctl->met_type == 2)
5912 compress_pck(varname, help, (size_t) (met->ny * met->nx),
5913 (size_t) met->np, 1, in);
5914
5915 /* Read zfp data... */
5916 else if (ctl->met_type == 3) {
5917#ifdef ZFP
5918 int precision;
5919 FREAD(&precision, int,
5920 1,
5921 in);
5922
5923 double tolerance;
5924 FREAD(&tolerance, double,
5925 1,
5926 in);
5927
5928 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
5929 tolerance, 1, in);
5930#else
5931 ERRMSG("MPTRAC was compiled without zfp compression!");
5932#endif
5933 }
5934
5935 /* Read zstd data... */
5936 else if (ctl->met_type == 4) {
5937#ifdef ZSTD
5938 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
5939 in);
5940#else
5941 ERRMSG("MPTRAC was compiled without zstd compression!");
5942#endif
5943 }
5944
5945 /* Read cmultiscale data... */
5946 else if (ctl->met_type == 5) {
5947#ifdef CMS
5948 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
5949 (size_t) met->np, 1, in);
5950#else
5951 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
5952#endif
5953 }
5954
5955 /* Copy data... */
5956#pragma omp parallel for default(shared) collapse(2)
5957 for (int ix = 0; ix < met->nx; ix++)
5958 for (int iy = 0; iy < met->ny; iy++)
5959 for (int ip = 0; ip < met->np; ip++) {
5960 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
5961 if (var[ix][iy][ip] < bound_min)
5962 var[ix][iy][ip] = bound_min;
5963 else if (var[ix][iy][ip] > bound_max)
5964 var[ix][iy][ip] = bound_max;
5965 }
5966
5967 /* Free... */
5968 free(help);
5969}
5970
5971/*****************************************************************************/
5972
5974 clim_t * clim,
5975 met_t * met) {
5976
5977 /* Set timer... */
5978 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
5979 LOG(2, "Calculate CAPE...");
5980
5981 /* Vertical spacing (about 100 m)... */
5982 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
5983
5984 /* Loop over columns... */
5985#pragma omp parallel for default(shared) collapse(2)
5986 for (int ix = 0; ix < met->nx; ix++)
5987 for (int iy = 0; iy < met->ny; iy++) {
5988
5989 /* Get potential temperature and water vapor at lowest 50 hPa... */
5990 int n = 0;
5991 double h2o = 0, t, theta = 0;
5992 double pbot = MIN(met->ps[ix][iy], met->p[0]);
5993 double ptop = pbot - 50.;
5994 for (int ip = 0; ip < met->np; ip++) {
5995 if (met->p[ip] <= pbot) {
5996 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
5997 h2o += met->h2o[ix][iy][ip];
5998 n++;
5999 }
6000 if (met->p[ip] < ptop && n > 0)
6001 break;
6002 }
6003 theta /= n;
6004 h2o /= n;
6005
6006 /* Cannot compute anything if water vapor is missing... */
6007 met->plcl[ix][iy] = NAN;
6008 met->plfc[ix][iy] = NAN;
6009 met->pel[ix][iy] = NAN;
6010 met->cape[ix][iy] = NAN;
6011 met->cin[ix][iy] = NAN;
6012 if (h2o <= 0)
6013 continue;
6014
6015 /* Find lifted condensation level (LCL)... */
6016 ptop = P(20.);
6017 pbot = met->ps[ix][iy];
6018 do {
6019 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
6020 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
6021 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
6022 ptop = met->plcl[ix][iy];
6023 else
6024 pbot = met->plcl[ix][iy];
6025 } while (pbot - ptop > 0.1);
6026
6027 /* Calculate CIN up to LCL... */
6029 double dcape, dz, h2o_env, t_env;
6030 double p = met->ps[ix][iy];
6031 met->cape[ix][iy] = met->cin[ix][iy] = 0;
6032 do {
6033 dz = dz0 * TVIRT(t, h2o);
6034 p /= pfac;
6035 t = theta / pow(1000. / p, 0.286);
6036 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6037 &t_env, ci, cw, 1);
6038 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6039 &h2o_env, ci, cw, 0);
6040 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6041 TVIRT(t_env, h2o_env) * dz;
6042 if (dcape < 0)
6043 met->cin[ix][iy] += fabsf((float) dcape);
6044 } while (p > met->plcl[ix][iy]);
6045
6046 /* Calculate level of free convection (LFC), equilibrium level (EL),
6047 and convective available potential energy (CAPE)... */
6048 dcape = 0;
6049 p = met->plcl[ix][iy];
6050 t = theta / pow(1000. / p, 0.286);
6051 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
6052 do {
6053 dz = dz0 * TVIRT(t, h2o);
6054 p /= pfac;
6055 t -= lapse_rate(t, h2o) * dz;
6056 double psat = PSAT(t);
6057 h2o = psat / (p - (1. - EPS) * psat);
6058 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6059 &t_env, ci, cw, 1);
6060 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6061 &h2o_env, ci, cw, 0);
6062 double dcape_old = dcape;
6063 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6064 TVIRT(t_env, h2o_env) * dz;
6065 if (dcape > 0) {
6066 met->cape[ix][iy] += (float) dcape;
6067 if (!isfinite(met->plfc[ix][iy]))
6068 met->plfc[ix][iy] = (float) p;
6069 } else if (dcape_old > 0)
6070 met->pel[ix][iy] = (float) p;
6071 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
6072 met->cin[ix][iy] += fabsf((float) dcape);
6073 } while (p > ptop);
6074
6075 /* Check results... */
6076 if (!isfinite(met->plfc[ix][iy]))
6077 met->cin[ix][iy] = NAN;
6078 }
6079}
6080
6081/*****************************************************************************/
6082
6084 met_t * met) {
6085
6086 /* Set timer... */
6087 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
6088 LOG(2, "Calculate cloud data...");
6089
6090 /* Loop over columns... */
6091#pragma omp parallel for default(shared) collapse(2)
6092 for (int ix = 0; ix < met->nx; ix++)
6093 for (int iy = 0; iy < met->ny; iy++) {
6094
6095 /* Init... */
6096 met->pct[ix][iy] = NAN;
6097 met->pcb[ix][iy] = NAN;
6098 met->cl[ix][iy] = 0;
6099
6100 /* Loop over pressure levels... */
6101 for (int ip = 0; ip < met->np - 1; ip++) {
6102
6103 /* Check pressure... */
6104 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
6105 continue;
6106
6107 /* Check ice water and liquid water content... */
6108 if (met->iwc[ix][iy][ip] > 0 || met->rwc[ix][iy][ip] > 0
6109 || met->lwc[ix][iy][ip] > 0 || met->swc[ix][iy][ip] > 0) {
6110
6111 /* Get cloud top pressure ... */
6112 met->pct[ix][iy]
6113 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
6114
6115 /* Get cloud bottom pressure ... */
6116 if (!isfinite(met->pcb[ix][iy]))
6117 met->pcb[ix][iy]
6118 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
6119 }
6120
6121 /* Get cloud water... */
6122 met->cl[ix][iy] += (float)
6123 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
6124 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
6125 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
6126 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
6127 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
6128 }
6129 }
6130}
6131
6132/*****************************************************************************/
6133
6135 ctl_t * ctl,
6136 met_t * met) {
6137
6138 met_t *help;
6139
6140 /* Check parameters... */
6141 if (ctl->met_detrend <= 0)
6142 return;
6143
6144 /* Set timer... */
6145 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
6146 LOG(2, "Detrend meteo data...");
6147
6148 /* Allocate... */
6149 ALLOC(help, met_t, 1);
6150
6151 /* Calculate standard deviation... */
6152 double sigma = ctl->met_detrend / 2.355;
6153 double tssq = 2. * SQR(sigma);
6154
6155 /* Calculate box size in latitude... */
6156 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
6157 sy = MIN(MAX(1, sy), met->ny / 2);
6158
6159 /* Calculate background... */
6160#pragma omp parallel for default(shared) collapse(2)
6161 for (int ix = 0; ix < met->nx; ix++) {
6162 for (int iy = 0; iy < met->ny; iy++) {
6163
6164 /* Calculate Cartesian coordinates... */
6165 double x0[3];
6166 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
6167
6168 /* Calculate box size in longitude... */
6169 int sx =
6170 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
6171 fabs(met->lon[1] - met->lon[0]));
6172 sx = MIN(MAX(1, sx), met->nx / 2);
6173
6174 /* Init... */
6175 float wsum = 0;
6176 for (int ip = 0; ip < met->np; ip++) {
6177 help->t[ix][iy][ip] = 0;
6178 help->u[ix][iy][ip] = 0;
6179 help->v[ix][iy][ip] = 0;
6180 help->w[ix][iy][ip] = 0;
6181 }
6182
6183 /* Loop over neighboring grid points... */
6184 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
6185 int ix3 = ix2;
6186 if (ix3 < 0)
6187 ix3 += met->nx;
6188 else if (ix3 >= met->nx)
6189 ix3 -= met->nx;
6190 for (int iy2 = MAX(iy - sy, 0);
6191 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
6192
6193 /* Calculate Cartesian coordinates... */
6194 double x1[3];
6195 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
6196
6197 /* Calculate weighting factor... */
6198 float w = (float) exp(-DIST2(x0, x1) / tssq);
6199
6200 /* Add data... */
6201 wsum += w;
6202 for (int ip = 0; ip < met->np; ip++) {
6203 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
6204 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
6205 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
6206 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
6207 }
6208 }
6209 }
6210
6211 /* Normalize... */
6212 for (int ip = 0; ip < met->np; ip++) {
6213 help->t[ix][iy][ip] /= wsum;
6214 help->u[ix][iy][ip] /= wsum;
6215 help->v[ix][iy][ip] /= wsum;
6216 help->w[ix][iy][ip] /= wsum;
6217 }
6218 }
6219 }
6220
6221 /* Subtract background... */
6222#pragma omp parallel for default(shared) collapse(3)
6223 for (int ix = 0; ix < met->nx; ix++)
6224 for (int iy = 0; iy < met->ny; iy++)
6225 for (int ip = 0; ip < met->np; ip++) {
6226 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
6227 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
6228 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
6229 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
6230 }
6231
6232 /* Free... */
6233 free(help);
6234}
6235
6236/*****************************************************************************/
6237
6239 met_t * met) {
6240
6241 /* Set timer... */
6242 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
6243 LOG(2, "Extrapolate meteo data...");
6244
6245 /* Loop over columns... */
6246#pragma omp parallel for default(shared) collapse(2)
6247 for (int ix = 0; ix < met->nx; ix++)
6248 for (int iy = 0; iy < met->ny; iy++) {
6249
6250 /* Find lowest valid data point... */
6251 int ip0;
6252 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
6253 if (!isfinite(met->t[ix][iy][ip0])
6254 || !isfinite(met->u[ix][iy][ip0])
6255 || !isfinite(met->v[ix][iy][ip0])
6256 || !isfinite(met->w[ix][iy][ip0]))
6257 break;
6258
6259 /* Extrapolate... */
6260 for (int ip = ip0; ip >= 0; ip--) {
6261 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
6262 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
6263 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
6264 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
6265 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
6266 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
6267 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
6268 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
6269 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
6270 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
6271 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
6272 }
6273 }
6274}
6275
6276/*****************************************************************************/
6277
6279 ctl_t * ctl,
6280 met_t * met) {
6281
6282 float *help;
6283
6284 double logp[EP];
6285
6286 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
6287
6288 /* Set timer... */
6289 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
6290 LOG(2, "Calculate geopotential heights...");
6291
6292 /* Allocate... */
6293 ALLOC(help, float,
6294 EX * EY * EP);
6295
6296 /* Calculate log pressure... */
6297#pragma omp parallel for default(shared)
6298 for (int ip = 0; ip < met->np; ip++)
6299 logp[ip] = log(met->p[ip]);
6300
6301 /* Apply hydrostatic equation to calculate geopotential heights... */
6302#pragma omp parallel for default(shared) collapse(2)
6303 for (int ix = 0; ix < met->nx; ix++)
6304 for (int iy = 0; iy < met->ny; iy++) {
6305
6306 /* Get surface height and pressure... */
6307 double zs = met->zs[ix][iy];
6308 double lnps = log(met->ps[ix][iy]);
6309
6310 /* Get temperature and water vapor at the surface... */
6311 int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
6312 double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
6313 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
6314 double h2os = LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
6315 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
6316
6317 /* Upper part of profile... */
6318 met->z[ix][iy][ip0 + 1]
6319 = (float) (zs +
6320 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
6321 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
6322 for (int ip = ip0 + 2; ip < met->np; ip++)
6323 met->z[ix][iy][ip]
6324 = (float) (met->z[ix][iy][ip - 1] +
6325 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
6326 met->h2o[ix][iy][ip - 1], logp[ip],
6327 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
6328
6329 /* Lower part of profile... */
6330 met->z[ix][iy][ip0]
6331 = (float) (zs +
6332 ZDIFF(lnps, ts, h2os, logp[ip0],
6333 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
6334 for (int ip = ip0 - 1; ip >= 0; ip--)
6335 met->z[ix][iy][ip]
6336 = (float) (met->z[ix][iy][ip + 1] +
6337 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
6338 met->h2o[ix][iy][ip + 1], logp[ip],
6339 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
6340 }
6341
6342 /* Check control parameters... */
6343 if (dx == 0 || dy == 0)
6344 return;
6345
6346 /* Default smoothing parameters... */
6347 if (dx < 0 || dy < 0) {
6348 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
6349 dx = 3;
6350 dy = 2;
6351 } else {
6352 dx = 6;
6353 dy = 4;
6354 }
6355 }
6356
6357 /* Calculate weights for smoothing... */
6358 float ws[dx + 1][dy + 1];
6359#pragma omp parallel for default(shared) collapse(2)
6360 for (int ix = 0; ix <= dx; ix++)
6361 for (int iy = 0; iy < dy; iy++)
6362 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
6363 * (1.0f - (float) iy / (float) dy);
6364
6365 /* Copy data... */
6366#pragma omp parallel for default(shared) collapse(3)
6367 for (int ix = 0; ix < met->nx; ix++)
6368 for (int iy = 0; iy < met->ny; iy++)
6369 for (int ip = 0; ip < met->np; ip++)
6370 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
6371
6372 /* Horizontal smoothing... */
6373#pragma omp parallel for default(shared) collapse(3)
6374 for (int ip = 0; ip < met->np; ip++)
6375 for (int ix = 0; ix < met->nx; ix++)
6376 for (int iy = 0; iy < met->ny; iy++) {
6377 float res = 0, wsum = 0;
6378 int iy0 = MAX(iy - dy + 1, 0);
6379 int iy1 = MIN(iy + dy - 1, met->ny - 1);
6380 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
6381 int ix3 = ix2;
6382 if (ix3 < 0)
6383 ix3 += met->nx;
6384 else if (ix3 >= met->nx)
6385 ix3 -= met->nx;
6386 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
6387 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
6388 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
6389 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
6390 wsum += w;
6391 }
6392 }
6393 if (wsum > 0)
6394 met->z[ix][iy][ip] = res / wsum;
6395 else
6396 met->z[ix][iy][ip] = NAN;
6397 }
6398
6399 /* Free... */
6400 free(help);
6401}
6402
6403/*****************************************************************************/
6404
6406 const char *filename,
6407 int ncid,
6408 ctl_t * ctl,
6409 met_t * met) {
6410
6411 char levname[LEN], tstr[10];
6412
6413 double rtime = 0, r, r2;
6414
6415 int varid, year2, mon2, day2, hour2, min2, sec2,
6416 year, mon, day, hour, min, sec;
6417
6418 size_t np;
6419
6420 /* Set timer... */
6421 SELECT_TIMER("READ_MET_GRID", "INPUT", NVTX_READ);
6422 LOG(2, "Read meteo grid information...");
6423
6424 /* MPTRAC meteo files... */
6425 if (ctl->met_clams == 0) {
6426
6427 /* Get time from filename... */
6428 met->time = time_from_filename(filename, 16);
6429
6430 /* Check time information from data file... */
6431 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
6432 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
6433 NC(nc_get_var_double(ncid, varid, &rtime));
6434 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
6435 WARN("Time information in meteo file does not match filename!");
6436 } else
6437 WARN("Time information in meteo file is missing!");
6438 }
6439
6440 /* CLaMS meteo files... */
6441 else {
6442
6443 /* Read time from file... */
6444 NC_GET_DOUBLE("time", &rtime, 0);
6445
6446 /* Get time from filename (considering the century)... */
6447 if (rtime < 0)
6448 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
6449 else
6450 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
6451 year = atoi(tstr);
6452 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
6453 mon = atoi(tstr);
6454 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
6455 day = atoi(tstr);
6456 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
6457 hour = atoi(tstr);
6458 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
6459 }
6460
6461 /* Check time... */
6462 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
6463 || day < 1 || day > 31 || hour < 0 || hour > 23)
6464 ERRMSG("Cannot read time from filename!");
6465 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
6466 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
6467 met->time, year2, mon2, day2, hour2, min2);
6468
6469 /* Get grid dimensions... */
6470 NC_INQ_DIM("lon", &met->nx, 2, EX);
6471 LOG(2, "Number of longitudes: %d", met->nx);
6472
6473 NC_INQ_DIM("lat", &met->ny, 2, EY);
6474 LOG(2, "Number of latitudes: %d", met->ny);
6475
6476 int dimid2;
6477 sprintf(levname, "lev");
6478 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
6479 sprintf(levname, "plev");
6480 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
6481 sprintf(levname, "hybrid");
6482
6483 NC_INQ_DIM(levname, &met->np, 1, EP);
6484 if (met->np == 1) {
6485 sprintf(levname, "lev_2");
6486 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR) {
6487 sprintf(levname, "plev");
6488 NC(nc_inq_dimid(ncid, levname, &dimid2));
6489 }
6490 NC(nc_inq_dimlen(ncid, dimid2, &np));
6491 met->np = (int) np;
6492 }
6493 LOG(2, "Number of levels: %d", met->np);
6494 if (met->np < 2 || met->np > EP)
6495 ERRMSG("Number of levels out of range!");
6496
6497 /* Read longitudes and latitudes... */
6498 NC_GET_DOUBLE("lon", met->lon, 1);
6499 LOG(2, "Longitudes: %g, %g ... %g deg",
6500 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
6501 NC_GET_DOUBLE("lat", met->lat, 1);
6502 LOG(2, "Latitudes: %g, %g ... %g deg",
6503 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
6504
6505 /* Read pressure levels... */
6506 if (ctl->met_np <= 0) {
6507 NC_GET_DOUBLE(levname, met->p, 1);
6508 for (int ip = 0; ip < met->np; ip++)
6509 met->p[ip] /= 100.;
6510 LOG(2, "Altitude levels: %g, %g ... %g km",
6511 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
6512 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6513 met->p[0], met->p[1], met->p[met->np - 1]);
6514 }
6515
6516 /* Read hybrid levels... */
6517 if (strcasecmp(levname, "hybrid") == 0)
6518 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
6519}
6520
6521/*****************************************************************************/
6522
6524 int ncid,
6525 ctl_t * ctl,
6526 met_t * met) {
6527
6528 /* Set timer... */
6529 SELECT_TIMER("READ_MET_LEVELS", "INPUT", NVTX_READ);
6530 LOG(2, "Read level data...");
6531
6532 /* Read temperature... */
6533 if (!read_met_nc_3d(ncid, "t", "T", "temp", "TEMP", ctl, met, met->t, 1.0))
6534 ERRMSG("Cannot read temperature!");
6535
6536 /* Read horizontal wind and vertical velocity... */
6537 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, met->u, 1.0))
6538 ERRMSG("Cannot read zonal wind!");
6539 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, met->v, 1.0))
6540 ERRMSG("Cannot read meridional wind!");
6541 if (!read_met_nc_3d
6542 (ncid, "w", "W", "omega", "OMEGA", ctl, met, met->w, 0.01f))
6543 WARN("Cannot read vertical velocity!");
6544
6545 /* Read water vapor... */
6546 if (!ctl->met_relhum) {
6547 if (!read_met_nc_3d
6548 (ncid, "q", "Q", "sh", "SH", ctl, met, met->h2o, (float) (MA / MH2O)))
6549 WARN("Cannot read specific humidity!");
6550 } else {
6551 if (!read_met_nc_3d
6552 (ncid, "rh", "RH", NULL, NULL, ctl, met, met->h2o, 0.01f))
6553 WARN("Cannot read relative humidity!");
6554#pragma omp parallel for default(shared) collapse(2)
6555 for (int ix = 0; ix < met->nx; ix++)
6556 for (int iy = 0; iy < met->ny; iy++)
6557 for (int ip = 0; ip < met->np; ip++) {
6558 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
6559 met->h2o[ix][iy][ip] =
6560 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
6561 }
6562 }
6563
6564 /* Read ozone... */
6565 if (!read_met_nc_3d
6566 (ncid, "o3", "O3", NULL, NULL, ctl, met, met->o3, (float) (MA / MO3)))
6567 WARN("Cannot read ozone data!");
6568
6569 /* Read cloud data... */
6570 if (!read_met_nc_3d
6571 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, met->lwc, 1.0))
6572 WARN("Cannot read cloud liquid water content!");
6573 if (!read_met_nc_3d
6574 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, met->rwc, 1.0))
6575 WARN("Cannot read cloud rain water content!");
6576 if (!read_met_nc_3d
6577 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, met->iwc, 1.0))
6578 WARN("Cannot read cloud ice water content!");
6579 if (!read_met_nc_3d
6580 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, met->swc, 1.0))
6581 WARN("Cannot read cloud snow water content!");
6582 if (!read_met_nc_3d(ncid, "cc", "CC", NULL, NULL, ctl, met, met->cc, 1.0))
6583 WARN("Cannot read cloud cover!");
6584
6585 /* Read zeta and zeta_dot... */
6586 if (!read_met_nc_3d
6587 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, met->zetal, 1.0))
6588 WARN("Cannot read ZETA in meteo data!");
6589 if (ctl->advect_vert_coord == 1) {
6590 if (!read_met_nc_3d
6591 (ncid, "ZETA_DOT_TOT", "zeta_dot_clr", NULL, NULL, ctl, met,
6592 met->zeta_dotl, 0.00001157407f)) {
6593 if (!read_met_nc_3d
6594 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", NULL, NULL, ctl, met,
6595 met->zeta_dotl, 0.00001157407f)) {
6596 WARN("Cannot read vertical velocity!");
6597 }
6598 }
6599 }
6600
6601 /* Store velocities on model levels for diabatic advection... */
6602 if (ctl->met_vert_coord == 1) {
6603 for (int ix = 0; ix < met->nx; ix++)
6604 for (int iy = 0; iy < met->ny; iy++)
6605 for (int ip = 0; ip < met->np; ip++) {
6606 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
6607 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
6608 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
6609 }
6610
6611 /* Original number of vertical levels... */
6612 met->npl = met->np;
6613 }
6614
6615 /* Read pressure on model levels... */
6616 if (ctl->met_np > 0 || ctl->met_vert_coord == 1) {
6617
6618 /* Read data... */
6619 if (!read_met_nc_3d
6620 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, met->pl, 0.01f))
6621 if (!read_met_nc_3d
6622 (ncid, "press", "PRESS", NULL, NULL, ctl, met, met->pl, 1.0))
6623 ERRMSG("Cannot read pressure on model levels!");
6624
6625 /* Check ordering of pressure levels... */
6626 for (int ix = 0; ix < met->nx; ix++)
6627 for (int iy = 0; iy < met->ny; iy++)
6628 for (int ip = 1; ip < met->np; ip++)
6629 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
6630 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
6631 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
6632 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
6633 ERRMSG("Pressure profiles are not monotonic!");
6634 }
6635
6636 /* Interpolate from model levels to pressure levels... */
6637 if (ctl->met_np > 0) {
6638
6639 /* Interpolate variables... */
6640 read_met_ml2pl(ctl, met, met->t, "T");
6641 read_met_ml2pl(ctl, met, met->u, "U");
6642 read_met_ml2pl(ctl, met, met->v, "V");
6643 read_met_ml2pl(ctl, met, met->w, "W");
6644 read_met_ml2pl(ctl, met, met->h2o, "H2O");
6645 read_met_ml2pl(ctl, met, met->o3, "O3");
6646 read_met_ml2pl(ctl, met, met->lwc, "LWC");
6647 read_met_ml2pl(ctl, met, met->rwc, "RWC");
6648 read_met_ml2pl(ctl, met, met->iwc, "IWC");
6649 read_met_ml2pl(ctl, met, met->swc, "SWC");
6650 read_met_ml2pl(ctl, met, met->cc, "CC");
6651
6652 /* Set new pressure levels... */
6653 met->np = ctl->met_np;
6654 for (int ip = 0; ip < met->np; ip++)
6655 met->p[ip] = ctl->met_p[ip];
6656 }
6657
6658 /* Check ordering of pressure levels... */
6659 for (int ip = 1; ip < met->np; ip++)
6660 if (met->p[ip - 1] < met->p[ip])
6661 ERRMSG("Pressure levels must be descending!");
6662}
6663
6664/*****************************************************************************/
6665
6667 ctl_t * ctl,
6668 met_t * met,
6669 float var[EX][EY][EP],
6670 char *varname) {
6671
6672 double aux[EP], p[EP];
6673
6674 /* Set timer... */
6675 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
6676 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
6677
6678 /* Loop over columns... */
6679#pragma omp parallel for default(shared) private(aux,p) collapse(2)
6680 for (int ix = 0; ix < met->nx; ix++)
6681 for (int iy = 0; iy < met->ny; iy++) {
6682
6683 /* Copy pressure profile... */
6684 for (int ip = 0; ip < met->np; ip++)
6685 p[ip] = met->pl[ix][iy][ip];
6686
6687 /* Interpolate... */
6688 for (int ip = 0; ip < ctl->met_np; ip++) {
6689 double pt = ctl->met_p[ip];
6690 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
6691 pt = p[0];
6692 else if ((pt > p[met->np - 1] && p[1] > p[0])
6693 || (pt < p[met->np - 1] && p[1] < p[0]))
6694 pt = p[met->np - 1];
6695 int ip2 = locate_irr(p, met->np, pt);
6696 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
6697 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
6698 }
6699
6700 /* Copy data... */
6701 for (int ip = 0; ip < ctl->met_np; ip++)
6702 var[ix][iy][ip] = (float) aux[ip];
6703 }
6704}
6705
6706/*****************************************************************************/
6707
6709 met_t * met) {
6710
6711 /* Set timer... */
6712 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
6713 LOG(2, "Make zeta profiles monotone...");
6714
6715 /* Create monotone zeta profiles... */
6716#pragma omp parallel for default(shared) collapse(2)
6717 for (int i = 0; i < met->nx; i++)
6718 for (int j = 0; j < met->ny; j++) {
6719 int k = 1;
6720
6721 while (k < met->npl) { /* Check if there is an inversion at level k... */
6722 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
6723 /* Find the upper level k+l over the inversion... */
6724 int l = 0;
6725 do {
6726 l++;
6727 }
6728 while ((met->zetal[i][j][k - 1] >=
6729 met->zetal[i][j][k + l]) & (k + l < met->npl));
6730
6731 /* Interpolate linear between the top and bottom
6732 of the inversion... */
6733 float s =
6734 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
6735 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
6736
6737 for (int m = k; m < k + l; m++) {
6738 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
6739 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
6740 }
6741
6742 /* Search for more inversions above the last inversion ... */
6743 k = k + l;
6744 } else {
6745 k++;
6746 }
6747 }
6748 }
6749
6750 /* Create monotone pressure profiles... */
6751#pragma omp parallel for default(shared) collapse(2)
6752 for (int i = 0; i < met->nx; i++)
6753 for (int j = 0; j < met->ny; j++) {
6754 int k = 1;
6755
6756 while (k < met->npl) { /* Check if there is an inversion at level k... */
6757 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
6758 /* Find the upper level k+l over the inversion... */
6759 int l = 0;
6760 do {
6761 l++;
6762 }
6763 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
6764 met->npl));
6765
6766 /* Interpolate linear between the top and bottom
6767 of the inversion... */
6768 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
6769 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
6770
6771 for (int m = k; m < k + l; m++) {
6772 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
6773 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
6774 }
6775
6776 /* Search for more inversions above the last inversion ... */
6777 k = k + l;
6778 } else {
6779 k++;
6780 }
6781 }
6782 }
6783}
6784
6785/*****************************************************************************/
6786
6788 int ncid,
6789 char *varname,
6790 char *varname2,
6791 char *varname3,
6792 char *varname4,
6793 ctl_t * ctl,
6794 met_t * met,
6795 float dest[EX][EY],
6796 float scl,
6797 int init) {
6798
6799 char varsel[LEN];
6800
6801 float offset, scalfac;
6802
6803 int varid;
6804
6805 /* Check if variable exists... */
6806 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
6807 sprintf(varsel, "%s", varname);
6808 else if (varname2 != NULL
6809 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
6810 sprintf(varsel, "%s", varname2);
6811 else if (varname3 != NULL
6812 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
6813 sprintf(varsel, "%s", varname3);
6814 else if (varname4 != NULL
6815 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
6816 sprintf(varsel, "%s", varname4);
6817 else
6818 return 0;
6819
6820 /* Read packed data... */
6821 if (ctl->met_nc_scale
6822 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
6823 && nc_get_att_float(ncid, varid, "scale_factor",
6824 &scalfac) == NC_NOERR) {
6825
6826 /* Allocate... */
6827 short *help;
6828 ALLOC(help, short,
6829 EX * EY * EP);
6830
6831 /* Read fill value and missing value... */
6832 short fillval, missval;
6833 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
6834 fillval = 0;
6835 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
6836 missval = 0;
6837
6838 /* Write info... */
6839 LOG(2, "Read 2-D variable: %s"
6840 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
6841 varsel, fillval, missval, scalfac, offset);
6842
6843 /* Read data... */
6844 NC(nc_get_var_short(ncid, varid, help));
6845
6846 /* Check meteo data layout... */
6847 if (ctl->met_convention != 0)
6848 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
6849
6850 /* Copy and check data... */
6851#pragma omp parallel for default(shared) num_threads(12)
6852 for (int ix = 0; ix < met->nx; ix++)
6853 for (int iy = 0; iy < met->ny; iy++) {
6854 if (init)
6855 dest[ix][iy] = 0;
6856 short aux = help[ARRAY_2D(iy, ix, met->nx)];
6857 if ((fillval == 0 || aux != fillval)
6858 && (missval == 0 || aux != missval)
6859 && fabsf(aux * scalfac + offset) < 1e14f)
6860 dest[ix][iy] += scl * (aux * scalfac + offset);
6861 else
6862 dest[ix][iy] = NAN;
6863 }
6864
6865 /* Free... */
6866 free(help);
6867 }
6868
6869 /* Unpacked data... */
6870 else {
6871
6872 /* Allocate... */
6873 float *help;
6874 ALLOC(help, float,
6875 EX * EY);
6876
6877 /* Read fill value and missing value... */
6878 float fillval, missval;
6879 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
6880 fillval = 0;
6881 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
6882 missval = 0;
6883
6884 /* Write info... */
6885 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
6886 varsel, fillval, missval);
6887
6888 /* Read data... */
6889 NC(nc_get_var_float(ncid, varid, help));
6890
6891 /* Check meteo data layout... */
6892 if (ctl->met_convention == 0) {
6893
6894 /* Copy and check data (ordering: lat, lon)... */
6895#pragma omp parallel for default(shared) num_threads(12)
6896 for (int ix = 0; ix < met->nx; ix++)
6897 for (int iy = 0; iy < met->ny; iy++) {
6898 if (init)
6899 dest[ix][iy] = 0;
6900 float aux = help[ARRAY_2D(iy, ix, met->nx)];
6901 if ((fillval == 0 || aux != fillval)
6902 && (missval == 0 || aux != missval)
6903 && fabsf(aux) < 1e14f)
6904 dest[ix][iy] += scl * aux;
6905 else
6906 dest[ix][iy] = NAN;
6907 }
6908
6909 } else {
6910
6911 /* Copy and check data (ordering: lon, lat)... */
6912#pragma omp parallel for default(shared) num_threads(12)
6913 for (int iy = 0; iy < met->ny; iy++)
6914 for (int ix = 0; ix < met->nx; ix++) {
6915 if (init)
6916 dest[ix][iy] = 0;
6917 float aux = help[ARRAY_2D(ix, iy, met->ny)];
6918 if ((fillval == 0 || aux != fillval)
6919 && (missval == 0 || aux != missval)
6920 && fabsf(aux) < 1e14f)
6921 dest[ix][iy] += scl * aux;
6922 else
6923 dest[ix][iy] = NAN;
6924 }
6925 }
6926
6927 /* Free... */
6928 free(help);
6929 }
6930
6931 /* Return... */
6932 return 1;
6933}
6934
6935/*****************************************************************************/
6936
6938 int ncid,
6939 char *varname,
6940 char *varname2,
6941 char *varname3,
6942 char *varname4,
6943 ctl_t * ctl,
6944 met_t * met,
6945 float dest[EX][EY][EP],
6946 float scl) {
6947
6948 char varsel[LEN];
6949
6950 float offset, scalfac;
6951
6952 int varid;
6953
6954 /* Check if variable exists... */
6955 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
6956 sprintf(varsel, "%s", varname);
6957 else if (varname2 != NULL
6958 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
6959 sprintf(varsel, "%s", varname2);
6960 else if (varname3 != NULL
6961 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
6962 sprintf(varsel, "%s", varname3);
6963 else if (varname4 != NULL
6964 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
6965 sprintf(varsel, "%s", varname4);
6966 else
6967 return 0;
6968
6969 /* Read packed data... */
6970 if (ctl->met_nc_scale
6971 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
6972 && nc_get_att_float(ncid, varid, "scale_factor",
6973 &scalfac) == NC_NOERR) {
6974
6975 /* Allocate... */
6976 short *help;
6977 ALLOC(help, short,
6978 EX * EY * EP);
6979
6980 /* Read fill value and missing value... */
6981 short fillval, missval;
6982 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
6983 fillval = 0;
6984 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
6985 missval = 0;
6986
6987 /* Write info... */
6988 LOG(2, "Read 3-D variable: %s "
6989 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
6990 varsel, fillval, missval, scalfac, offset);
6991
6992 /* Read data... */
6993 NC(nc_get_var_short(ncid, varid, help));
6994
6995 /* Check meteo data layout... */
6996 if (ctl->met_convention != 0)
6997 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
6998
6999 /* Copy and check data... */
7000#pragma omp parallel for default(shared) num_threads(12)
7001 for (int ix = 0; ix < met->nx; ix++)
7002 for (int iy = 0; iy < met->ny; iy++)
7003 for (int ip = 0; ip < met->np; ip++) {
7004 short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7005 if ((fillval == 0 || aux != fillval)
7006 && (missval == 0 || aux != missval)
7007 && fabsf(aux * scalfac + offset) < 1e14f)
7008 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
7009 else
7010 dest[ix][iy][ip] = NAN;
7011 }
7012
7013 /* Free... */
7014 free(help);
7015 }
7016
7017 /* Unpacked data... */
7018 else {
7019
7020 /* Allocate... */
7021 float *help;
7022 ALLOC(help, float,
7023 EX * EY * EP);
7024
7025 /* Read fill value and missing value... */
7026 float fillval, missval;
7027 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7028 fillval = 0;
7029 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7030 missval = 0;
7031
7032 /* Write info... */
7033 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
7034 varsel, fillval, missval);
7035
7036 /* Read data... */
7037 NC(nc_get_var_float(ncid, varid, help));
7038
7039 /* Check meteo data layout... */
7040 if (ctl->met_convention == 0) {
7041
7042 /* Copy and check data (ordering: lev, lat, lon)... */
7043#pragma omp parallel for default(shared) num_threads(12)
7044 for (int ix = 0; ix < met->nx; ix++)
7045 for (int iy = 0; iy < met->ny; iy++)
7046 for (int ip = 0; ip < met->np; ip++) {
7047 float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7048 if ((fillval == 0 || aux != fillval)
7049 && (missval == 0 || aux != missval)
7050 && fabsf(aux) < 1e14f)
7051 dest[ix][iy][ip] = scl * aux;
7052 else
7053 dest[ix][iy][ip] = NAN;
7054 }
7055
7056 } else {
7057
7058 /* Copy and check data (ordering: lon, lat, lev)... */
7059#pragma omp parallel for default(shared) num_threads(12)
7060 for (int ip = 0; ip < met->np; ip++)
7061 for (int iy = 0; iy < met->ny; iy++)
7062 for (int ix = 0; ix < met->nx; ix++) {
7063 float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7064 if ((fillval == 0 || aux != fillval)
7065 && (missval == 0 || aux != missval)
7066 && fabsf(aux) < 1e14f)
7067 dest[ix][iy][ip] = scl * aux;
7068 else
7069 dest[ix][iy][ip] = NAN;
7070 }
7071 }
7072
7073 /* Free... */
7074 free(help);
7075 }
7076
7077 /* Return... */
7078 return 1;
7079}
7080
7081/*****************************************************************************/
7082
7084 met_t * met) {
7085
7086 /* Set timer... */
7087 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
7088 LOG(2, "Calculate planetary boundary layer...");
7089
7090 /* Parameters used to estimate the height of the PBL
7091 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
7092 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
7093
7094 /* Loop over grid points... */
7095#pragma omp parallel for default(shared) collapse(2)
7096 for (int ix = 0; ix < met->nx; ix++)
7097 for (int iy = 0; iy < met->ny; iy++) {
7098
7099 /* Set bottom level of PBL... */
7100 double pbl_bot = met->ps[ix][iy] + DZ2DP(dz, met->ps[ix][iy]);
7101
7102 /* Find lowest level near the bottom... */
7103 int ip;
7104 for (ip = 1; ip < met->np; ip++)
7105 if (met->p[ip] < pbl_bot)
7106 break;
7107
7108 /* Get near surface data... */
7109 double zs = LIN(met->p[ip - 1], met->z[ix][iy][ip - 1],
7110 met->p[ip], met->z[ix][iy][ip], pbl_bot);
7111 double ts = LIN(met->p[ip - 1], met->t[ix][iy][ip - 1],
7112 met->p[ip], met->t[ix][iy][ip], pbl_bot);
7113 double us = LIN(met->p[ip - 1], met->u[ix][iy][ip - 1],
7114 met->p[ip], met->u[ix][iy][ip], pbl_bot);
7115 double vs = LIN(met->p[ip - 1], met->v[ix][iy][ip - 1],
7116 met->p[ip], met->v[ix][iy][ip], pbl_bot);
7117 double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
7118 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
7119 double tvs = THETAVIRT(pbl_bot, ts, h2os);
7120
7121 /* Init... */
7122 double rib_old = 0;
7123
7124 /* Loop over levels... */
7125 for (; ip < met->np; ip++) {
7126
7127 /* Get squared horizontal wind speed... */
7128 double vh2
7129 = SQR(met->u[ix][iy][ip] - us) + SQR(met->v[ix][iy][ip] - vs);
7130 vh2 = MAX(vh2, SQR(umin));
7131
7132 /* Calculate bulk Richardson number... */
7133 double rib = G0 * 1e3 * (met->z[ix][iy][ip] - zs) / tvs
7134 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
7135 met->h2o[ix][iy][ip]) - tvs) / vh2;
7136
7137 /* Check for critical value... */
7138 if (rib >= rib_crit) {
7139 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
7140 rib, met->p[ip], rib_crit));
7141 if (met->pbl[ix][iy] > pbl_bot)
7142 met->pbl[ix][iy] = (float) pbl_bot;
7143 break;
7144 }
7145
7146 /* Save Richardson number... */
7147 rib_old = rib;
7148 }
7149 }
7150}
7151
7152/*****************************************************************************/
7153
7155 met_t * met) {
7156
7157 /* Set timer... */
7158 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
7159 LOG(2, "Apply periodic boundary conditions...");
7160
7161 /* Check longitudes... */
7162 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
7163 + met->lon[1] - met->lon[0] - 360) < 0.01))
7164 return;
7165
7166 /* Increase longitude counter... */
7167 if ((++met->nx) >= EX)
7168 ERRMSG("Cannot create periodic boundary conditions!");
7169
7170 /* Set longitude... */
7171 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
7172
7173 /* Loop over latitudes and pressure levels... */
7174#pragma omp parallel for default(shared)
7175 for (int iy = 0; iy < met->ny; iy++) {
7176 met->ps[met->nx - 1][iy] = met->ps[0][iy];
7177 met->zs[met->nx - 1][iy] = met->zs[0][iy];
7178 met->ts[met->nx - 1][iy] = met->ts[0][iy];
7179 met->us[met->nx - 1][iy] = met->us[0][iy];
7180 met->vs[met->nx - 1][iy] = met->vs[0][iy];
7181 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
7182 met->sst[met->nx - 1][iy] = met->sst[0][iy];
7183 for (int ip = 0; ip < met->np; ip++) {
7184 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
7185 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
7186 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
7187 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
7188 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
7189 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
7190 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
7191 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
7192 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
7193 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
7194 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
7195 }
7196 for (int ip = 0; ip < met->npl; ip++) {
7197 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
7198 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
7199 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
7200 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
7201 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
7202 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
7203 }
7204 }
7205}
7206
7207/*****************************************************************************/
7208
7210 met_t * met) {
7211
7212 /* Set timer... */
7213 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
7214 LOG(2, "Apply fix for polar winds...");
7215
7216 /* Check latitudes... */
7217 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
7218 return;
7219
7220 /* Loop over hemispheres... */
7221 for (int ihem = 0; ihem < 2; ihem++) {
7222
7223 /* Set latitude indices... */
7224 int i89 = 1, i90 = 0, sign = 1;
7225 if (ihem == 1) {
7226 i89 = met->ny - 2;
7227 i90 = met->ny - 1;
7228 }
7229 if (met->lat[i90] < 0)
7230 sign = -1;
7231
7232 /* Look-up table of cosinus and sinus... */
7233 double clon[EX], slon[EX];
7234#pragma omp parallel for default(shared)
7235 for (int ix = 0; ix < met->nx; ix++) {
7236 clon[ix] = cos(sign * met->lon[ix] / 180. * M_PI);
7237 slon[ix] = sin(sign * met->lon[ix] / 180. * M_PI);
7238 }
7239
7240 /* Loop over levels... */
7241#pragma omp parallel for default(shared)
7242 for (int ip = 0; ip < met->np; ip++) {
7243
7244 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
7245 double vel89x = 0, vel89y = 0;
7246 for (int ix = 0; ix < met->nx; ix++) {
7247 vel89x +=
7248 (met->u[ix][i89][ip] * clon[ix] -
7249 met->v[ix][i89][ip] * slon[ix]) / met->nx;
7250 vel89y +=
7251 (met->u[ix][i89][ip] * slon[ix] +
7252 met->v[ix][i89][ip] * clon[ix]) / met->nx;
7253 }
7254
7255 /* Replace 90 degree winds by 89 degree mean... */
7256 for (int ix = 0; ix < met->nx; ix++) {
7257 met->u[ix][i90][ip]
7258 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
7259 met->v[ix][i90][ip]
7260 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
7261 }
7262 }
7263 }
7264}
7265
7266/*****************************************************************************/
7267
7269 met_t * met) {
7270
7271 double pows[EP];
7272
7273 /* Set timer... */
7274 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
7275 LOG(2, "Calculate potential vorticity...");
7276
7277 /* Set powers... */
7278#pragma omp parallel for default(shared)
7279 for (int ip = 0; ip < met->np; ip++)
7280 pows[ip] = pow(1000. / met->p[ip], 0.286);
7281
7282 /* Loop over grid points... */
7283#pragma omp parallel for default(shared)
7284 for (int ix = 0; ix < met->nx; ix++) {
7285
7286 /* Set indices... */
7287 int ix0 = MAX(ix - 1, 0);
7288 int ix1 = MIN(ix + 1, met->nx - 1);
7289
7290 /* Loop over grid points... */
7291 for (int iy = 0; iy < met->ny; iy++) {
7292
7293 /* Set indices... */
7294 int iy0 = MAX(iy - 1, 0);
7295 int iy1 = MIN(iy + 1, met->ny - 1);
7296
7297 /* Set auxiliary variables... */
7298 double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
7299 double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
7300 double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
7301 double c0 = cos(met->lat[iy0] / 180. * M_PI);
7302 double c1 = cos(met->lat[iy1] / 180. * M_PI);
7303 double cr = cos(latr / 180. * M_PI);
7304 double vort = 2 * 7.2921e-5 * sin(latr * M_PI / 180.);
7305
7306 /* Loop over grid points... */
7307 for (int ip = 0; ip < met->np; ip++) {
7308
7309 /* Get gradients in longitude... */
7310 double dtdx
7311 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
7312 double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
7313
7314 /* Get gradients in latitude... */
7315 double dtdy
7316 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
7317 double dudy
7318 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
7319
7320 /* Set indices... */
7321 int ip0 = MAX(ip - 1, 0);
7322 int ip1 = MIN(ip + 1, met->np - 1);
7323
7324 /* Get gradients in pressure... */
7325 double dtdp, dudp, dvdp;
7326 double dp0 = 100. * (met->p[ip] - met->p[ip0]);
7327 double dp1 = 100. * (met->p[ip1] - met->p[ip]);
7328 if (ip != ip0 && ip != ip1) {
7329 double denom = dp0 * dp1 * (dp0 + dp1);
7330 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
7331 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
7332 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
7333 / denom;
7334 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
7335 - dp1 * dp1 * met->u[ix][iy][ip0]
7336 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
7337 / denom;
7338 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
7339 - dp1 * dp1 * met->v[ix][iy][ip0]
7340 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
7341 / denom;
7342 } else {
7343 double denom = dp0 + dp1;
7344 dtdp =
7345 (met->t[ix][iy][ip1] * pows[ip1] -
7346 met->t[ix][iy][ip0] * pows[ip0]) / denom;
7347 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
7348 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
7349 }
7350
7351 /* Calculate PV... */
7352 met->pv[ix][iy][ip] = (float)
7353 (1e6 * G0 *
7354 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
7355 }
7356 }
7357 }
7358
7359 /* Fix for polar regions... */
7360#pragma omp parallel for default(shared)
7361 for (int ix = 0; ix < met->nx; ix++)
7362 for (int ip = 0; ip < met->np; ip++) {
7363 met->pv[ix][0][ip]
7364 = met->pv[ix][1][ip]
7365 = met->pv[ix][2][ip];
7366 met->pv[ix][met->ny - 1][ip]
7367 = met->pv[ix][met->ny - 2][ip]
7368 = met->pv[ix][met->ny - 3][ip];
7369 }
7370}
7371
7372/*****************************************************************************/
7373
7375 met_t * met) {
7376
7377 /* Set timer... */
7378 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
7379 LOG(2, "Calculate total column ozone...");
7380
7381 /* Loop over columns... */
7382#pragma omp parallel for default(shared) collapse(2)
7383 for (int ix = 0; ix < met->nx; ix++)
7384 for (int iy = 0; iy < met->ny; iy++) {
7385
7386 /* Integrate... */
7387 double cd = 0;
7388 for (int ip = 1; ip < met->np; ip++)
7389 if (met->p[ip - 1] <= met->ps[ix][iy]) {
7390 double vmr = 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
7391 double dp = met->p[ip - 1] - met->p[ip];
7392 cd += vmr * MO3 / MA * dp * 1e2 / G0;
7393 }
7394
7395 /* Convert to Dobson units... */
7396 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
7397 }
7398}
7399
7400/*****************************************************************************/
7401
7403 ctl_t * ctl,
7404 met_t * met) {
7405
7406 met_t *help;
7407
7408 /* Check parameters... */
7409 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
7410 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
7411 return;
7412
7413 /* Set timer... */
7414 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
7415 LOG(2, "Downsampling of meteo data...");
7416
7417 /* Allocate... */
7418 ALLOC(help, met_t, 1);
7419
7420 /* Copy data... */
7421 help->nx = met->nx;
7422 help->ny = met->ny;
7423 help->np = met->np;
7424 memcpy(help->lon, met->lon, sizeof(met->lon));
7425 memcpy(help->lat, met->lat, sizeof(met->lat));
7426 memcpy(help->p, met->p, sizeof(met->p));
7427
7428 /* Smoothing... */
7429 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
7430 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
7431 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
7432 help->ps[ix][iy] = 0;
7433 help->zs[ix][iy] = 0;
7434 help->ts[ix][iy] = 0;
7435 help->us[ix][iy] = 0;
7436 help->vs[ix][iy] = 0;
7437 help->lsm[ix][iy] = 0;
7438 help->sst[ix][iy] = 0;
7439 help->t[ix][iy][ip] = 0;
7440 help->u[ix][iy][ip] = 0;
7441 help->v[ix][iy][ip] = 0;
7442 help->w[ix][iy][ip] = 0;
7443 help->h2o[ix][iy][ip] = 0;
7444 help->o3[ix][iy][ip] = 0;
7445 help->lwc[ix][iy][ip] = 0;
7446 help->rwc[ix][iy][ip] = 0;
7447 help->iwc[ix][iy][ip] = 0;
7448 help->swc[ix][iy][ip] = 0;
7449 help->cc[ix][iy][ip] = 0;
7450 float wsum = 0;
7451 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
7452 ix2++) {
7453 int ix3 = ix2;
7454 if (ix3 < 0)
7455 ix3 += met->nx;
7456 else if (ix3 >= met->nx)
7457 ix3 -= met->nx;
7458
7459 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
7460 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
7461 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
7462 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
7463 float w = (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
7464 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
7465 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
7466 help->ps[ix][iy] += w * met->ps[ix3][iy2];
7467 help->zs[ix][iy] += w * met->zs[ix3][iy2];
7468 help->ts[ix][iy] += w * met->ts[ix3][iy2];
7469 help->us[ix][iy] += w * met->us[ix3][iy2];
7470 help->vs[ix][iy] += w * met->vs[ix3][iy2];
7471 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
7472 help->sst[ix][iy] += w * met->sst[ix3][iy2];
7473 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
7474 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
7475 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
7476 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
7477 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
7478 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
7479 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
7480 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
7481 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
7482 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
7483 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
7484 wsum += w;
7485 }
7486 }
7487 help->ps[ix][iy] /= wsum;
7488 help->zs[ix][iy] /= wsum;
7489 help->ts[ix][iy] /= wsum;
7490 help->us[ix][iy] /= wsum;
7491 help->vs[ix][iy] /= wsum;
7492 help->lsm[ix][iy] /= wsum;
7493 help->sst[ix][iy] /= wsum;
7494 help->t[ix][iy][ip] /= wsum;
7495 help->u[ix][iy][ip] /= wsum;
7496 help->v[ix][iy][ip] /= wsum;
7497 help->w[ix][iy][ip] /= wsum;
7498 help->h2o[ix][iy][ip] /= wsum;
7499 help->o3[ix][iy][ip] /= wsum;
7500 help->lwc[ix][iy][ip] /= wsum;
7501 help->rwc[ix][iy][ip] /= wsum;
7502 help->iwc[ix][iy][ip] /= wsum;
7503 help->swc[ix][iy][ip] /= wsum;
7504 help->cc[ix][iy][ip] /= wsum;
7505 }
7506 }
7507 }
7508
7509 /* Downsampling... */
7510 met->nx = 0;
7511 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
7512 met->lon[met->nx] = help->lon[ix];
7513 met->ny = 0;
7514 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
7515 met->lat[met->ny] = help->lat[iy];
7516 met->ps[met->nx][met->ny] = help->ps[ix][iy];
7517 met->zs[met->nx][met->ny] = help->zs[ix][iy];
7518 met->ts[met->nx][met->ny] = help->ts[ix][iy];
7519 met->us[met->nx][met->ny] = help->us[ix][iy];
7520 met->vs[met->nx][met->ny] = help->vs[ix][iy];
7521 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
7522 met->sst[met->nx][met->ny] = help->sst[ix][iy];
7523 met->np = 0;
7524 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
7525 met->p[met->np] = help->p[ip];
7526 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
7527 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
7528 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
7529 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
7530 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
7531 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
7532 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
7533 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
7534 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
7535 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
7536 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
7537 met->np++;
7538 }
7539 met->ny++;
7540 }
7541 met->nx++;
7542 }
7543
7544 /* Free... */
7545 free(help);
7546}
7547
7548/*****************************************************************************/
7549
7551 int ncid,
7552 met_t * met,
7553 ctl_t * ctl) {
7554
7555 /* Set timer... */
7556 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
7557 LOG(2, "Read surface data...");
7558
7559 /* MPTRAC meteo data... */
7560 if (ctl->met_clams == 0) {
7561
7562 /* Read surface pressure... */
7563 if (read_met_nc_2d
7564 (ncid, "lnsp", "LNSP", NULL, NULL, ctl, met, met->ps, 1.0f, 1)) {
7565 for (int ix = 0; ix < met->nx; ix++)
7566 for (int iy = 0; iy < met->ny; iy++)
7567 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
7568 } else
7569 if (!read_met_nc_2d
7570 (ncid, "ps", "PS", "sp", "SP", ctl, met, met->ps, 0.01f, 1)) {
7571 WARN("Cannot not read surface pressure data (use lowest level)!");
7572 for (int ix = 0; ix < met->nx; ix++)
7573 for (int iy = 0; iy < met->ny; iy++)
7574 met->ps[ix][iy] = (float) met->p[0];
7575 }
7576
7577 /* Read geopotential height at the surface... */
7578 if (!read_met_nc_2d
7579 (ncid, "z", "Z", NULL, NULL, ctl, met, met->zs,
7580 (float) (1. / (1000. * G0)), 1))
7581 if (!read_met_nc_2d
7582 (ncid, "zm", "ZM", NULL, NULL, ctl, met, met->zs,
7583 (float) (1. / 1000.), 1))
7584 WARN("Cannot read surface geopotential height!");
7585
7586 /* Read temperature at the surface... */
7587 if (!read_met_nc_2d
7588 (ncid, "t2m", "T2M", "2t", "2T", ctl, met, met->ts, 1.0, 1))
7589 WARN("Cannot read surface temperature!");
7590
7591 /* Read zonal wind at the surface... */
7592 if (!read_met_nc_2d
7593 (ncid, "u10m", "U10M", "10u", "10U", ctl, met, met->us, 1.0, 1))
7594 WARN("Cannot read surface zonal wind!");
7595
7596 /* Read meridional wind at the surface... */
7597 if (!read_met_nc_2d
7598 (ncid, "v10m", "V10M", "10v", "10V", ctl, met, met->vs, 1.0, 1))
7599 WARN("Cannot read surface meridional wind!");
7600
7601 /* Read land-sea mask... */
7602 if (!read_met_nc_2d
7603 (ncid, "lsm", "LSM", NULL, NULL, ctl, met, met->lsm, 1.0, 1))
7604 WARN("Cannot read land-sea mask!");
7605
7606 /* Read sea surface temperature... */
7607 if (!read_met_nc_2d
7608 (ncid, "sstk", "SSTK", "sst", "SST", ctl, met, met->sst, 1.0, 1))
7609 WARN("Cannot read sea surface temperature!");
7610 }
7611
7612 /* CLaMS meteo data... */
7613 else {
7614
7615 /* Read surface pressure... */
7616 if (!read_met_nc_2d
7617 (ncid, "ps", "PS", NULL, NULL, ctl, met, met->ps, 0.01f, 1)) {
7618 WARN("Cannot not read surface pressure data (use lowest level)!");
7619 for (int ix = 0; ix < met->nx; ix++)
7620 for (int iy = 0; iy < met->ny; iy++)
7621 met->ps[ix][iy] = (float) met->p[0];
7622 }
7623
7624 /* Read geopotential height at the surface
7625 (use lowermost level of 3-D data field)... */
7626 float *help;
7627 ALLOC(help, float,
7628 EX * EY * EP);
7629 memcpy(help, met->pl, sizeof(met->pl));
7630 if (!read_met_nc_3d
7631 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
7632 (float) (1e-3 / G0))) {
7633 ERRMSG("Cannot read geopotential height!");
7634 } else
7635 for (int ix = 0; ix < met->nx; ix++)
7636 for (int iy = 0; iy < met->ny; iy++)
7637 met->zs[ix][iy] = met->pl[ix][iy][0];
7638 memcpy(met->pl, help, sizeof(met->pl));
7639 free(help);
7640
7641 /* Read temperature at the surface... */
7642 if (!read_met_nc_2d
7643 (ncid, "t2", "T2", NULL, NULL, ctl, met, met->ts, 1.0, 1))
7644 WARN("Cannot read surface temperature!");
7645
7646 /* Read zonal wind at the surface... */
7647 if (!read_met_nc_2d
7648 (ncid, "u10", "U10", NULL, NULL, ctl, met, met->us, 1.0, 1))
7649 WARN("Cannot read surface zonal wind!");
7650
7651 /* Read meridional wind at the surface... */
7652 if (!read_met_nc_2d
7653 (ncid, "v10", "V10", NULL, NULL, ctl, met, met->vs, 1.0, 1))
7654 WARN("Cannot read surface meridional wind!");
7655
7656 /* Read land-sea mask... */
7657 if (!read_met_nc_2d
7658 (ncid, "lsm", "LSM", NULL, NULL, ctl, met, met->lsm, 1.0, 1))
7659 WARN("Cannot read land-sea mask!");
7660
7661 /* Read sea surface temperature... */
7662 if (!read_met_nc_2d
7663 (ncid, "sstk", "SSTK", NULL, NULL, ctl, met, met->sst, 1.0, 1))
7664 WARN("Cannot read sea surface temperature!");
7665 }
7666}
7667
7668/*****************************************************************************/
7669
7671 ctl_t * ctl,
7672 clim_t * clim,
7673 met_t * met) {
7674
7675 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
7676 th2[200], z[EP], z2[200];
7677
7678 /* Set timer... */
7679 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
7680 LOG(2, "Calculate tropopause...");
7681
7682 /* Get altitude and pressure profiles... */
7683#pragma omp parallel for default(shared)
7684 for (int iz = 0; iz < met->np; iz++)
7685 z[iz] = Z(met->p[iz]);
7686#pragma omp parallel for default(shared)
7687 for (int iz = 0; iz <= 190; iz++) {
7688 z2[iz] = 4.5 + 0.1 * iz;
7689 p2[iz] = P(z2[iz]);
7690 }
7691
7692 /* Do not calculate tropopause... */
7693 if (ctl->met_tropo == 0)
7694#pragma omp parallel for default(shared) collapse(2)
7695 for (int ix = 0; ix < met->nx; ix++)
7696 for (int iy = 0; iy < met->ny; iy++)
7697 met->pt[ix][iy] = NAN;
7698
7699 /* Use tropopause climatology... */
7700 else if (ctl->met_tropo == 1) {
7701#pragma omp parallel for default(shared) collapse(2)
7702 for (int ix = 0; ix < met->nx; ix++)
7703 for (int iy = 0; iy < met->ny; iy++)
7704 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
7705 }
7706
7707 /* Use cold point... */
7708 else if (ctl->met_tropo == 2) {
7709
7710 /* Loop over grid points... */
7711#pragma omp parallel for default(shared) private(t,t2) collapse(2)
7712 for (int ix = 0; ix < met->nx; ix++)
7713 for (int iy = 0; iy < met->ny; iy++) {
7714
7715 /* Interpolate temperature profile... */
7716 for (int iz = 0; iz < met->np; iz++)
7717 t[iz] = met->t[ix][iy][iz];
7718 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
7719
7720 /* Find minimum... */
7721 int iz = (int) gsl_stats_min_index(t2, 1, 171);
7722 if (iz > 0 && iz < 170)
7723 met->pt[ix][iy] = (float) p2[iz];
7724 else
7725 met->pt[ix][iy] = NAN;
7726 }
7727 }
7728
7729 /* Use WMO definition... */
7730 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
7731
7732 /* Loop over grid points... */
7733#pragma omp parallel for default(shared) private(t,t2) collapse(2)
7734 for (int ix = 0; ix < met->nx; ix++)
7735 for (int iy = 0; iy < met->ny; iy++) {
7736
7737 /* Interpolate temperature profile... */
7738 int iz;
7739 for (iz = 0; iz < met->np; iz++)
7740 t[iz] = met->t[ix][iy][iz];
7741 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
7742
7743 /* Find 1st tropopause... */
7744 met->pt[ix][iy] = NAN;
7745 for (iz = 0; iz <= 170; iz++) {
7746 int found = 1;
7747 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
7748 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
7749 found = 0;
7750 break;
7751 }
7752 if (found) {
7753 if (iz > 0 && iz < 170)
7754 met->pt[ix][iy] = (float) p2[iz];
7755 break;
7756 }
7757 }
7758
7759 /* Find 2nd tropopause... */
7760 if (ctl->met_tropo == 4) {
7761 met->pt[ix][iy] = NAN;
7762 for (; iz <= 170; iz++) {
7763 int found = 1;
7764 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
7765 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
7766 found = 0;
7767 break;
7768 }
7769 if (found)
7770 break;
7771 }
7772 for (; iz <= 170; iz++) {
7773 int found = 1;
7774 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
7775 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
7776 found = 0;
7777 break;
7778 }
7779 if (found) {
7780 if (iz > 0 && iz < 170)
7781 met->pt[ix][iy] = (float) p2[iz];
7782 break;
7783 }
7784 }
7785 }
7786 }
7787 }
7788
7789 /* Use dynamical tropopause... */
7790 else if (ctl->met_tropo == 5) {
7791
7792 /* Loop over grid points... */
7793#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
7794 for (int ix = 0; ix < met->nx; ix++)
7795 for (int iy = 0; iy < met->ny; iy++) {
7796
7797 /* Interpolate potential vorticity profile... */
7798 for (int iz = 0; iz < met->np; iz++)
7799 pv[iz] = met->pv[ix][iy][iz];
7800 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
7801
7802 /* Interpolate potential temperature profile... */
7803 for (int iz = 0; iz < met->np; iz++)
7804 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
7805 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
7806
7807 /* Find dynamical tropopause... */
7808 met->pt[ix][iy] = NAN;
7809 for (int iz = 0; iz <= 170; iz++)
7810 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
7811 || th2[iz] >= ctl->met_tropo_theta) {
7812 if (iz > 0 && iz < 170)
7813 met->pt[ix][iy] = (float) p2[iz];
7814 break;
7815 }
7816 }
7817 }
7818
7819 else
7820 ERRMSG("Cannot calculate tropopause!");
7821
7822 /* Interpolate temperature, geopotential height, and water vapor... */
7823#pragma omp parallel for default(shared) collapse(2)
7824 for (int ix = 0; ix < met->nx; ix++)
7825 for (int iy = 0; iy < met->ny; iy++) {
7826 double h2ot, tt, zt;
7828 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
7829 met->lat[iy], &tt, ci, cw, 1);
7830 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
7831 met->lat[iy], &zt, ci, cw, 0);
7832 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
7833 met->lat[iy], &h2ot, ci, cw, 0);
7834 met->tt[ix][iy] = (float) tt;
7835 met->zt[ix][iy] = (float) zt;
7836 met->h2ot[ix][iy] = (float) h2ot;
7837 }
7838}
7839
7840/*****************************************************************************/
7841
7843 const char *filename,
7844 ctl_t * ctl,
7845 double *rt,
7846 double *rz,
7847 double *rlon,
7848 double *rlat,
7849 double *robs,
7850 int *nobs) {
7851
7852 /* Write info... */
7853 LOG(1, "Read observation data: %s", filename);
7854
7855 /* Read data... */
7856 if (ctl->obs_type == 0)
7857 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
7858 else if (ctl->obs_type == 1)
7859 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
7860 else
7861 ERRMSG("Set OBS_TYPE to 0 or 1!");
7862
7863 /* Check time... */
7864 for (int i = 1; i < *nobs; i++)
7865 if (rt[i] < rt[i - 1])
7866 ERRMSG("Time must be ascending!");
7867
7868 /* Write info... */
7869 int n = *nobs;
7870 double mini, maxi;
7871 LOG(2, "Number of observations: %d", *nobs);
7872 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
7873 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
7874 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
7875 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
7876 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
7877 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
7878 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
7879 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
7880 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
7881 LOG(2, "Observation range: %g ... %g", mini, maxi);
7882}
7883
7884/*****************************************************************************/
7885
7887 const char *filename,
7888 double *rt,
7889 double *rz,
7890 double *rlon,
7891 double *rlat,
7892 double *robs,
7893 int *nobs) {
7894
7895 /* Open observation data file... */
7896 FILE *in;
7897 if (!(in = fopen(filename, "r")))
7898 ERRMSG("Cannot open file!");
7899
7900 /* Read observations... */
7901 char line[LEN];
7902 while (fgets(line, LEN, in))
7903 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
7904 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
7905 if ((++(*nobs)) >= NOBS)
7906 ERRMSG("Too many observations!");
7907
7908 /* Close observation data file... */
7909 fclose(in);
7910}
7911
7912/*****************************************************************************/
7913
7915 const char *filename,
7916 double *rt,
7917 double *rz,
7918 double *rlon,
7919 double *rlat,
7920 double *robs,
7921 int *nobs) {
7922
7923 int ncid, varid;
7924
7925 /* Open netCDF file... */
7926 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7927 ERRMSG("Cannot open file!");
7928
7929 /* Read the observations from the NetCDF file... */
7930 NC_INQ_DIM("nobs", nobs, 1, NOBS);
7931 NC_GET_DOUBLE("time", rt, 1);
7932 NC_GET_DOUBLE("alt", rz, 1);
7933 NC_GET_DOUBLE("lon", rlon, 1);
7934 NC_GET_DOUBLE("lat", rlat, 1);
7935 NC_GET_DOUBLE("obs", robs, 1);
7936
7937 /* Close file... */
7938 NC(nc_close(ncid));
7939}
7940
7941/*****************************************************************************/
7942
7944 const char *filename,
7945 int argc,
7946 char *argv[],
7947 const char *varname,
7948 int arridx,
7949 const char *defvalue,
7950 char *value) {
7951
7952 FILE *in = NULL;
7953
7954 char fullname1[LEN], fullname2[LEN], rval[LEN];
7955
7956 int contain = 0, i;
7957
7958 /* Open file... */
7959 if (filename[strlen(filename) - 1] != '-')
7960 if (!(in = fopen(filename, "r")))
7961 ERRMSG("Cannot open file!");
7962
7963 /* Set full variable name... */
7964 if (arridx >= 0) {
7965 sprintf(fullname1, "%s[%d]", varname, arridx);
7966 sprintf(fullname2, "%s[*]", varname);
7967 } else {
7968 sprintf(fullname1, "%s", varname);
7969 sprintf(fullname2, "%s", varname);
7970 }
7971
7972 /* Read data... */
7973 if (in != NULL) {
7974 char dummy[LEN], line[LEN], rvarname[LEN];
7975 while (fgets(line, LEN, in)) {
7976 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
7977 if (strcasecmp(rvarname, fullname1) == 0 ||
7978 strcasecmp(rvarname, fullname2) == 0) {
7979 contain = 1;
7980 break;
7981 }
7982 }
7983 }
7984 for (i = 1; i < argc - 1; i++)
7985 if (strcasecmp(argv[i], fullname1) == 0 ||
7986 strcasecmp(argv[i], fullname2) == 0) {
7987 sprintf(rval, "%s", argv[i + 1]);
7988 contain = 1;
7989 break;
7990 }
7991
7992 /* Close file... */
7993 if (in != NULL)
7994 fclose(in);
7995
7996 /* Check for missing variables... */
7997 if (!contain) {
7998 if (strlen(defvalue) > 0)
7999 sprintf(rval, "%s", defvalue);
8000 else
8001 ERRMSG("Missing variable %s!\n", fullname1);
8002 }
8003
8004 /* Write info... */
8005 LOG(1, "%s = %s", fullname1, rval);
8006
8007 /* Return values... */
8008 if (value != NULL)
8009 sprintf(value, "%s", rval);
8010 return atof(rval);
8011}
8012
8013/*****************************************************************************/
8014
8015double sedi(
8016 const double p,
8017 const double T,
8018 const double rp,
8019 const double rhop) {
8020
8021 /* Convert particle radius from microns to m... */
8022 double rp_help = rp * 1e-6;
8023
8024 /* Density of dry air [kg / m^3]... */
8025 double rho = RHO(p, T);
8026
8027 /* Dynamic viscosity of air [kg / (m s)]... */
8028 double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
8029
8030 /* Thermal velocity of an air molecule [m / s]... */
8031 double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
8032
8033 /* Mean free path of an air molecule [m]... */
8034 double lambda = 2. * eta / (rho * v);
8035
8036 /* Knudsen number for air (dimensionless)... */
8037 double K = lambda / rp_help;
8038
8039 /* Cunningham slip-flow correction (dimensionless)... */
8040 double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
8041
8042 /* Sedimentation velocity [m / s]... */
8043 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
8044}
8045
8046/*****************************************************************************/
8047
8049 const double *x,
8050 const double *y,
8051 const int n,
8052 const double *x2,
8053 double *y2,
8054 const int n2,
8055 const int method) {
8056
8057 /* Cubic spline interpolation... */
8058 if (method == 1) {
8059
8060 /* Allocate... */
8061 gsl_interp_accel *acc;
8062 gsl_spline *s;
8063 acc = gsl_interp_accel_alloc();
8064 s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
8065
8066 /* Interpolate profile... */
8067 gsl_spline_init(s, x, y, (size_t) n);
8068 for (int i = 0; i < n2; i++)
8069 if (x2[i] <= x[0])
8070 y2[i] = y[0];
8071 else if (x2[i] >= x[n - 1])
8072 y2[i] = y[n - 1];
8073 else
8074 y2[i] = gsl_spline_eval(s, x2[i], acc);
8075
8076 /* Free... */
8077 gsl_spline_free(s);
8078 gsl_interp_accel_free(acc);
8079 }
8080
8081 /* Linear interpolation... */
8082 else {
8083 for (int i = 0; i < n2; i++)
8084 if (x2[i] <= x[0])
8085 y2[i] = y[0];
8086 else if (x2[i] >= x[n - 1])
8087 y2[i] = y[n - 1];
8088 else {
8089 int idx = locate_irr(x, n, x2[i]);
8090 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
8091 }
8092 }
8093}
8094
8095/*****************************************************************************/
8096
8098 const float *data,
8099 const int n) {
8100
8101 if (n <= 0)
8102 return 0;
8103
8104 float mean = 0, var = 0;
8105
8106 for (int i = 0; i < n; ++i) {
8107 mean += data[i];
8108 var += SQR(data[i]);
8109 }
8110
8111 var = var / (float) n - SQR(mean / (float) n);
8112
8113 return (var > 0 ? sqrtf(var) : 0);
8114}
8115
8116/*****************************************************************************/
8117
8119 const double sec,
8120 const double lon,
8121 const double lat) {
8122
8123 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
8124 const double D = sec / 86400 - 0.5;
8125
8126 /* Geocentric apparent ecliptic longitude [rad]... */
8127 const double g = (357.529 + 0.98560028 * D) * M_PI / 180;
8128 const double q = 280.459 + 0.98564736 * D;
8129 const double L = (q + 1.915 * sin(g) + 0.020 * sin(2 * g)) * M_PI / 180;
8130
8131 /* Mean obliquity of the ecliptic [rad]... */
8132 const double e = (23.439 - 0.00000036 * D) * M_PI / 180;
8133
8134 /* Declination [rad]... */
8135 const double sindec = sin(e) * sin(L);
8136
8137 /* Right ascension [rad]... */
8138 const double ra = atan2(cos(e) * sin(L), cos(L));
8139
8140 /* Greenwich Mean Sidereal Time [h]... */
8141 const double GMST = 18.697374558 + 24.06570982441908 * D;
8142
8143 /* Local Sidereal Time [h]... */
8144 const double LST = GMST + lon / 15;
8145
8146 /* Hour angle [rad]... */
8147 const double h = LST / 12 * M_PI - ra;
8148
8149 /* Convert latitude... */
8150 const double lat_help = lat * M_PI / 180;
8151
8152 /* Return solar zenith angle [rad]... */
8153 return acos(sin(lat_help) * sindec +
8154 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
8155}
8156
8157/*****************************************************************************/
8158
8160 const int year,
8161 const int mon,
8162 const int day,
8163 const int hour,
8164 const int min,
8165 const int sec,
8166 const double remain,
8167 double *jsec) {
8168
8169 struct tm t0, t1;
8170
8171 t0.tm_year = 100;
8172 t0.tm_mon = 0;
8173 t0.tm_mday = 1;
8174 t0.tm_hour = 0;
8175 t0.tm_min = 0;
8176 t0.tm_sec = 0;
8177
8178 t1.tm_year = year - 1900;
8179 t1.tm_mon = mon - 1;
8180 t1.tm_mday = day;
8181 t1.tm_hour = hour;
8182 t1.tm_min = min;
8183 t1.tm_sec = sec;
8184
8185 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
8186}
8187
8188/*****************************************************************************/
8189
8191 const char *name,
8192 const char *group,
8193 int output) {
8194
8195 static char names[NTIMER][100], groups[NTIMER][100];
8196
8197 static double rt_name[NTIMER], rt_group[NTIMER],
8198 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
8199
8200 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
8201
8202 /* Get time... */
8203 t1 = omp_get_wtime();
8204 dt = t1 - t0;
8205
8206 /* Add elapsed time to current timers... */
8207 if (iname >= 0) {
8208 rt_name[iname] += dt;
8209 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
8210 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
8211 ct_name[iname]++;
8212 }
8213 if (igroup >= 0)
8214 rt_group[igroup] += t1 - t0;
8215
8216 /* Report timers... */
8217 if (output) {
8218 for (int i = 0; i < nname; i++)
8219 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
8220 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
8221 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
8222 for (int i = 0; i < ngroup; i++)
8223 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
8224 double total = 0.0;
8225 for (int i = 0; i < nname; i++)
8226 total += rt_name[i];
8227 LOG(1, "TIMER_TOTAL = %.3f s", total);
8228 }
8229
8230 /* Identify IDs of next timer... */
8231 for (iname = 0; iname < nname; iname++)
8232 if (strcasecmp(name, names[iname]) == 0)
8233 break;
8234 for (igroup = 0; igroup < ngroup; igroup++)
8235 if (strcasecmp(group, groups[igroup]) == 0)
8236 break;
8237
8238 /* Check whether this is a new timer... */
8239 if (iname >= nname) {
8240 sprintf(names[iname], "%s", name);
8241 if ((++nname) >= NTIMER)
8242 ERRMSG("Too many timers!");
8243 }
8244
8245 /* Check whether this is a new group... */
8246 if (igroup >= ngroup) {
8247 sprintf(groups[igroup], "%s", group);
8248 if ((++ngroup) >= NTIMER)
8249 ERRMSG("Too many groups!");
8250 }
8251
8252 /* Save starting time... */
8253 t0 = t1;
8254}
8255
8256/*****************************************************************************/
8257
8259 const char *filename,
8260 int offset) {
8261
8262 char tstr[10];
8263
8264 double t;
8265
8266 /* Get time from filename... */
8267 int len = (int) strlen(filename);
8268 sprintf(tstr, "%.4s", &filename[len - offset]);
8269 int year = atoi(tstr);
8270 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
8271 int mon = atoi(tstr);
8272 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
8273 int day = atoi(tstr);
8274 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
8275 int hour = atoi(tstr);
8276 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
8277 int min = atoi(tstr);
8278
8279 /* Check time... */
8280 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
8281 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
8282 ERRMSG("Cannot read time from filename!");
8283
8284 /* Convert time to Julian seconds... */
8285 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
8286
8287 /* Return time... */
8288 return t;
8289}
8290
8291/*****************************************************************************/
8292
8294 const clim_t * clim,
8295 const double t,
8296 const double lat,
8297 const double p) {
8298
8299 /* Get tropopause pressure... */
8300 double pt = clim_tropo(clim, t, lat);
8301
8302 /* Get pressure range... */
8303 double p1 = pt * 0.866877899;
8304 double p0 = pt / 0.866877899;
8305
8306 /* Get weighting factor... */
8307 if (p > p0)
8308 return 1;
8309 else if (p < p1)
8310 return 0;
8311 else
8312 return LIN(p0, 1.0, p1, 0.0, p);
8313}
8314
8315/*****************************************************************************/
8316
8318 const char *filename,
8319 ctl_t * ctl,
8320 atm_t * atm,
8321 double t) {
8322
8323 /* Set timer... */
8324 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
8325
8326 /* Write info... */
8327 LOG(1, "Write atmospheric data: %s", filename);
8328
8329 /* Write ASCII data... */
8330 if (ctl->atm_type_out == 0)
8331 write_atm_asc(filename, ctl, atm, t);
8332
8333 /* Write binary data... */
8334 else if (ctl->atm_type_out == 1)
8335 write_atm_bin(filename, ctl, atm);
8336
8337 /* Write netCDF data... */
8338 else if (ctl->atm_type_out == 2)
8339 write_atm_nc(filename, ctl, atm);
8340
8341 /* Write CLaMS trajectory data... */
8342 else if (ctl->atm_type_out == 3)
8343 write_atm_clams_traj(filename, ctl, atm, t);
8344
8345 /* Write CLaMS pos data... */
8346 else if (ctl->atm_type_out == 4)
8347 write_atm_clams(filename, ctl, atm);
8348
8349 /* Error... */
8350 else
8351 ERRMSG("Atmospheric data type not supported!");
8352
8353 /* Write info... */
8354 double mini, maxi;
8355 LOG(2, "Number of particles: %d", atm->np);
8356 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
8357 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8358 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
8359 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
8360 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
8361 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
8362 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
8363 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
8364 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
8365 for (int iq = 0; iq < ctl->nq; iq++) {
8366 char msg[5 * LEN];
8367 sprintf(msg, "Quantity %s range: %s ... %s %s",
8368 ctl->qnt_name[iq], ctl->qnt_format[iq],
8369 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
8370 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
8371 LOG(2, msg, mini, maxi);
8372 }
8373}
8374
8375/*****************************************************************************/
8376
8378 const char *filename,
8379 ctl_t * ctl,
8380 atm_t * atm,
8381 double t) {
8382
8383 FILE *out;
8384
8385 /* Set time interval for output... */
8386 double t0 = t - 0.5 * ctl->dt_mod;
8387 double t1 = t + 0.5 * ctl->dt_mod;
8388
8389 /* Check if gnuplot output is requested... */
8390 if (ctl->atm_gpfile[0] != '-') {
8391
8392 /* Create gnuplot pipe... */
8393 if (!(out = popen("gnuplot", "w")))
8394 ERRMSG("Cannot create pipe to gnuplot!");
8395
8396 /* Set plot filename... */
8397 fprintf(out, "set out \"%s.png\"\n", filename);
8398
8399 /* Set time string... */
8400 double r;
8401 int year, mon, day, hour, min, sec;
8402 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
8403 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
8404 year, mon, day, hour, min);
8405
8406 /* Dump gnuplot file to pipe... */
8407 FILE *in;
8408 if (!(in = fopen(ctl->atm_gpfile, "r")))
8409 ERRMSG("Cannot open file!");
8410 char line[LEN];
8411 while (fgets(line, LEN, in))
8412 fprintf(out, "%s", line);
8413 fclose(in);
8414 }
8415
8416 else {
8417
8418 /* Create file... */
8419 if (!(out = fopen(filename, "w")))
8420 ERRMSG("Cannot create file!");
8421 }
8422
8423 /* Write header... */
8424 fprintf(out,
8425 "# $1 = time [s]\n"
8426 "# $2 = altitude [km]\n"
8427 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
8428 for (int iq = 0; iq < ctl->nq; iq++)
8429 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
8430 ctl->qnt_unit[iq]);
8431 fprintf(out, "\n");
8432
8433 /* Write data... */
8434 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
8435
8436 /* Check time... */
8437 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
8438 continue;
8439
8440 /* Write output... */
8441 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
8442 atm->lon[ip], atm->lat[ip]);
8443 for (int iq = 0; iq < ctl->nq; iq++) {
8444 fprintf(out, " ");
8445 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
8446 fprintf(out, ctl->qnt_format[iq], NAN);
8447 else
8448 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
8449 }
8450 fprintf(out, "\n");
8451 }
8452
8453 /* Close file... */
8454 fclose(out);
8455}
8456
8457/*****************************************************************************/
8458
8460 const char *filename,
8461 ctl_t * ctl,
8462 atm_t * atm) {
8463
8464 FILE *out;
8465
8466 /* Create file... */
8467 if (!(out = fopen(filename, "w")))
8468 ERRMSG("Cannot create file!");
8469
8470 /* Write version of binary data... */
8471 int version = 100;
8472 FWRITE(&version, int,
8473 1,
8474 out);
8475
8476 /* Write data... */
8477 FWRITE(&atm->np, int,
8478 1,
8479 out);
8480 FWRITE(atm->time, double,
8481 (size_t) atm->np,
8482 out);
8483 FWRITE(atm->p, double,
8484 (size_t) atm->np,
8485 out);
8486 FWRITE(atm->lon, double,
8487 (size_t) atm->np,
8488 out);
8489 FWRITE(atm->lat, double,
8490 (size_t) atm->np,
8491 out);
8492 for (int iq = 0; iq < ctl->nq; iq++)
8493 FWRITE(atm->q[iq], double,
8494 (size_t) atm->np,
8495 out);
8496
8497 /* Write final flag... */
8498 int final = 999;
8499 FWRITE(&final, int,
8500 1,
8501 out);
8502
8503 /* Close file... */
8504 fclose(out);
8505}
8506
8507/*****************************************************************************/
8508
8510 const char *filename,
8511 ctl_t * ctl,
8512 atm_t * atm) {
8513
8514 int tid, pid, ncid, varid;
8515 size_t start[2], count[2];
8516
8517 /* Create file... */
8518 nc_create(filename, NC_CLOBBER, &ncid);
8519
8520 /* Define dimensions... */
8521 NC(nc_def_dim(ncid, "time", 1, &tid));
8522 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
8523
8524 /* Define variables and their attributes... */
8525 int dim_ids[2] = { tid, pid };
8526 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
8527 "seconds since 2000-01-01 00:00:00 UTC");
8528 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg");
8529 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg");
8530 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa");
8531 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K");
8532 for (int iq = 0; iq < ctl->nq; iq++)
8533 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
8534 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
8535
8536 /* Define global attributes... */
8537 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
8538 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
8539
8540 /* End definitions... */
8541 NC(nc_enddef(ncid));
8542
8543 /* Write data... */
8544 NC_PUT_DOUBLE("time", atm->time, 0);
8545 NC_PUT_DOUBLE("LAT", atm->lat, 0);
8546 NC_PUT_DOUBLE("LON", atm->lon, 0);
8547 NC_PUT_DOUBLE("PRESS", atm->p, 0);
8548 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
8549 for (int iq = 0; iq < ctl->nq; iq++)
8550 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8551
8552 /* Close file... */
8553 NC(nc_close(ncid));
8554}
8555
8556/*****************************************************************************/
8557
8559 const char *dirname,
8560 ctl_t * ctl,
8561 atm_t * atm,
8562 double t) {
8563
8564 /* Global Counter... */
8565 static size_t out_cnt = 0;
8566
8567 double r, r_start, r_stop;
8568 int year, mon, day, hour, min, sec;
8569 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
8570 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
8571 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
8572
8573 int ncid, varid, tid, pid, cid;
8574 int dim_ids[2];
8575
8576 /* time, nparc */
8577 size_t start[2];
8578 size_t count[2];
8579
8580 /* Determine start and stop times of calculation... */
8581 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
8582 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
8583 &min_start, &sec_start, &r_start);
8584 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
8585 &min_stop, &sec_stop, &r_stop);
8586
8587 sprintf(filename_out, "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc",
8588 dirname,
8589 year_start % 100, mon_start, day_start, hour_start,
8590 year_stop % 100, mon_stop, day_stop, hour_stop);
8591 LOG(1, "Write traj file: %s", filename_out);
8592
8593 /* Define hyperslap for the traj_file... */
8594 start[0] = out_cnt;
8595 start[1] = 0;
8596 count[0] = 1;
8597 count[1] = (size_t) atm->np;
8598
8599 /* Create the file at the first timestep... */
8600 if (out_cnt == 0) {
8601
8602 /* Create file... */
8603 nc_create(filename_out, NC_CLOBBER, &ncid);
8604
8605 /* Define dimensions... */
8606 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
8607 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
8608 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
8609 dim_ids[0] = tid;
8610 dim_ids[1] = pid;
8611
8612 /* Define variables and their attributes... */
8613 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
8614 "seconds since 2000-01-01 00:00:00 UTC");
8615 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg");
8616 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg");
8617 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa");
8618 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K");
8619 for (int iq = 0; iq < ctl->nq; iq++)
8620 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
8621 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
8622
8623 /* Define global attributes... */
8624 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
8625 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
8626
8627 /* End definitions... */
8628 NC(nc_enddef(ncid));
8629 NC(nc_close(ncid));
8630 }
8631
8632 /* Increment global counter to change hyperslap... */
8633 out_cnt++;
8634
8635 /* Open file... */
8636 NC(nc_open(filename_out, NC_WRITE, &ncid));
8637
8638 /* Write data... */
8639 NC_PUT_DOUBLE("time", atm->time, 1);
8640 NC_PUT_DOUBLE("LAT", atm->lat, 1);
8641 NC_PUT_DOUBLE("LON", atm->lon, 1);
8642 NC_PUT_DOUBLE("PRESS", atm->p, 1);
8643 if (ctl->advect_vert_coord == 1) {
8644 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
8645 } else if (ctl->qnt_zeta >= 0) {
8646 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
8647 }
8648 for (int iq = 0; iq < ctl->nq; iq++)
8649 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
8650
8651 /* Close file... */
8652 NC(nc_close(ncid));
8653
8654 /* At the last time step create the init_fix_YYYYMMDDHH file... */
8655 if ((year == year_stop) && (mon == mon_stop)
8656 && (day == day_stop) && (hour == hour_stop)) {
8657
8658 /* Set filename... */
8659 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
8660 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
8661 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
8662 LOG(1, "Write init file: %s", filename_init);
8663
8664 /* Create file... */
8665 nc_create(filename_init, NC_CLOBBER, &ncid);
8666
8667 /* Define dimensions... */
8668 NC(nc_def_dim(ncid, "time", 1, &tid));
8669 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
8670 dim_ids[0] = tid;
8671 dim_ids[1] = pid;
8672
8673 /* Define variables and their attributes... */
8674 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
8675 "seconds since 2000-01-01 00:00:00 UTC");
8676 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg");
8677 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg");
8678 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa");
8679 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K");
8680 for (int iq = 0; iq < ctl->nq; iq++)
8681 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
8682 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
8683
8684 /* Define global attributes... */
8685 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
8686 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
8687
8688 /* End definitions... */
8689 NC(nc_enddef(ncid));
8690
8691 /* Write data... */
8692 NC_PUT_DOUBLE("time", atm->time, 0);
8693 NC_PUT_DOUBLE("LAT", atm->lat, 0);
8694 NC_PUT_DOUBLE("LON", atm->lon, 0);
8695 NC_PUT_DOUBLE("PRESS", atm->p, 0);
8696 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
8697 for (int iq = 0; iq < ctl->nq; iq++)
8698 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8699
8700 /* Close file... */
8701 NC(nc_close(ncid));
8702 }
8703}
8704
8705/*****************************************************************************/
8706
8708 const char *filename,
8709 ctl_t * ctl,
8710 atm_t * atm) {
8711
8712 int ncid, obsid, varid;
8713
8714 size_t start[2], count[2];
8715
8716 /* Create file... */
8717 NC(nc_create(filename, NC_CLOBBER, &ncid));
8718
8719 /* Define dimensions... */
8720 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
8721
8722 /* Define variables and their attributes... */
8723 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
8724 "seconds since 2000-01-01 00:00:00 UTC");
8725 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa");
8726 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east");
8727 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north");
8728 for (int iq = 0; iq < ctl->nq; iq++)
8729 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
8730 ctl->qnt_longname[iq], ctl->qnt_unit[iq]);
8731
8732 /* Define global attributes... */
8733 NC_PUT_ATT_GLOBAL("featureType", "point");
8734
8735 /* End definitions... */
8736 NC(nc_enddef(ncid));
8737
8738 /* Write data... */
8739 NC_PUT_DOUBLE("time", atm->time, 0);
8740 NC_PUT_DOUBLE("press", atm->p, 0);
8741 NC_PUT_DOUBLE("lon", atm->lon, 0);
8742 NC_PUT_DOUBLE("lat", atm->lat, 0);
8743 for (int iq = 0; iq < ctl->nq; iq++)
8744 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8745
8746 /* Close file... */
8747 NC(nc_close(ncid));
8748}
8749
8750/*****************************************************************************/
8751
8753 const char *filename,
8754 ctl_t * ctl,
8755 atm_t * atm,
8756 double t) {
8757
8758 static FILE *out;
8759
8760 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
8761 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
8762
8763 static int *obscount, ct, cx, cy, cz, ip, ix, iy, iz, n, nobs, nk;
8764
8765 /* Set timer... */
8766 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
8767
8768 /* Init... */
8769 if (t == ctl->t_start) {
8770
8771 /* Check quantity index for mass... */
8772 if (ctl->qnt_m < 0)
8773 ERRMSG("Need quantity mass!");
8774
8775 /* Allocate... */
8776 ALLOC(area, double,
8777 ctl->csi_ny);
8778 ALLOC(rt, double,
8779 NOBS);
8780 ALLOC(rz, double,
8781 NOBS);
8782 ALLOC(rlon, double,
8783 NOBS);
8784 ALLOC(rlat, double,
8785 NOBS);
8786 ALLOC(robs, double,
8787 NOBS);
8788
8789 /* Read observation data... */
8790 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
8791
8792 /* Read kernel data... */
8793 if (ctl->csi_kernel[0] != '-')
8794 read_kernel(ctl->csi_kernel, kz, kw, &nk);
8795
8796 /* Create new file... */
8797 LOG(1, "Write CSI data: %s", filename);
8798 if (!(out = fopen(filename, "w")))
8799 ERRMSG("Cannot create file!");
8800
8801 /* Write header... */
8802 fprintf(out,
8803 "# $1 = time [s]\n"
8804 "# $2 = number of hits (cx)\n"
8805 "# $3 = number of misses (cy)\n"
8806 "# $4 = number of false alarms (cz)\n"
8807 "# $5 = number of observations (cx + cy)\n"
8808 "# $6 = number of forecasts (cx + cz)\n"
8809 "# $7 = bias (ratio of forecasts and observations) [%%]\n"
8810 "# $8 = probability of detection (POD) [%%]\n"
8811 "# $9 = false alarm rate (FAR) [%%]\n"
8812 "# $10 = critical success index (CSI) [%%]\n");
8813 fprintf(out,
8814 "# $11 = hits associated with random chance\n"
8815 "# $12 = equitable threat score (ETS) [%%]\n"
8816 "# $13 = Pearson linear correlation coefficient\n"
8817 "# $14 = Spearman rank-order correlation coefficient\n"
8818 "# $15 = column density mean error (F - O) [kg/m^2]\n"
8819 "# $16 = column density root mean square error (RMSE) [kg/m^2]\n"
8820 "# $17 = column density mean absolute error [kg/m^2]\n"
8821 "# $18 = log-likelihood function\n"
8822 "# $19 = number of data points\n\n");
8823
8824 /* Set grid box size... */
8825 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
8826 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
8827 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
8828
8829 /* Set horizontal coordinates... */
8830 for (iy = 0; iy < ctl->csi_ny; iy++) {
8831 double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
8832 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(lat * M_PI / 180.);
8833 }
8834 }
8835
8836 /* Set time interval... */
8837 double t0 = t - 0.5 * ctl->dt_mod;
8838 double t1 = t + 0.5 * ctl->dt_mod;
8839
8840 /* Allocate... */
8841 ALLOC(modmean, double,
8842 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
8843 ALLOC(obsmean, double,
8844 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
8845 ALLOC(obscount, int,
8846 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
8847 ALLOC(obsstd, double,
8848 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
8849
8850 /* Loop over observations... */
8851 for (int i = 0; i < nobs; i++) {
8852
8853 /* Check time... */
8854 if (rt[i] < t0)
8855 continue;
8856 else if (rt[i] >= t1)
8857 break;
8858
8859 /* Check observation data... */
8860 if (!isfinite(robs[i]))
8861 continue;
8862
8863 /* Calculate indices... */
8864 ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
8865 iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
8866 iz = (int) ((rz[i] - ctl->csi_z0) / dz);
8867
8868 /* Check indices... */
8869 if (ix < 0 || ix >= ctl->csi_nx ||
8870 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
8871 continue;
8872
8873 /* Get mean observation index... */
8874 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
8875 obsmean[idx] += robs[i];
8876 obsstd[idx] += SQR(robs[i]);
8877 obscount[idx]++;
8878 }
8879
8880 /* Analyze model data... */
8881 for (ip = 0; ip < atm->np; ip++) {
8882
8883 /* Check time... */
8884 if (atm->time[ip] < t0 || atm->time[ip] > t1)
8885 continue;
8886
8887 /* Get indices... */
8888 ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
8889 iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
8890 iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
8891
8892 /* Check indices... */
8893 if (ix < 0 || ix >= ctl->csi_nx ||
8894 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
8895 continue;
8896
8897 /* Get total mass in grid cell... */
8898 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
8899 modmean[idx] += kernel_weight(kz, kw, nk, atm->p[ip])
8900 * atm->q[ctl->qnt_m][ip];
8901 }
8902
8903 /* Analyze all grid cells... */
8904 for (ix = 0; ix < ctl->csi_nx; ix++)
8905 for (iy = 0; iy < ctl->csi_ny; iy++)
8906 for (iz = 0; iz < ctl->csi_nz; iz++) {
8907
8908 /* Calculate mean observation index... */
8909 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
8910 if (obscount[idx] > 0) {
8911 obsmean[idx] /= obscount[idx];
8912 obsstd[idx] -= SQR(obsmean[idx]);
8913 obsstd[idx] = sqrt(obsstd[idx]);
8914 }
8915
8916 /* Calculate column density... */
8917 if (modmean[idx] > 0)
8918 modmean[idx] /= (1e6 * area[iy]);
8919
8920 /* Calculate CSI... */
8921 if (obscount[idx] > 0) {
8922 ct++;
8923 if (obsmean[idx] >= ctl->csi_obsmin &&
8924 modmean[idx] >= ctl->csi_modmin)
8925 cx++;
8926 else if (obsmean[idx] >= ctl->csi_obsmin &&
8927 modmean[idx] < ctl->csi_modmin)
8928 cy++;
8929 else if (obsmean[idx] < ctl->csi_obsmin &&
8930 modmean[idx] >= ctl->csi_modmin)
8931 cz++;
8932 }
8933
8934 /* Save data for other verification statistics... */
8935 if (obscount[idx] > 0
8936 && (obsmean[idx] >= ctl->csi_obsmin
8937 || modmean[idx] >= ctl->csi_modmin)) {
8938 x[n] = modmean[idx];
8939 y[n] = obsmean[idx];
8940 if (modmean[idx] >= ctl->csi_modmin)
8941 obsstdn[n] = obsstd[idx];
8942 if ((++n) >= NCSI)
8943 ERRMSG("Too many data points to calculate statistics!");
8944 }
8945 }
8946
8947 /* Write output... */
8948 if (fmod(t, ctl->csi_dt_out) == 0) {
8949
8950 /* Calculate verification statistics
8951 (https://www.cawcr.gov.au/projects/verification/) ... */
8952 static double work[2 * NCSI], work2[2 * NCSI];;
8953 int n_obs = cx + cy;
8954 int n_for = cx + cz;
8955 double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
8956 double pod = (n_obs > 0) ? (100. * cx) / n_obs : NAN;
8957 double far = (n_for > 0) ? (100. * cz) / n_for : NAN;
8958 double csi = (cx + cy + cz > 0) ? (100. * cx) / (cx + cy + cz) : NAN;
8959 double cx_rd = (ct > 0) ? (1. * n_obs * n_for) / ct : NAN;
8960 double ets = (cx + cy + cz - cx_rd > 0) ?
8961 (100. * (cx - cx_rd)) / (cx + cy + cz - cx_rd) : NAN;
8962 double rho_p =
8963 (n > 0) ? gsl_stats_correlation(x, 1, y, 1, (size_t) n) : NAN;
8964 double rho_s =
8965 (n > 0) ? gsl_stats_spearman(x, 1, y, 1, (size_t) n, work) : NAN;
8966 for (int i = 0; i < n; i++) {
8967 work[i] = x[i] - y[i];
8968 work2[i] = (obsstdn[i] != 0) ? (x[i] - y[i]) / obsstdn[i] : 0;
8969 }
8970 double mean = (n > 0) ? gsl_stats_mean(work, 1, (size_t) n) : NAN;
8971 double rmse = (n > 0) ? gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n,
8972 0.0) : NAN;
8973 double absdev =
8974 (n > 0) ? gsl_stats_absdev_m(work, 1, (size_t) n, 0.0) : NAN;
8975 double loglikelihood =
8976 (n > 0) ? gsl_stats_tss(work2, 1, (size_t) n) * (-0.5) : GSL_NAN;
8977
8978 /* Write... */
8979 fprintf(out,
8980 "%.2f %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n", t,
8981 cx, cy, cz, n_obs, n_for, bias, pod, far, csi, cx_rd, ets, rho_p,
8982 rho_s, mean, rmse, absdev, loglikelihood, n);
8983
8984 /* Set counters to zero... */
8985 n = ct = cx = cy = cz = 0;
8986 }
8987
8988 /* Free... */
8989 free(modmean);
8990 free(obsmean);
8991 free(obscount);
8992 free(obsstd);
8993
8994 /* Finalize... */
8995 if (t == ctl->t_stop) {
8996
8997 /* Close output file... */
8998 fclose(out);
8999
9000 /* Free... */
9001 free(area);
9002 free(rt);
9003 free(rz);
9004 free(rlon);
9005 free(rlat);
9006 free(robs);
9007 }
9008}
9009
9010/*****************************************************************************/
9011
9013 const char *filename,
9014 ctl_t * ctl,
9015 atm_t * atm,
9016 double t) {
9017
9018 static FILE *out;
9019
9020 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
9021 x[3], zm[NENS];
9022
9023 static int n[NENS];
9024
9025 /* Set timer... */
9026 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
9027
9028 /* Check quantities... */
9029 if (ctl->qnt_ens < 0)
9030 ERRMSG("Missing ensemble IDs!");
9031
9032 /* Set time interval... */
9033 double t0 = t - 0.5 * ctl->dt_mod;
9034 double t1 = t + 0.5 * ctl->dt_mod;
9035
9036 /* Init... */
9037 for (int i = 0; i < NENS; i++) {
9038 for (int iq = 0; iq < ctl->nq; iq++)
9039 qm[iq][i] = qs[iq][i] = 0;
9040 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
9041 n[i] = 0;
9042 }
9043
9044 /* Loop over air parcels... */
9045 for (int ip = 0; ip < atm->np; ip++) {
9046
9047 /* Check time... */
9048 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9049 continue;
9050
9051 /* Check ensemble ID... */
9052 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
9053 ERRMSG("Ensemble ID is out of range!");
9054
9055 /* Get means... */
9056 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
9057 for (int iq = 0; iq < ctl->nq; iq++) {
9058 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
9059 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
9060 }
9061 xm[ctl->qnt_ens][0] += x[0];
9062 xm[ctl->qnt_ens][1] += x[1];
9063 xm[ctl->qnt_ens][2] += x[2];
9064 zm[ctl->qnt_ens] += Z(atm->p[ip]);
9065 n[ctl->qnt_ens]++;
9066 }
9067
9068 /* Create file... */
9069 LOG(1, "Write ensemble data: %s", filename);
9070 if (!(out = fopen(filename, "w")))
9071 ERRMSG("Cannot create file!");
9072
9073 /* Write header... */
9074 fprintf(out,
9075 "# $1 = time [s]\n"
9076 "# $2 = altitude [km]\n"
9077 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
9078 for (int iq = 0; iq < ctl->nq; iq++)
9079 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
9080 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9081 for (int iq = 0; iq < ctl->nq; iq++)
9082 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
9083 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9084 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
9085
9086 /* Write data... */
9087 for (int i = 0; i < NENS; i++)
9088 if (n[i] > 0) {
9089 cart2geo(xm[i], &dummy, &lon, &lat);
9090 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
9091 for (int iq = 0; iq < ctl->nq; iq++) {
9092 fprintf(out, " ");
9093 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
9094 }
9095 for (int iq = 0; iq < ctl->nq; iq++) {
9096 fprintf(out, " ");
9097 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
9098 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
9099 }
9100 fprintf(out, " %d\n", n[i]);
9101 }
9102
9103 /* Close file... */
9104 fclose(out);
9105}
9106
9107/*****************************************************************************/
9108
9110 const char *filename,
9111 ctl_t * ctl,
9112 met_t * met0,
9113 met_t * met1,
9114 atm_t * atm,
9115 double t) {
9116
9117 static double kz[EP], kw[EP];
9118
9119 static int nk;
9120
9121 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
9122
9123 int *ixs, *iys, *izs, *np;
9124
9125 /* Set timer... */
9126 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
9127
9128 /* Write info... */
9129 LOG(1, "Write grid data: %s", filename);
9130
9131 /* Init... */
9132 if (t == ctl->t_start) {
9133
9134 /* Read kernel data... */
9135 if (ctl->grid_kernel[0] != '-')
9136 read_kernel(ctl->grid_kernel, kz, kw, &nk);
9137 }
9138
9139 /* Allocate... */
9140 ALLOC(cd, double,
9141 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9142 for (int iq = 0; iq < ctl->nq; iq++) {
9143 ALLOC(mean[iq], double,
9144 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9145 ALLOC(sigma[iq], double,
9146 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9147 }
9148 ALLOC(vmr_impl, double,
9149 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9150 ALLOC(z, double,
9151 ctl->grid_nz);
9152 ALLOC(lon, double,
9153 ctl->grid_nx);
9154 ALLOC(lat, double,
9155 ctl->grid_ny);
9156 ALLOC(area, double,
9157 ctl->grid_ny);
9158 ALLOC(press, double,
9159 ctl->grid_nz);
9160 ALLOC(np, int,
9161 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9162 ALLOC(ixs, int,
9163 atm->np);
9164 ALLOC(iys, int,
9165 atm->np);
9166 ALLOC(izs, int,
9167 atm->np);
9168
9169 /* Set grid box size... */
9170 double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
9171 double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
9172 double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
9173
9174 /* Set vertical coordinates... */
9175#pragma omp parallel for default(shared)
9176 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9177 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
9178 press[iz] = P(z[iz]);
9179 }
9180
9181 /* Set horizontal coordinates... */
9182 for (int ix = 0; ix < ctl->grid_nx; ix++)
9183 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
9184#pragma omp parallel for default(shared)
9185 for (int iy = 0; iy < ctl->grid_ny; iy++) {
9186 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
9187 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.)
9188 * cos(lat[iy] * M_PI / 180.);
9189 }
9190
9191 /* Set time interval for output... */
9192 double t0 = t - 0.5 * ctl->dt_mod;
9193 double t1 = t + 0.5 * ctl->dt_mod;
9194
9195 /* Get grid box indices... */
9196#pragma omp parallel for default(shared)
9197 for (int ip = 0; ip < atm->np; ip++) {
9198 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
9199 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
9200 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
9201 if (atm->time[ip] < t0 || atm->time[ip] > t1
9202 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
9203 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
9204 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
9205 izs[ip] = -1;
9206 }
9207
9208 /* Average data... */
9209 for (int ip = 0; ip < atm->np; ip++)
9210 if (izs[ip] >= 0) {
9211 int idx =
9212 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
9213 double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
9214 np[idx]++;
9215 for (int iq = 0; iq < ctl->nq; iq++) {
9216 mean[iq][idx] += kernel * atm->q[iq][ip];
9217 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
9218 }
9219 }
9220
9221 /* Calculate column density and volume mixing ratio... */
9222#pragma omp parallel for default(shared)
9223 for (int ix = 0; ix < ctl->grid_nx; ix++)
9224 for (int iy = 0; iy < ctl->grid_ny; iy++)
9225 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9226
9227 /* Get grid index... */
9228 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
9229
9230 /* Calculate column density... */
9231 cd[idx] = NAN;
9232 if (ctl->qnt_m >= 0)
9233 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
9234
9235 /* Calculate volume mixing ratio (implicit)... */
9236 vmr_impl[idx] = NAN;
9237 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
9238 && met1 != NULL) {
9239 vmr_impl[idx] = 0;
9240 if (mean[ctl->qnt_m][idx] > 0) {
9241
9242 /* Get temperature... */
9243 double temp;
9245 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
9246 lon[ix], lat[iy], &temp, ci, cw, 1);
9247
9248 /* Calculate volume mixing ratio... */
9249 vmr_impl[idx] = MA / ctl->molmass * mean[ctl->qnt_m][idx]
9250 / (RHO(press[iz], temp) * 1e6 * area[iy] * 1e3 * dz);
9251 }
9252 }
9253
9254 /* Calculate mean... */
9255 if (np[idx] > 0)
9256 for (int iq = 0; iq < ctl->nq; iq++) {
9257 mean[iq][idx] /= np[idx];
9258 double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
9259 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
9260 } else
9261 for (int iq = 0; iq < ctl->nq; iq++) {
9262 mean[iq][idx] = NAN;
9263 sigma[iq][idx] = NAN;
9264 }
9265 }
9266
9267 /* Write ASCII data... */
9268 if (ctl->grid_type == 0)
9269 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
9270 t, z, lon, lat, area, dz, np);
9271
9272 /* Write netCDF data... */
9273 else if (ctl->grid_type == 1)
9274 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
9275 t, z, lon, lat, area, dz, np);
9276
9277 /* Error message... */
9278 else
9279 ERRMSG("Grid data format GRID_TYPE unknown!");
9280
9281 /* Free... */
9282 free(cd);
9283 for (int iq = 0; iq < ctl->nq; iq++) {
9284 free(mean[iq]);
9285 free(sigma[iq]);
9286 }
9287 free(vmr_impl);
9288 free(z);
9289 free(lon);
9290 free(lat);
9291 free(area);
9292 free(press);
9293 free(np);
9294 free(ixs);
9295 free(iys);
9296 free(izs);
9297}
9298
9299/*****************************************************************************/
9300
9302 const char *filename,
9303 ctl_t * ctl,
9304 double *cd,
9305 double *mean[NQ],
9306 double *sigma[NQ],
9307 double *vmr_impl,
9308 double t,
9309 double *z,
9310 double *lon,
9311 double *lat,
9312 double *area,
9313 double dz,
9314 int *np) {
9315
9316 FILE *out;
9317
9318 /* Check if gnuplot output is requested... */
9319 if (ctl->grid_gpfile[0] != '-') {
9320
9321 /* Create gnuplot pipe... */
9322 if (!(out = popen("gnuplot", "w")))
9323 ERRMSG("Cannot create pipe to gnuplot!");
9324
9325 /* Set plot filename... */
9326 fprintf(out, "set out \"%s.png\"\n", filename);
9327
9328 /* Set time string... */
9329 double r;
9330 int year, mon, day, hour, min, sec;
9331 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9332 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
9333 year, mon, day, hour, min);
9334
9335 /* Dump gnuplot file to pipe... */
9336 FILE *in;
9337 char line[LEN];
9338 if (!(in = fopen(ctl->grid_gpfile, "r")))
9339 ERRMSG("Cannot open file!");
9340 while (fgets(line, LEN, in))
9341 fprintf(out, "%s", line);
9342 fclose(in);
9343 }
9344
9345 else {
9346
9347 /* Create file... */
9348 if (!(out = fopen(filename, "w")))
9349 ERRMSG("Cannot create file!");
9350 }
9351
9352 /* Write header... */
9353 fprintf(out,
9354 "# $1 = time [s]\n"
9355 "# $2 = altitude [km]\n"
9356 "# $3 = longitude [deg]\n"
9357 "# $4 = latitude [deg]\n"
9358 "# $5 = surface area [km^2]\n"
9359 "# $6 = layer depth [km]\n"
9360 "# $7 = column density (implicit) [kg/m^2]\n"
9361 "# $8 = volume mixing ratio (implicit) [ppv]\n"
9362 "# $9 = number of particles [1]\n");
9363 for (int iq = 0; iq < ctl->nq; iq++)
9364 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
9365 ctl->qnt_unit[iq]);
9366 if (ctl->grid_stddev)
9367 for (int iq = 0; iq < ctl->nq; iq++)
9368 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
9369 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9370 fprintf(out, "\n");
9371
9372 /* Write data... */
9373 for (int ix = 0; ix < ctl->grid_nx; ix++) {
9374 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
9375 fprintf(out, "\n");
9376 for (int iy = 0; iy < ctl->grid_ny; iy++) {
9377 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
9378 fprintf(out, "\n");
9379 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9380 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
9381 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
9382 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
9383 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
9384 for (int iq = 0; iq < ctl->nq; iq++) {
9385 fprintf(out, " ");
9386 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
9387 }
9388 if (ctl->grid_stddev)
9389 for (int iq = 0; iq < ctl->nq; iq++) {
9390 fprintf(out, " ");
9391 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
9392 }
9393 fprintf(out, "\n");
9394 }
9395 }
9396 }
9397 }
9398
9399 /* Close file... */
9400 fclose(out);
9401}
9402
9403/*****************************************************************************/
9404
9406 const char *filename,
9407 ctl_t * ctl,
9408 double *cd,
9409 double *mean[NQ],
9410 double *sigma[NQ],
9411 double *vmr_impl,
9412 double t,
9413 double *z,
9414 double *lon,
9415 double *lat,
9416 double *area,
9417 double dz,
9418 int *np) {
9419
9420 char longname[2 * LEN], varname[2 * LEN];
9421
9422 double *help;
9423
9424 int *help2, ncid, dimid[10], varid;
9425
9426 size_t start[2], count[2];
9427
9428 /* Allocate... */
9429 ALLOC(help, double,
9430 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9431 ALLOC(help2, int,
9432 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9433
9434 /* Create file... */
9435 NC(nc_create(filename, NC_CLOBBER, &ncid));
9436
9437 /* Define dimensions... */
9438 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
9439 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
9440 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
9441 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
9442 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
9443
9444 /* Define variables and their attributes... */
9445 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
9446 "seconds since 2000-01-01 00:00:00 UTC");
9447 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km");
9448 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north");
9449 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east");
9450 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km");
9451 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2");
9452 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2");
9453 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
9454 "volume mixing ratio (implicit)", "ppv");
9455 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1");
9456 for (int iq = 0; iq < ctl->nq; iq++) {
9457 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
9458 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
9459 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq]);
9460 if (ctl->grid_stddev) {
9461 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
9462 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
9463 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq]);
9464 }
9465 }
9466 /* End definitions... */
9467 NC(nc_enddef(ncid));
9468
9469 /* Write data... */
9470 NC_PUT_DOUBLE("time", &t, 0);
9471 NC_PUT_DOUBLE("lon", lon, 0);
9472 NC_PUT_DOUBLE("lat", lat, 0);
9473 NC_PUT_DOUBLE("z", z, 0);
9474 NC_PUT_DOUBLE("area", area, 0);
9475 NC_PUT_DOUBLE("dz", &dz, 0);
9476
9477 for (int ix = 0; ix < ctl->grid_nx; ix++)
9478 for (int iy = 0; iy < ctl->grid_ny; iy++)
9479 for (int iz = 0; iz < ctl->grid_nz; iz++)
9480 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9481 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9482 NC_PUT_DOUBLE("cd", help, 0);
9483
9484 for (int ix = 0; ix < ctl->grid_nx; ix++)
9485 for (int iy = 0; iy < ctl->grid_ny; iy++)
9486 for (int iz = 0; iz < ctl->grid_nz; iz++)
9487 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9488 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9489 NC_PUT_DOUBLE("vmr_impl", help, 0);
9490
9491 for (int ix = 0; ix < ctl->grid_nx; ix++)
9492 for (int iy = 0; iy < ctl->grid_ny; iy++)
9493 for (int iz = 0; iz < ctl->grid_nz; iz++)
9494 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9495 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9496 NC_PUT_INT("np", help2, 0);
9497
9498 for (int iq = 0; iq < ctl->nq; iq++) {
9499 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
9500 for (int ix = 0; ix < ctl->grid_nx; ix++)
9501 for (int iy = 0; iy < ctl->grid_ny; iy++)
9502 for (int iz = 0; iz < ctl->grid_nz; iz++)
9503 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9504 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9505 NC_PUT_DOUBLE(varname, help, 0);
9506 }
9507
9508 if (ctl->grid_stddev)
9509 for (int iq = 0; iq < ctl->nq; iq++) {
9510 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
9511 for (int ix = 0; ix < ctl->grid_nx; ix++)
9512 for (int iy = 0; iy < ctl->grid_ny; iy++)
9513 for (int iz = 0; iz < ctl->grid_nz; iz++)
9514 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
9515 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
9516 NC_PUT_DOUBLE(varname, help, 0);
9517 }
9518
9519 /* Close file... */
9520 NC(nc_close(ncid));
9521
9522 /* Free... */
9523 free(help);
9524 free(help2);
9525}
9526
9527/*****************************************************************************/
9528
9530 const char *filename,
9531 ctl_t * ctl,
9532 met_t * met) {
9533
9534 /* Set timer... */
9535 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
9536
9537 /* Write info... */
9538 LOG(1, "Write meteo data: %s", filename);
9539
9540 /* Check compression flags... */
9541#ifndef ZFP
9542 if (ctl->met_type == 3)
9543 ERRMSG("MPTRAC was compiled without zfp compression!");
9544#endif
9545#ifndef ZSTD
9546 if (ctl->met_type == 4)
9547 ERRMSG("MPTRAC was compiled without zstd compression!");
9548#endif
9549#ifndef CMS
9550 if (ctl->met_type == 5)
9551 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
9552#endif
9553
9554 /* Write binary data... */
9555 if (ctl->met_type >= 1 && ctl->met_type <= 5) {
9556
9557 /* Create file... */
9558 FILE *out;
9559 if (!(out = fopen(filename, "w")))
9560 ERRMSG("Cannot create file!");
9561
9562 /* Write type of binary data... */
9563 FWRITE(&ctl->met_type, int,
9564 1,
9565 out);
9566
9567 /* Write version of binary data... */
9568 int version = 102;
9569 FWRITE(&version, int,
9570 1,
9571 out);
9572
9573 /* Write grid data... */
9574 FWRITE(&met->time, double,
9575 1,
9576 out);
9577 FWRITE(&met->nx, int,
9578 1,
9579 out);
9580 FWRITE(&met->ny, int,
9581 1,
9582 out);
9583 FWRITE(&met->np, int,
9584 1,
9585 out);
9586 FWRITE(met->lon, double,
9587 (size_t) met->nx,
9588 out);
9589 FWRITE(met->lat, double,
9590 (size_t) met->ny,
9591 out);
9592 FWRITE(met->p, double,
9593 (size_t) met->np,
9594 out);
9595
9596 /* Write surface data... */
9597 write_met_bin_2d(out, met, met->ps, "PS");
9598 write_met_bin_2d(out, met, met->ts, "TS");
9599 write_met_bin_2d(out, met, met->zs, "ZS");
9600 write_met_bin_2d(out, met, met->us, "US");
9601 write_met_bin_2d(out, met, met->vs, "VS");
9602 write_met_bin_2d(out, met, met->lsm, "LSM");
9603 write_met_bin_2d(out, met, met->sst, "SST");
9604 write_met_bin_2d(out, met, met->pbl, "PBL");
9605 write_met_bin_2d(out, met, met->pt, "PT");
9606 write_met_bin_2d(out, met, met->tt, "TT");
9607 write_met_bin_2d(out, met, met->zt, "ZT");
9608 write_met_bin_2d(out, met, met->h2ot, "H2OT");
9609 write_met_bin_2d(out, met, met->pct, "PCT");
9610 write_met_bin_2d(out, met, met->pcb, "PCB");
9611 write_met_bin_2d(out, met, met->cl, "CL");
9612 write_met_bin_2d(out, met, met->plcl, "PLCL");
9613 write_met_bin_2d(out, met, met->plfc, "PLFC");
9614 write_met_bin_2d(out, met, met->pel, "PEL");
9615 write_met_bin_2d(out, met, met->cape, "CAPE");
9616 write_met_bin_2d(out, met, met->cin, "CIN");
9617
9618 /* Write level data... */
9619 write_met_bin_3d(out, ctl, met, met->z, "Z",
9620 (ctl->met_zfp_tol_z <= 0 ? ctl->met_zfp_prec : 0),
9621 ctl->met_zfp_tol_z);
9622 write_met_bin_3d(out, ctl, met, met->t, "T",
9623 (ctl->met_zfp_tol_t <= 0 ? ctl->met_zfp_prec : 0),
9624 ctl->met_zfp_tol_t);
9625 write_met_bin_3d(out, ctl, met, met->u, "U", ctl->met_zfp_prec, 0);
9626 write_met_bin_3d(out, ctl, met, met->v, "V", ctl->met_zfp_prec, 0);
9627 write_met_bin_3d(out, ctl, met, met->w, "W", ctl->met_zfp_prec, 0);
9628 write_met_bin_3d(out, ctl, met, met->pv, "PV", ctl->met_zfp_prec, 0);
9629 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", ctl->met_zfp_prec, 0);
9630 write_met_bin_3d(out, ctl, met, met->o3, "O3", ctl->met_zfp_prec, 0);
9631 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", ctl->met_zfp_prec, 0);
9632 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", ctl->met_zfp_prec, 0);
9633 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", ctl->met_zfp_prec, 0);
9634 write_met_bin_3d(out, ctl, met, met->swc, "SWC", ctl->met_zfp_prec, 0);
9635 write_met_bin_3d(out, ctl, met, met->cc, "CC", ctl->met_zfp_prec, 0);
9636
9637 /* Write final flag... */
9638 int final = 999;
9639 FWRITE(&final, int,
9640 1,
9641 out);
9642
9643 /* Close file... */
9644 fclose(out);
9645 }
9646
9647 return 0;
9648}
9649
9650/*****************************************************************************/
9651
9653 FILE * out,
9654 met_t * met,
9655 float var[EX][EY],
9656 char *varname) {
9657
9658 float *help;
9659
9660 /* Allocate... */
9661 ALLOC(help, float,
9662 EX * EY);
9663
9664 /* Copy data... */
9665 for (int ix = 0; ix < met->nx; ix++)
9666 for (int iy = 0; iy < met->ny; iy++)
9667 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
9668
9669 /* Write uncompressed data... */
9670 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
9671 FWRITE(help, float,
9672 (size_t) (met->nx * met->ny),
9673 out);
9674
9675 /* Free... */
9676 free(help);
9677}
9678
9679/*****************************************************************************/
9680
9682 FILE * out,
9683 ctl_t * ctl,
9684 met_t * met,
9685 float var[EX][EY][EP],
9686 char *varname,
9687 int precision,
9688 double tolerance) {
9689
9690 float *help;
9691
9692 /* Allocate... */
9693 ALLOC(help, float,
9694 EX * EY * EP);
9695
9696 /* Copy data... */
9697#pragma omp parallel for default(shared) collapse(2)
9698 for (int ix = 0; ix < met->nx; ix++)
9699 for (int iy = 0; iy < met->ny; iy++)
9700 for (int ip = 0; ip < met->np; ip++)
9701 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
9702
9703 /* Write uncompressed data... */
9704 if (ctl->met_type == 1) {
9705 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
9706 FWRITE(help, float,
9707 (size_t) (met->nx * met->ny * met->np),
9708 out);
9709 }
9710
9711 /* Write packed data... */
9712 else if (ctl->met_type == 2)
9713 compress_pck(varname, help, (size_t) (met->ny * met->nx),
9714 (size_t) met->np, 0, out);
9715
9716 /* Write zfp data... */
9717#ifdef ZFP
9718 else if (ctl->met_type == 3) {
9719 FWRITE(&precision, int,
9720 1,
9721 out);
9722 FWRITE(&tolerance, double,
9723 1,
9724 out);
9725 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
9726 tolerance, 0, out);
9727 }
9728#endif
9729
9730 /* Write zstd data... */
9731#ifdef ZSTD
9732 else if (ctl->met_type == 4)
9733 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
9734 out);
9735#endif
9736
9737 /* Write cmultiscale data... */
9738#ifdef CMS
9739 else if (ctl->met_type == 5) {
9740 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
9741 (size_t) met->np, 0, out);
9742 }
9743#endif
9744
9745 /* Unknown method... */
9746 else {
9747 ERRMSG("MET_TYPE not supported!");
9748 LOG(3, "%d %g", precision, tolerance);
9749 }
9750
9751 /* Free... */
9752 free(help);
9753}
9754
9755/*****************************************************************************/
9756
9758 const char *dirname,
9759 ctl_t * ctl,
9760 met_t * met0,
9761 met_t * met1,
9762 atm_t * atm,
9763 double t) {
9764
9765 char ext[10], filename[2 * LEN];
9766
9767 double r;
9768
9769 int year, mon, day, hour, min, sec;
9770
9771 /* Get time... */
9772 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9773
9774 /* Update host... */
9775#ifdef _OPENACC
9776 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
9777 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
9778 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
9779 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
9780 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
9781 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0)) {
9782 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_D2H);
9783#pragma acc update host(atm[:1])
9784 }
9785#endif
9786
9787 /* Write atmospheric data... */
9788 if (ctl->atm_basename[0] != '-' &&
9789 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
9790 if (ctl->atm_type_out == 0)
9791 sprintf(ext, "tab");
9792 else if (ctl->atm_type_out == 1)
9793 sprintf(ext, "bin");
9794 else if (ctl->atm_type_out == 2)
9795 sprintf(ext, "nc");
9796 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
9797 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
9798 write_atm(filename, ctl, atm, t);
9799 }
9800
9801 /* Write gridded data... */
9802 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
9803 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
9804 dirname, ctl->grid_basename, year, mon, day, hour, min,
9805 ctl->grid_type == 0 ? "tab" : "nc");
9806 write_grid(filename, ctl, met0, met1, atm, t);
9807 }
9808
9809 /* Write CSI data... */
9810 if (ctl->csi_basename[0] != '-') {
9811 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
9812 write_csi(filename, ctl, atm, t);
9813 }
9814
9815 /* Write ensemble data... */
9816 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
9817 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
9818 dirname, ctl->ens_basename, year, mon, day, hour, min);
9819 write_ens(filename, ctl, atm, t);
9820 }
9821
9822 /* Write profile data... */
9823 if (ctl->prof_basename[0] != '-') {
9824 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
9825 write_prof(filename, ctl, met0, met1, atm, t);
9826 }
9827
9828 /* Write sample data... */
9829 if (ctl->sample_basename[0] != '-') {
9830 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
9831 write_sample(filename, ctl, met0, met1, atm, t);
9832 }
9833
9834 /* Write station data... */
9835 if (ctl->stat_basename[0] != '-') {
9836 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
9837 write_station(filename, ctl, atm, t);
9838 }
9839
9840 /* Write VTK data... */
9841 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
9842 static int nvtk;
9843 if (t == ctl->t_start)
9844 nvtk = 0;
9845 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
9846 write_vtk(filename, ctl, atm, t);
9847 }
9848}
9849
9850/*****************************************************************************/
9851
9853 const char *filename,
9854 ctl_t * ctl,
9855 met_t * met0,
9856 met_t * met1,
9857 atm_t * atm,
9858 double t) {
9859
9860 static FILE *out;
9861
9862 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
9863 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
9864
9865 static int nobs, *obscount, ip, okay;
9866
9867 /* Set timer... */
9868 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
9869
9870 /* Init... */
9871 if (t == ctl->t_start) {
9872
9873 /* Check quantity index for mass... */
9874 if (ctl->qnt_m < 0)
9875 ERRMSG("Need quantity mass!");
9876
9877 /* Check molar mass... */
9878 if (ctl->molmass <= 0)
9879 ERRMSG("Specify molar mass!");
9880
9881 /* Allocate... */
9882 ALLOC(lon, double,
9883 ctl->prof_nx);
9884 ALLOC(lat, double,
9885 ctl->prof_ny);
9886 ALLOC(area, double,
9887 ctl->prof_ny);
9888 ALLOC(z, double,
9889 ctl->prof_nz);
9890 ALLOC(press, double,
9891 ctl->prof_nz);
9892 ALLOC(rt, double,
9893 NOBS);
9894 ALLOC(rz, double,
9895 NOBS);
9896 ALLOC(rlon, double,
9897 NOBS);
9898 ALLOC(rlat, double,
9899 NOBS);
9900 ALLOC(robs, double,
9901 NOBS);
9902
9903 /* Read observation data... */
9904 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
9905
9906 /* Create new output file... */
9907 LOG(1, "Write profile data: %s", filename);
9908 if (!(out = fopen(filename, "w")))
9909 ERRMSG("Cannot create file!");
9910
9911 /* Write header... */
9912 fprintf(out,
9913 "# $1 = time [s]\n"
9914 "# $2 = altitude [km]\n"
9915 "# $3 = longitude [deg]\n"
9916 "# $4 = latitude [deg]\n"
9917 "# $5 = pressure [hPa]\n"
9918 "# $6 = temperature [K]\n"
9919 "# $7 = volume mixing ratio [ppv]\n"
9920 "# $8 = H2O volume mixing ratio [ppv]\n"
9921 "# $9 = O3 volume mixing ratio [ppv]\n"
9922 "# $10 = observed BT index [K]\n"
9923 "# $11 = number of observations\n");
9924
9925 /* Set grid box size... */
9926 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
9927 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
9928 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
9929
9930 /* Set vertical coordinates... */
9931 for (int iz = 0; iz < ctl->prof_nz; iz++) {
9932 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
9933 press[iz] = P(z[iz]);
9934 }
9935
9936 /* Set horizontal coordinates... */
9937 for (int ix = 0; ix < ctl->prof_nx; ix++)
9938 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
9939 for (int iy = 0; iy < ctl->prof_ny; iy++) {
9940 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
9941 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.)
9942 * cos(lat[iy] * M_PI / 180.);
9943 }
9944 }
9945
9946 /* Set time interval... */
9947 double t0 = t - 0.5 * ctl->dt_mod;
9948 double t1 = t + 0.5 * ctl->dt_mod;
9949
9950 /* Allocate... */
9951 ALLOC(mass, double,
9952 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
9953 ALLOC(obsmean, double,
9954 ctl->prof_nx * ctl->prof_ny);
9955 ALLOC(obscount, int,
9956 ctl->prof_nx * ctl->prof_ny);
9957
9958 /* Loop over observations... */
9959 for (int i = 0; i < nobs; i++) {
9960
9961 /* Check time... */
9962 if (rt[i] < t0)
9963 continue;
9964 else if (rt[i] >= t1)
9965 break;
9966
9967 /* Check observation data... */
9968 if (!isfinite(robs[i]))
9969 continue;
9970
9971 /* Calculate indices... */
9972 int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
9973 int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
9974
9975 /* Check indices... */
9976 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
9977 continue;
9978
9979 /* Get mean observation index... */
9980 int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
9981 obsmean[idx] += robs[i];
9982 obscount[idx]++;
9983 }
9984
9985 /* Analyze model data... */
9986 for (ip = 0; ip < atm->np; ip++) {
9987
9988 /* Check time... */
9989 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9990 continue;
9991
9992 /* Get indices... */
9993 int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
9994 int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
9995 int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
9996
9997 /* Check indices... */
9998 if (ix < 0 || ix >= ctl->prof_nx ||
9999 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
10000 continue;
10001
10002 /* Get total mass in grid cell... */
10003 int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10004 mass[idx] += atm->q[ctl->qnt_m][ip];
10005 }
10006
10007 /* Extract profiles... */
10008 for (int ix = 0; ix < ctl->prof_nx; ix++)
10009 for (int iy = 0; iy < ctl->prof_ny; iy++) {
10010 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
10011 if (obscount[idx2] > 0) {
10012
10013 /* Check profile... */
10014 okay = 0;
10015 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10016 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10017 if (mass[idx3] > 0) {
10018 okay = 1;
10019 break;
10020 }
10021 }
10022 if (!okay)
10023 continue;
10024
10025 /* Write output... */
10026 fprintf(out, "\n");
10027
10028 /* Loop over altitudes... */
10029 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10030
10031 /* Get temperature, water vapor, and ozone... */
10033 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
10034 lon[ix], lat[iy], &temp, ci, cw, 1);
10035 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
10036 lon[ix], lat[iy], &h2o, ci, cw, 0);
10037 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
10038 lon[ix], lat[iy], &o3, ci, cw, 0);
10039
10040 /* Calculate volume mixing ratio... */
10041 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10042 vmr = MA / ctl->molmass * mass[idx3]
10043 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
10044
10045 /* Write output... */
10046 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
10047 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
10048 obsmean[idx2] / obscount[idx2], obscount[idx2]);
10049 }
10050 }
10051 }
10052
10053 /* Free... */
10054 free(mass);
10055 free(obsmean);
10056 free(obscount);
10057
10058 /* Finalize... */
10059 if (t == ctl->t_stop) {
10060
10061 /* Close output file... */
10062 fclose(out);
10063
10064 /* Free... */
10065 free(lon);
10066 free(lat);
10067 free(area);
10068 free(z);
10069 free(press);
10070 free(rt);
10071 free(rz);
10072 free(rlon);
10073 free(rlat);
10074 free(robs);
10075 }
10076}
10077
10078/*****************************************************************************/
10079
10081 const char *filename,
10082 ctl_t * ctl,
10083 met_t * met0,
10084 met_t * met1,
10085 atm_t * atm,
10086 double t) {
10087
10088 static FILE *out;
10089
10090 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
10091 kw[EP];
10092
10093 static int nobs, nk;
10094
10095 /* Set timer... */
10096 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
10097
10098 /* Init... */
10099 if (t == ctl->t_start) {
10100
10101 /* Allocate... */
10102 ALLOC(rt, double,
10103 NOBS);
10104 ALLOC(rz, double,
10105 NOBS);
10106 ALLOC(rlon, double,
10107 NOBS);
10108 ALLOC(rlat, double,
10109 NOBS);
10110 ALLOC(robs, double,
10111 NOBS);
10112
10113 /* Read observation data... */
10114 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
10115
10116 /* Read kernel data... */
10117 if (ctl->sample_kernel[0] != '-')
10118 read_kernel(ctl->sample_kernel, kz, kw, &nk);
10119
10120 /* Create output file... */
10121 LOG(1, "Write sample data: %s", filename);
10122 if (!(out = fopen(filename, "w")))
10123 ERRMSG("Cannot create file!");
10124
10125 /* Write header... */
10126 fprintf(out,
10127 "# $1 = time [s]\n"
10128 "# $2 = altitude [km]\n"
10129 "# $3 = longitude [deg]\n"
10130 "# $4 = latitude [deg]\n"
10131 "# $5 = surface area [km^2]\n"
10132 "# $6 = layer depth [km]\n"
10133 "# $7 = number of particles [1]\n"
10134 "# $8 = column density [kg/m^2]\n"
10135 "# $9 = volume mixing ratio [ppv]\n"
10136 "# $10 = observed BT index [K]\n\n");
10137
10138 /* Set latitude range, squared radius, and area... */
10139 dlat = DY2DEG(ctl->sample_dx);
10140 rmax2 = SQR(ctl->sample_dx);
10141 area = M_PI * rmax2;
10142 }
10143
10144 /* Set time interval for output... */
10145 double t0 = t - 0.5 * ctl->dt_mod;
10146 double t1 = t + 0.5 * ctl->dt_mod;
10147
10148 /* Loop over observations... */
10149 for (int i = 0; i < nobs; i++) {
10150
10151 /* Check time... */
10152 if (rt[i] < t0)
10153 continue;
10154 else if (rt[i] >= t1)
10155 break;
10156
10157 /* Calculate Cartesian coordinates... */
10158 double x0[3];
10159 geo2cart(0, rlon[i], rlat[i], x0);
10160
10161 /* Set pressure range... */
10162 double rp = P(rz[i]);
10163 double ptop = P(rz[i] + ctl->sample_dz);
10164 double pbot = P(rz[i] - ctl->sample_dz);
10165
10166 /* Init... */
10167 double mass = 0;
10168 int np = 0;
10169
10170 /* Loop over air parcels... */
10171#pragma omp parallel for default(shared) reduction(+:mass,np)
10172 for (int ip = 0; ip < atm->np; ip++) {
10173
10174 /* Check time... */
10175 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10176 continue;
10177
10178 /* Check latitude... */
10179 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
10180 continue;
10181
10182 /* Check horizontal distance... */
10183 double x1[3];
10184 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
10185 if (DIST2(x0, x1) > rmax2)
10186 continue;
10187
10188 /* Check pressure... */
10189 if (ctl->sample_dz > 0)
10190 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
10191 continue;
10192
10193 /* Add mass... */
10194 if (ctl->qnt_m >= 0)
10195 mass +=
10196 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
10197 np++;
10198 }
10199
10200 /* Calculate column density... */
10201 double cd = mass / (1e6 * area);
10202
10203 /* Calculate volume mixing ratio... */
10204 double vmr = 0;
10205 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
10206 if (mass > 0) {
10207
10208 /* Get temperature... */
10209 double temp;
10211 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
10212 rlon[i], rlat[i], &temp, ci, cw, 1);
10213
10214 /* Calculate volume mixing ratio... */
10215 vmr = MA / ctl->molmass * mass
10216 / (RHO(rp, temp) * 1e6 * area * 1e3 * ctl->sample_dz);
10217 }
10218 } else
10219 vmr = NAN;
10220
10221 /* Write output... */
10222 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
10223 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
10224 }
10225
10226 /* Finalize...... */
10227 if (t == ctl->t_stop) {
10228
10229 /* Close output file... */
10230 fclose(out);
10231
10232 /* Free... */
10233 free(rt);
10234 free(rz);
10235 free(rlon);
10236 free(rlat);
10237 free(robs);
10238 }
10239}
10240
10241/*****************************************************************************/
10242
10244 const char *filename,
10245 ctl_t * ctl,
10246 atm_t * atm,
10247 double t) {
10248
10249 static FILE *out;
10250
10251 static double rmax2, x0[3], x1[3];
10252
10253 /* Set timer... */
10254 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
10255
10256 /* Init... */
10257 if (t == ctl->t_start) {
10258
10259 /* Write info... */
10260 LOG(1, "Write station data: %s", filename);
10261
10262 /* Create new file... */
10263 if (!(out = fopen(filename, "w")))
10264 ERRMSG("Cannot create file!");
10265
10266 /* Write header... */
10267 fprintf(out,
10268 "# $1 = time [s]\n"
10269 "# $2 = altitude [km]\n"
10270 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
10271 for (int iq = 0; iq < ctl->nq; iq++)
10272 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
10273 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10274 fprintf(out, "\n");
10275
10276 /* Set geolocation and search radius... */
10277 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
10278 rmax2 = SQR(ctl->stat_r);
10279 }
10280
10281 /* Set time interval for output... */
10282 double t0 = t - 0.5 * ctl->dt_mod;
10283 double t1 = t + 0.5 * ctl->dt_mod;
10284
10285 /* Loop over air parcels... */
10286 for (int ip = 0; ip < atm->np; ip++) {
10287
10288 /* Check time... */
10289 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10290 continue;
10291
10292 /* Check time range for station output... */
10293 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
10294 continue;
10295
10296 /* Check station flag... */
10297 if (ctl->qnt_stat >= 0)
10298 if ((int) atm->q[ctl->qnt_stat][ip])
10299 continue;
10300
10301 /* Get Cartesian coordinates... */
10302 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
10303
10304 /* Check horizontal distance... */
10305 if (DIST2(x0, x1) > rmax2)
10306 continue;
10307
10308 /* Set station flag... */
10309 if (ctl->qnt_stat >= 0)
10310 atm->q[ctl->qnt_stat][ip] = 1;
10311
10312 /* Write data... */
10313 fprintf(out, "%.2f %g %g %g",
10314 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
10315 for (int iq = 0; iq < ctl->nq; iq++) {
10316 fprintf(out, " ");
10317 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
10318 }
10319 fprintf(out, "\n");
10320 }
10321
10322 /* Close file... */
10323 if (t == ctl->t_stop)
10324 fclose(out);
10325}
10326
10327/*****************************************************************************/
10328
10330 const char *filename,
10331 ctl_t * ctl,
10332 atm_t * atm,
10333 double t) {
10334
10335 FILE *out;
10336
10337 /* Set timer... */
10338 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
10339
10340 /* Write info... */
10341 LOG(1, "Write VTK data: %s", filename);
10342
10343 /* Set time interval for output... */
10344 double t0 = t - 0.5 * ctl->dt_mod;
10345 double t1 = t + 0.5 * ctl->dt_mod;
10346
10347 /* Create file... */
10348 if (!(out = fopen(filename, "w")))
10349 ERRMSG("Cannot create file!");
10350
10351 /* Count data points... */
10352 int np = 0;
10353 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10354 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10355 continue;
10356 np++;
10357 }
10358
10359 /* Write header... */
10360 fprintf(out,
10361 "# vtk DataFile Version 3.0\n"
10362 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
10363
10364 /* Write point coordinates... */
10365 fprintf(out, "POINTS %d float\n", np);
10366 if (ctl->vtk_sphere) {
10367 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10368 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10369 continue;
10370 double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
10371 + ctl->vtk_offset) / RE;
10372 double x = radius * cos(atm->lat[ip] / 180. * M_PI)
10373 * cos(atm->lon[ip] / 180. * M_PI);
10374 double y = radius * cos(atm->lat[ip] / 180. * M_PI)
10375 * sin(atm->lon[ip] / 180. * M_PI);
10376 double z = radius * sin(atm->lat[ip] / 180. * M_PI);
10377 fprintf(out, "%g %g %g\n", x, y, z);
10378 }
10379 } else
10380 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10381 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10382 continue;
10383 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
10384 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
10385 }
10386
10387 /* Write point data... */
10388 fprintf(out, "POINT_DATA %d\n", np);
10389 for (int iq = 0; iq < ctl->nq; iq++) {
10390 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
10391 ctl->qnt_name[iq]);
10392 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
10393 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10394 continue;
10395 fprintf(out, "%g\n", atm->q[iq][ip]);
10396 }
10397 }
10398
10399 /* Close file... */
10400 fclose(out);
10401}
void module_mixing_help(ctl_t *ctl, clim_t *clim, atm_t *atm, const int *ixs, const int *iys, const int *izs, int qnt_idx)
Perform interparcel mixing for a specific quantity.
Definition: mptrac.c:3392
int write_met(const char *filename, ctl_t *ctl, met_t *met)
Writes meteorological data to a binary file.
Definition: mptrac.c:9529
void read_met_bin_2d(FILE *in, met_t *met, float var[EX][EY], char *varname)
Reads a 2-dimensional meteorological variable from a binary file and stores it in the provided array.
Definition: mptrac.c:5858
void module_chem_init(ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Initializes the chemistry modules by setting atmospheric composition.
Definition: mptrac.c:2615
void intpol_met_time_2d(met_t *met0, float array0[EX][EY], met_t *met1, float array1[EX][EY], double ts, double lon, double lat, double *var, int *ci, double *cw, int init)
Interpolates meteorological data in 2D space and time.
Definition: mptrac.c:1645
void module_timesteps(ctl_t *ctl, met_t *met0, atm_t *atm, double *dt, double t)
Calculate time steps for air parcels based on specified conditions.
Definition: mptrac.c:3888
void day2doy(const int year, const int mon, const int day, int *doy)
Get day of year from date.
Definition: mptrac.c:852
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:6238
int read_atm_nc(const char *filename, ctl_t *ctl, atm_t *atm)
Reads air parcel data from a generic netCDF file and populates the given atmospheric structure.
Definition: mptrac.c:4408
void write_grid_asc(const char *filename, ctl_t *ctl, double *cd, double *mean[NQ], double *sigma[NQ], double *vmr_impl, double t, double *z, double *lon, double *lat, double *area, double dz, int *np)
Writes grid data to an ASCII file.
Definition: mptrac.c:9301
int read_atm(const char *filename, ctl_t *ctl, atm_t *atm)
Reads air parcel data from a specified file into the given atmospheric structure.
Definition: mptrac.c:4183
void read_met_levels(int ncid, ctl_t *ctl, met_t *met)
Reads meteorological variables at different vertical levels from a NetCDF file.
Definition: mptrac.c:6523
void timer(const char *name, const char *group, int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:8190
void read_clim_photo(const char *filename, clim_photo_t *photo)
Reads photolysis rates from a NetCDF file and populates the given photolysis structure.
Definition: mptrac.c:4501
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:6083
double sedi(const double p, const double T, const double rp, const double rhop)
Calculates the sedimentation velocity of a particle in air.
Definition: mptrac.c:8015
void module_sedi(ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double *dt)
Simulate sedimentation of particles in the atmosphere.
Definition: mptrac.c:3763
void module_advect_init(ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm)
Initializes the advection module by setting up pressure fields.
Definition: mptrac.c:2350
void read_met_grid(const char *filename, int ncid, ctl_t *ctl, met_t *met)
Reads meteorological grid information from a NetCDF file.
Definition: mptrac.c:6405
void write_met_bin_3d(FILE *out, ctl_t *ctl, met_t *met, float var[EX][EY][EP], char *varname, int precision, double tolerance)
Writes a 3-dimensional meteorological variable to a binary file.
Definition: mptrac.c:9681
void read_clim(ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:4441
void module_wet_deposition(ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double *dt)
Perform wet deposition calculations for air parcels.
Definition: mptrac.c:4024
void read_obs_asc(const char *filename, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
Reads observation data from an ASCII file.
Definition: mptrac.c:7886
int locate_reg(const double *xx, const int n, const double x)
Locate the index of the interval containing a given value in a regular grid.
Definition: mptrac.c:2153
int read_met_nc_2d(int ncid, char *varname, char *varname2, char *varname3, char *varname4, ctl_t *ctl, met_t *met, float dest[EX][EY], float scl, int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:6787
void write_vtk(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes VTK (Visualization Toolkit) data to a specified file.
Definition: mptrac.c:10329
void module_sort(ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:3792
int read_atm_asc(const char *filename, ctl_t *ctl, atm_t *atm)
Reads air parcel data from an ASCII file and populates the given atmospheric structure.
Definition: mptrac.c:4254
void module_rng_init(int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:3628
int read_clim_ts(const char *filename, clim_ts_t *ts)
Reads a climatological time series from a file and populates the given time series structure.
Definition: mptrac.c:4636
void write_atm_asc(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes air parcel data to an ASCII file or gnuplot.
Definition: mptrac.c:8377
void write_grid_nc(const char *filename, ctl_t *ctl, double *cd, double *mean[NQ], double *sigma[NQ], double *vmr_impl, double t, double *z, double *lon, double *lat, double *area, double dz, int *np)
Writes grid data to a NetCDF file.
Definition: mptrac.c:9405
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:7154
void clim_oh_diurnal_correction(ctl_t *ctl, clim_t *clim)
Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data.
Definition: mptrac.c:112
double clim_zm(const clim_zm_t *zm, const double t, const double lat, const double p)
Interpolates monthly mean zonal mean climatological variables.
Definition: mptrac.c:394
void module_tracer_chem(ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, double *dt)
Simulate chemical reactions involving long-lived atmospheric tracers.
Definition: mptrac.c:3956
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:193
void read_obs_nc(const char *filename, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
Reads observation data from a NetCDF file.
Definition: mptrac.c:7914
void intpol_met_space_3d_ml(met_t *met, float array[EX][EY][EP], double p, double lon, double lat, double *var)
Interpolates a meteorological variable in 3D space (longitude, latitude, pressure).
Definition: mptrac.c:1466
void intpol_met_time_3d(met_t *met0, float array0[EX][EY][EP], met_t *met1, float array1[EX][EY][EP], double ts, double p, double lon, double lat, double *var, int *ci, double *cw, int init)
Interpolates meteorological data in 3D space and time.
Definition: mptrac.c:1593
void write_met_bin_2d(FILE *out, met_t *met, float var[EX][EY], char *varname)
Writes a 2-dimensional meteorological variable to a binary file.
Definition: mptrac.c:9652
void fft_help(double *fcReal, double *fcImag, int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:901
void module_rng(ctl_t *ctl, double *rs, size_t n, int method)
Generate random numbers using various methods and distributions.
Definition: mptrac.c:3659
void module_advect(ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double *dt)
Performs the advection of atmospheric particles using meteorological data.
Definition: mptrac.c:2192
int locate_irr(const double *xx, const int n, const double x)
Locate the index of the interval containing a given value in a sorted array.
Definition: mptrac.c:2055
void get_tropo(int met_tropo, ctl_t *ctl, clim_t *clim, met_t *met, double *lons, int nx, double *lats, int ny, double *pt, double *zt, double *tt, double *qt, double *o3t, double *ps, double *zs)
Calculate tropopause data.
Definition: mptrac.c:1190
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:1848
void write_atm_clams_traj(const char *dirname, ctl_t *ctl, atm_t *atm, double t)
Writes CLaMS trajectory data to a NetCDF file.
Definition: mptrac.c:8558
void read_obs(const char *filename, ctl_t *ctl, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
Reads observation data from a file and stores it in arrays.
Definition: mptrac.c:7842
void time2jsec(const int year, const int mon, const int day, const int hour, const int min, const int sec, const double remain, double *jsec)
Converts time components to seconds since January 1, 2000, 12:00:00 UTC.
Definition: mptrac.c:8159
void write_grid(const char *filename, ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double t)
Writes grid data to a file in ASCII or netCDF format.
Definition: mptrac.c:9109
void read_clim_zm(const char *filename, char *varname, clim_zm_t *zm)
Reads zonally averaged climatological data from a netCDF file and populates the given structure.
Definition: mptrac.c:4690
void read_met_pbl(met_t *met)
Calculates the planetary boundary layer (PBL) height for each grid point.
Definition: mptrac.c:7083
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:4159
void spline(const double *x, const double *y, const int n, const double *x2, double *y2, const int n2, const int method)
Performs spline interpolation or linear interpolation.
Definition: mptrac.c:8048
void read_met_tropo(ctl_t *ctl, clim_t *clim, met_t *met)
Calculates the tropopause and related meteorological variables based on various methods and stores th...
Definition: mptrac.c:7670
int read_atm_clams(const char *filename, ctl_t *ctl, atm_t *atm)
Reads air parcel data from a CLaMS netCDF file and populates the given atmospheric structure.
Definition: mptrac.c:4352
void write_sample(const char *filename, ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double t)
Writes sample data to a specified file.
Definition: mptrac.c:10080
void module_bound_cond(ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, double *dt)
Apply boundary conditions to particles based on meteorological and climatological data.
Definition: mptrac.c:2370
void module_timesteps_init(ctl_t *ctl, atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:3925
int read_atm_bin(const char *filename, ctl_t *ctl, atm_t *atm)
Reads air parcel data from a binary file and populates the given atmospheric structure.
Definition: mptrac.c:4296
void read_met_sample(ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:7402
void module_h2o2_chem(ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, double *dt)
Perform chemical reactions involving H2O2 within cloud particles.
Definition: mptrac.c:2946
void write_station(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes station data to a specified file.
Definition: mptrac.c:10243
void read_met_monotonize(met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:6708
void write_atm(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes air parcel data to a file in various formats.
Definition: mptrac.c:8317
void write_csi(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes Critical Success Index (CSI) data to a file.
Definition: mptrac.c:8752
void intpol_tropo_3d(double time0, float array0[EX][EY], double time1, float array1[EX][EY], double lons[EX], double lats[EY], int nlon, int nlat, double time, double lon, double lat, int method, double *var, double *sigma)
Interpolates tropopause data in 3D (latitude, longitude, and time).
Definition: mptrac.c:1678
void read_met_ml2pl(ctl_t *ctl, met_t *met, float var[EX][EY][EP], char *varname)
Interpolates meteorological data to specified pressure levels.
Definition: mptrac.c:6666
void read_kernel(const char *filename, double kz[EP], double kw[EP], int *nk)
Reads kernel function data from a file and populates the provided arrays.
Definition: mptrac.c:5570
void module_mixing(ctl_t *ctl, clim_t *clim, atm_t *atm, double t)
Update atmospheric properties through interparcel mixing.
Definition: mptrac.c:3302
void module_position(ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double *dt)
Update the positions and pressure levels of atmospheric particles.
Definition: mptrac.c:3569
void module_meteo(ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, double *dt)
Update atmospheric properties using meteorological data.
Definition: mptrac.c:3202
void get_met(ctl_t *ctl, clim_t *clim, double t, met_t **met0, met_t **met1)
Retrieves meteorological data for the specified time.
Definition: mptrac.c:955
void module_oh_chem(ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, double *dt)
Perform hydroxyl chemistry calculations for atmospheric particles.
Definition: mptrac.c:3487
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:3852
void module_chemgrid(ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double tt)
Calculate grid data for chemistry modules.
Definition: mptrac.c:2465
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:8097
int locate_irr_float(const float *xx, const int n, const double x, const int ig)
Locate the index of the interval containing a given value in an irregularly spaced array.
Definition: mptrac.c:2085
void read_met_bin_3d(FILE *in, ctl_t *ctl, met_t *met, float var[EX][EY][EP], char *varname, float bound_min, float bound_max)
Reads 3D meteorological data from a binary file, potentially using different compression methods.
Definition: mptrac.c:5887
void intpol_met_4d_coord(met_t *met0, float heights0[EX][EY][EP], float array0[EX][EY][EP], met_t *met1, float heights1[EX][EY][EP], float array1[EX][EY][EP], double ts, double height, double lon, double lat, double *var, int *ci, double *cw, int init)
Interpolates meteorological variables to a given position and time.
Definition: mptrac.c:1233
void module_isosurf_init(ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, cache_t *cache)
Initialize the isosurface module based on atmospheric data.
Definition: mptrac.c:3026
int read_met_nc_3d(int ncid, char *varname, char *varname2, char *varname3, char *varname4, ctl_t *ctl, met_t *met, float dest[EX][EY][EP], float scl)
Reads a 3-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:6937
void read_met_detrend(ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:6134
double time_from_filename(const char *filename, int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:8258
void module_dry_deposition(ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double *dt)
Simulate dry deposition of atmospheric particles.
Definition: mptrac.c:2883
double clim_oh(const ctl_t *ctl, const clim_t *clim, const double t, const double lon, const double lat, const double p)
Calculates the hydroxyl radical (OH) concentration from climatology data, with an optional diurnal co...
Definition: mptrac.c:88
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:7374
void intpol_met_time_3d_ml(met_t *met0, float array0[EX][EY][EP], met_t *met1, float array1[EX][EY][EP], double ts, double p, double lon, double lat, double *var)
Interpolates a meteorological variable in time and 3D space (longitude, latitude, pressure).
Definition: mptrac.c:1622
void write_atm_clams(const char *filename, ctl_t *ctl, atm_t *atm)
Writes air parcel data to a NetCDF file in the CLaMS format.
Definition: mptrac.c:8509
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:221
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
double sza_calc(const double sec, const double lon, const double lat)
Calculates the solar zenith angle.
Definition: mptrac.c:8118
void read_met_surface(int ncid, met_t *met, ctl_t *ctl)
Reads surface meteorological data from a netCDF file and stores it in the meteorological data structu...
Definition: mptrac.c:7550
void module_decay(ctl_t *ctl, clim_t *clim, atm_t *atm, double *dt)
Simulate exponential decay processes for atmospheric particles.
Definition: mptrac.c:2724
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).
Definition: mptrac.c:871
void intpol_met_space_3d(met_t *met, float array[EX][EY][EP], double p, double lon, double lat, double *var, int *ci, double *cw, int init)
Interpolates meteorological variables in 3D space.
Definition: mptrac.c:1409
void 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:4789
int locate_irr_3d(float profiles[EX][EY][EP], int np, int ind_lon, int ind_lat, double x)
Locate the index of the interval containing a given value in a 3D irregular grid.
Definition: mptrac.c:2119
int read_met(const char *filename, ctl_t *ctl, clim_t *clim, met_t *met)
Reads meteorological data from a file and populates the provided structures.
Definition: mptrac.c:5611
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:7268
void module_isosurf(ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, cache_t *cache, double *dt)
Apply the isosurface module to adjust atmospheric properties.
Definition: mptrac.c:3090
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:1166
void write_atm_bin(const char *filename, ctl_t *ctl, atm_t *atm)
Writes air parcel data to a binary file.
Definition: mptrac.c:8459
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:376
void jsec2time(const double jsec, int *year, int *mon, int *day, int *hour, int *min, int *sec, double *remain)
Converts Julian seconds to calendar date and time components.
Definition: mptrac.c:1771
double scan_ctl(const char *filename, int argc, char *argv[], const char *varname, int arridx, const char *defvalue, char *value)
Scans a control file or command-line arguments for a specified variable.
Definition: mptrac.c:7943
void write_atm_nc(const char *filename, ctl_t *ctl, atm_t *atm)
Writes air parcel data to a NetCDF file.
Definition: mptrac.c:8707
void module_convection(ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double *dt, double *rs)
Simulate convective processes for atmospheric particles.
Definition: mptrac.c:2652
void locate_vert(float profiles[EX][EY][EP], int np, int lon_ap_ind, int lat_ap_ind, double height_ap, int *ind)
Locate the four vertical indizes of a box for a given height value.
Definition: mptrac.c:2172
void get_met_help(ctl_t *ctl, double t, int direct, char *metbase, double dt_met, char *filename)
Helper function to generate the filename for meteorological data.
Definition: mptrac.c:1101
void intpol_met_space_2d(met_t *met, float array[EX][EY], double lon, double lat, double *var, int *ci, double *cw, int init)
Interpolates meteorological variables in 2D space.
Definition: mptrac.c:1536
void module_diffusion_meso(ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, cache_t *cache, double *dt, double *rs)
Simulate mesoscale diffusion for atmospheric particles.
Definition: mptrac.c:2763
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:7209
void geo2cart(const double z, const double lon, const double lat, double *x)
Converts geographic coordinates (longitude, latitude, altitude) to Cartesian coordinates.
Definition: mptrac.c:941
double kernel_weight(const double kz[EP], const double kw[EP], const int nk, const double p)
Calculates the kernel weight based on altitude and given kernel data.
Definition: mptrac.c:1804
void module_diffusion_turb(ctl_t *ctl, clim_t *clim, atm_t *atm, double *dt, double *rs)
Simulate turbulent diffusion for atmospheric particles.
Definition: mptrac.c:2843
void read_met_cape(clim_t *clim, met_t *met)
Calculates Convective Available Potential Energy (CAPE) for each grid point.
Definition: mptrac.c:5973
double tropo_weight(const clim_t *clim, const double t, const double lat, const double p)
Computes the weighting factor for a given pressure with respect to the tropopause.
Definition: mptrac.c:8293
void read_met_geopot(ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:6278
void write_output(const char *dirname, ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double t)
Writes various types of output data to files in a specified directory.
Definition: mptrac.c:9757
void write_prof(const char *filename, ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, double t)
Writes profile data to a specified file.
Definition: mptrac.c:9852
void compress_pck(char *varname, float *array, size_t nxy, size_t nz, int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats.
Definition: mptrac.c:611
void write_ens(const char *filename, ctl_t *ctl, atm_t *atm, double t)
Writes ensemble data to a file.
Definition: mptrac.c:9012
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:1830
double clim_photo(double rate[CP][CSZA][CO3], clim_photo_t *photo, double p, double sza, double o3c)
Calculates the photolysis rate for a given set of atmospheric conditions.
Definition: mptrac.c:142
MPTRAC library declarations.
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1183
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:236
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:217
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1684
void module_kpp_chem(ctl_t *ctl, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, double *dt)
KPP chemistry module.
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:386
void compress_cms(ctl_t *ctl, char *varname, float *array, size_t nx, size_t ny, size_t np, int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using a custom multiscale compression algorithm.
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1225
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:192
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:157
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:187
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:197
void compress_zstd(char *varname, float *array, size_t n, int decompress, FILE *inout)
Compresses or decompresses an array of floats using the Zstandard (ZSTD) library.
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:271
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:641
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1330
#define H0
Scale height [km].
Definition: mptrac.h:177
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1163
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:967
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:808
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:981
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:212
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:656
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:952
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:1881
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1124
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:266
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1509
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:687
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:276
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:281
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:367
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:1706
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1255
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:182
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:172
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:296
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:246
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:621
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:501
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:456
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:261
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:167
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1303
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1609
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:222
#define NORM(a)
Compute the norm (magnitude) of a vector.
Definition: mptrac.h:1198
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1488
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1585
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1659
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1737
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1638
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:536
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:1848
#define ZETA(ps, p, t)
Calculate potential vorticity using the Zeta approximation.
Definition: mptrac.h:1768
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1390
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:757
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:344
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1465
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:311
void broadcast_large_data(void *data, size_t N)
Broadcasts large data across all processes in an MPI communicator.
#define MO3
Molar mass of ozone [g/mol].
Definition: mptrac.h:202
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1522
#define NC_INQ_DIM(dimname, ptr, min, max)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1054
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:241
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:1925
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:1961
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:670
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1360
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:286
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:1811
void thrustSortWrapper(double *__restrict__ c, int n, int *__restrict__ index)
Wrapper to Thrust sorting function.
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1560
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:411
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:251
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1026
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:256
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1279
void compress_zfp(char *varname, float *array, int nx, int ny, int nz, int precision, double tolerance, int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using the ZFP library.
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1415
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:291
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1077
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:827
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1003
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:568
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:435
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:162
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:301
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:519
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:854
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:603
Air parcel data.
Definition: mptrac.h:3068
double time[NP]
Time [s].
Definition: mptrac.h:3074
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3083
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3080
int np
Number of air parcels.
Definition: mptrac.h:3071
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3086
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3077
Cache data structure.
Definition: mptrac.h:3096
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3105
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3108
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3102
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3111
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3099
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3122
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3128
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3137
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3158
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3134
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3152
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3155
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3149
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3143
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3164
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3167
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3146
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3161
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3140
int np
Number of pressure levels.
Definition: mptrac.h:3125
int no3c
Number of total ozone columns.
Definition: mptrac.h:3131
Climatological data.
Definition: mptrac.h:3230
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3272
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3248
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3260
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3251
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3233
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3278
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3266
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3269
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3263
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3242
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3257
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3236
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3254
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3245
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3239
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3275
Climatological data in the form of time series.
Definition: mptrac.h:3178
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3187
double time[CTS]
Time [s].
Definition: mptrac.h:3184
int ntime
Number of timesteps.
Definition: mptrac.h:3181
Climatological data in the form of zonal means.
Definition: mptrac.h:3198
double time[CT]
Time [s].
Definition: mptrac.h:3210
int np
Number of pressure levels.
Definition: mptrac.h:3207
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3216
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3219
int ntime
Number of timesteps.
Definition: mptrac.h:3201
int nlat
Number of latitudes.
Definition: mptrac.h:3204
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3213
Control parameters.
Definition: mptrac.h:2135
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:2948
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2256
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:2918
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:2885
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2403
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2814
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2468
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2289
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:2894
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2676
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2235
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2427
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:2851
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2739
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2763
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2172
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2184
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2436
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2193
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2268
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:2888
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2277
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2715
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2664
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:2909
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2244
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3026
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2724
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2585
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2736
double stat_r
Search radius around station [km].
Definition: mptrac.h:3032
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2808
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:2912
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3056
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2760
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2265
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2778
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2622
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2415
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2499
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2343
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:2975
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:2951
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2439
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2592
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2421
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2529
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2572
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2307
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2370
char species[LEN]
Species.
Definition: mptrac.h:2673
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:2903
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:2915
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2610
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2259
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2619
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:2954
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:2864
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2637
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:2966
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2199
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2334
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2502
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2286
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:2957
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2313
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2569
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3011
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2364
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2458
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2697
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2781
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2553
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:2933
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2490
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2607
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2187
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2211
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2355
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2652
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3038
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:2879
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2604
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:2972
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:2906
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2217
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2787
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:2942
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2340
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2769
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2670
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2325
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2550
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2535
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2196
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2601
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:2978
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2589
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2658
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2202
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:2981
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:2882
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:2891
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2532
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2772
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2616
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2514
int conv_mix_bot
Lower level for mixing (0=particle pressure, 1=surface).
Definition: mptrac.h:2631
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2517
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:2930
int met_zfp_prec
ZFP compression precision for all variables, except z and T.
Definition: mptrac.h:2471
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2493
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:2984
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2250
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2643
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2563
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:2990
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2181
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2560
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2190
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2578
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2727
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2373
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2310
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:2900
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3035
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2790
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2700
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2685
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2733
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2331
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:2869
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2799
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:2876
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2832
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2208
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2400
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3044
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2445
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2628
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3014
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2301
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:2927
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2153
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2229
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2349
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2520
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2649
int met_dx
Stride for longitudes.
Definition: mptrac.h:2523
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2748
int met_convention
Meteo data layout (0=[lev, lat, lon], 1 = [lon, lat, lev]).
Definition: mptrac.h:2461
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2361
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2694
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2802
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2448
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2388
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2382
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2232
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3053
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2247
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2328
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2646
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2575
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2304
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2169
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2406
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2144
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2784
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2253
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:2999
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2352
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2241
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3020
double wet_depo_ic_h[3]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb, pH).
Definition: mptrac.h:2820
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2682
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:2873
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2508
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2205
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2484
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:2960
int conv_mix_top
Upper level for mixing (0=particle pressure, 1=EL).
Definition: mptrac.h:2634
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2430
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2424
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2163
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:2848
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2751
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2220
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2280
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2595
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:2987
int reflect
Reflection of particles at top and bottom boundary (0=no, 1=yes).
Definition: mptrac.h:2598
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2238
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:2857
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2796
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2358
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:2921
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2805
int met_vert_coord
Vertical coordinate of input meteo data (0=pressure-level, 1=model-level).
Definition: mptrac.h:2150
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:2897
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2367
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3029
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2409
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2823
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:2963
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2433
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2394
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2541
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2455
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2661
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2487
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2757
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2292
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2640
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2730
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2298
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2655
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2742
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2706
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2397
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2385
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:2945
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2691
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:2924
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3008
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:2860
int advect_cpl_zeta_and_press_modules
Coupled use of pressure based modules and diabatic advection.
Definition: mptrac.h:2141
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2556
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2754
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:2854
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2718
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3005
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2838
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2538
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:2993
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2766
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2274
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2322
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2337
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3002
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2295
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2841
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:2996
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2511
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2793
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2418
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2829
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2775
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2709
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2505
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:2939
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3041
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2835
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2223
int met_np
Number of target pressure levels.
Definition: mptrac.h:2544
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2178
double met_zfp_tol_t
ZFP compression tolerance for temperature.
Definition: mptrac.h:2474
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2721
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2319
double met_zfp_tol_z
ZFP compression tolerance for geopotential height.
Definition: mptrac.h:2477
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3050
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2712
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2496
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2625
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2376
int advect_vert_coord
Vertical coordinate of air parcels (0=pressure, 1=zeta, 2=eta).
Definition: mptrac.h:2147
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2316
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2412
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2214
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2745
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2688
int met_cms_heur
cmultiscale coarsening heuristics (0=default, 1=mean diff, 2=median diff, 3=max diff).
Definition: mptrac.h:2481
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2826
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2346
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2817
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2811
int met_dy
Stride for latitudes.
Definition: mptrac.h:2526
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2391
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2613
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2667
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2175
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2566
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2262
double t_start
Start time of simulation [s].
Definition: mptrac.h:2442
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2166
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2547
int nq
Number of quantities.
Definition: mptrac.h:2160
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2679
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3017
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3047
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3023
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:2969
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2226
int met_type
Type of meteo data files (0=netCDF, 1=binary, 2=pck, 3=zfp, 4=zstd, 5=cms).
Definition: mptrac.h:2465
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2271
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2283
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:2936
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2379
Meteo data structure.
Definition: mptrac.h:3289
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3349
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3337
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3409
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3379
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3436
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3400
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3373
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3394
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3355
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3316
int nx
Number of longitudes.
Definition: mptrac.h:3295
int ny
Number of latitudes.
Definition: mptrac.h:3298
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3319
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3406
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3328
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3430
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3427
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3325
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3403
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3418
int np
Number of pressure levels.
Definition: mptrac.h:3301
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3385
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3322
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3388
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3424
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3358
float pel[EX][EY]
Pressure at equilibrium level [hPa].
Definition: mptrac.h:3370
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3376
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3364
double lon[EX]
Longitude [deg].
Definition: mptrac.h:3307
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3343
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3346
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3340
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3331
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3382
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3391
int npl
Number of model levels.
Definition: mptrac.h:3304
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3334
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3412
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3352
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3397
double time
Time [s].
Definition: mptrac.h:3292
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3361
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3421
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3367
double lat[EY]
Latitude [deg].
Definition: mptrac.h:3310
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3415
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3433
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3313