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-2025 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 const 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 const size_t start = i * CHUNK_SIZE;
62 const size_t end = (start + CHUNK_SIZE > N) ? N : start + CHUNK_SIZE;
63 const 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 const double radius = sqrt(DOTP(x, x));
81
82 *lat = RAD2DEG(asin(x[2] / radius));
83 *lon = RAD2DEG(atan2(x[1], x[0]));
84 *z = radius - RE;
85}
86
87/*****************************************************************************/
88
89double clim_oh(
90 const ctl_t *ctl,
91 const clim_t *clim,
92 const double t,
93 const double lon,
94 const double lat,
95 const double p) {
96
97 /* Set SZA threshold... */
98 const double sza_thresh = DEG2RAD(85.), cos_sza_thresh = cos(sza_thresh);
99
100 /* Get OH data from climatology... */
101 const double oh = clim_zm(&clim->oh, t, lat, p);
102
103 /* Check beta... */
104 if (ctl->oh_chem_beta <= 0)
105 return oh;
106
107 /* Apply diurnal correction... */
108 const double sza = sza_calc(t, lon, lat);
109 const double denom = (sza <= sza_thresh) ? cos(sza) : cos_sza_thresh;
110 return oh * exp(-ctl->oh_chem_beta / denom);
111}
112
113/*****************************************************************************/
114
116 const ctl_t *ctl,
117 clim_t *clim) {
118
119 /* Set SZA threshold... */
120 const double sza_thresh = DEG2RAD(85.), cos_sza_thresh = cos(sza_thresh);
121
122 /* Loop over climatology data points... */
123 for (int it = 0; it < clim->oh.ntime; it++)
124 for (int iz = 0; iz < clim->oh.np; iz++)
125 for (int iy = 0; iy < clim->oh.nlat; iy++) {
126
127 /* Init... */
128 int n = 0;
129 double sum = 0;
130
131 /* Integrate day/night correction factor over longitude... */
132 for (double lon = -180; lon < 180; lon += 1.0) {
133 const double sza =
134 sza_calc(clim->oh.time[it], lon, clim->oh.lat[iy]);
135 const double denom =
136 (sza <= sza_thresh) ? cos(sza) : cos_sza_thresh;
137 sum += exp(-ctl->oh_chem_beta / denom);
138 n++;
139 }
140
141 /* Apply scaling factor to OH data... */
142 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
143 }
144}
145
146/*****************************************************************************/
147
149 const double rate[CP][CSZA][CO3],
150 const clim_photo_t *photo,
151 const double p,
152 const double sza,
153 const double o3c) {
154
155 /* Check pressure range... */
156 double p_help = p;
157 if (p < photo->p[photo->np - 1])
158 p_help = photo->p[photo->np - 1];
159 else if (p > photo->p[0])
160 p_help = photo->p[0];
161
162 /* Check sza range... */
163 double sza_help = sza;
164 if (sza < photo->sza[0])
165 sza_help = photo->sza[0];
166 else if (sza > photo->sza[photo->nsza - 1])
167 sza_help = photo->sza[photo->nsza - 1];
168
169 /* Check ozone column range... */
170 double o3c_help = o3c;
171 if (o3c < photo->o3c[0])
172 o3c_help = photo->o3c[0];
173 else if (o3c > photo->o3c[photo->no3c - 1])
174 o3c_help = photo->o3c[photo->no3c - 1];
175
176 /* Get indices... */
177 const int ip = locate_irr(photo->p, photo->np, p_help);
178 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
179 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
180
181 /* Interpolate photolysis rate... */
182 const double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
183 photo->p[ip + 1], rate[ip + 1][isza][io3c],
184 p_help);
185 const double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
186 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1],
187 p_help);
188 const double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
189 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c],
190 p_help);
191 const double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
192 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
193 p_help);
194 const double aux0 =
195 LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
196 const double aux1 =
197 LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
198 const double aux =
199 LIN(photo->sza[isza], aux0, photo->sza[isza + 1], aux1, sza_help);
200 return MAX(aux, 0.0);
201}
202
203/*****************************************************************************/
204
206 const clim_t *clim,
207 const double t,
208 const double lat) {
209
210 /* Get seconds since begin of year... */
211 double sec = FMOD(t, 365.25 * 86400.);
212 while (sec < 0)
213 sec += 365.25 * 86400.;
214
215 /* Get indices... */
216 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
217 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
218
219 /* Interpolate tropopause pressure... */
220 const double p0 = LIN(clim->tropo_lat[ilat],
221 clim->tropo[isec][ilat],
222 clim->tropo_lat[ilat + 1],
223 clim->tropo[isec][ilat + 1], lat);
224 const double p1 = LIN(clim->tropo_lat[ilat],
225 clim->tropo[isec + 1][ilat],
226 clim->tropo_lat[ilat + 1],
227 clim->tropo[isec + 1][ilat + 1], lat);
228 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
229}
230
231/*****************************************************************************/
232
234 clim_t *clim) {
235
236 /* Write info... */
237 LOG(1, "Initialize tropopause data...");
238
239 /* Set time [s]... */
240 clim->tropo_ntime = 12;
241 double tropo_time[12] = {
242 1209600.00, 3888000.00, 6393600.00,
243 9072000.00, 11664000.00, 14342400.00,
244 16934400.00, 19612800.00, 22291200.00,
245 24883200.00, 27561600.00, 30153600.00
246 };
247 memcpy(clim->tropo_time, tropo_time, sizeof(clim->tropo_time));
248
249 /* Set latitudes [deg]... */
250 clim->tropo_nlat = 73;
251 const double tropo_lat[73] = {
252 -90, -87.5, -85, -82.5, -80, -77.5, -75, -72.5, -70, -67.5,
253 -65, -62.5, -60, -57.5, -55, -52.5, -50, -47.5, -45, -42.5,
254 -40, -37.5, -35, -32.5, -30, -27.5, -25, -22.5, -20, -17.5,
255 -15, -12.5, -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10, 12.5,
256 15, 17.5, 20, 22.5, 25, 27.5, 30, 32.5, 35, 37.5, 40, 42.5,
257 45, 47.5, 50, 52.5, 55, 57.5, 60, 62.5, 65, 67.5, 70, 72.5,
258 75, 77.5, 80, 82.5, 85, 87.5, 90
259 };
260 memcpy(clim->tropo_lat, tropo_lat, sizeof(clim->tropo_lat));
261
262 /* Set tropopause pressure [hPa] (NCEP/NCAR Reanalysis 1)... */
263 const double tropo[12][73] = {
264 {324.1, 325.6, 325, 324.3, 322.5, 319.7, 314, 307.2, 301.8, 299.6,
265 297.1, 292.2, 285.6, 276.1, 264, 248.9, 231.9, 213.5, 194.4,
266 175.3, 157, 140.4, 126.7, 116.3, 109.5, 105.4, 103, 101.4, 100.4,
267 99.69, 99.19, 98.84, 98.56, 98.39, 98.39, 98.42, 98.44, 98.54,
268 98.68, 98.81, 98.89, 98.96, 99.12, 99.65, 101.4, 105.4, 113.5, 128,
269 152.1, 184.7, 214, 234.1, 247.3, 255.8, 262.6, 267.7, 271.7, 275,
270 277.2, 279, 280.1, 280.4, 280.6, 280.1, 279.3, 278.3, 276.8, 275.8,
271 275.3, 275.6, 275.4, 274.1, 273.5},
272 {337.3, 338.7, 337.8, 336.4, 333, 328.8, 321.1, 312.6, 306.6, 303.7,
273 300.2, 293.8, 285.4, 273.8, 259.6, 242.7, 224.4, 205.2, 186, 167.5,
274 150.3, 135, 122.8, 113.9, 108.2, 104.7, 102.5, 101.1, 100.2, 99.42,
275 98.88, 98.52, 98.25, 98.09, 98.07, 98.1, 98.12, 98.2, 98.25, 98.27,
276 98.26, 98.27, 98.36, 98.79, 100.2, 104.2, 113.7, 131.2, 159.5, 193,
277 220.4, 238.1, 250.2, 258.1, 264.7, 269.7, 273.7, 277.3, 280.2, 282.8,
278 284.9, 286.5, 288.1, 288.8, 289, 288.5, 287.2, 286.3, 286.1, 287.2,
279 287.5, 286.2, 285.8},
280 {335, 336, 335.7, 335.1, 332.3, 328.1, 320.6, 311.8, 305.1, 301.9,
281 297.6, 290, 280.4, 268.3, 254.6, 239.6, 223.9, 207.9, 192.2, 176.9,
282 161.7, 146.4, 132.2, 120.6, 112.3, 107.2, 104.3, 102.4, 101.3,
283 100.4, 99.86, 99.47, 99.16, 98.97, 98.94, 98.97, 99, 99.09, 99.2,
284 99.31, 99.35, 99.41, 99.51, 99.86, 101.1, 104.9, 114.3, 131, 156.8,
285 186.3, 209.3, 224.6, 236.8, 246.3, 254.9, 262.3, 268.8, 274.8,
286 279.9, 284.6, 288.6, 291.6, 294.9, 297.5, 299.8, 301.8, 303.1,
287 304.3, 304.9, 306, 306.6, 306.2, 306},
288 {306.2, 306.7, 305.7, 307.1, 307.3, 306.4, 301.8, 296.2, 292.4,
289 290.3, 287.1, 280.9, 273.4, 264.3, 254.1, 242.8, 231, 219, 207.2,
290 195.5, 183.3, 169.7, 154.7, 138.7, 124.1, 113.6, 107.8, 104.7,
291 102.8, 101.7, 100.9, 100.4, 100, 99.79, 99.7, 99.66, 99.68, 99.79,
292 99.94, 100.2, 100.5, 100.9, 101.4, 102.1, 103.4, 107, 115.2, 129.1,
293 148.7, 171, 190.8, 205.6, 218.4, 229.4, 239.6, 248.6, 256.5,
294 263.7, 270.3, 276.6, 282.6, 288.1, 294.5, 300.4, 306.3, 311.4,
295 315.1, 318.3, 320.3, 322.2, 322.8, 321.5, 321.1},
296 {266.5, 264.9, 260.8, 261, 262, 263, 261.3, 259.7, 259.2, 259.8,
297 260.1, 258.6, 256.7, 253.6, 249.5, 243.9, 237.4, 230, 222.1, 213.9,
298 205, 194.4, 180.4, 161.8, 140.7, 122.9, 112.1, 106.7, 104.1, 102.7,
299 101.8, 101.4, 101.1, 101, 101, 101, 101.1, 101.2, 101.5, 101.9,
300 102.4, 103, 103.8, 104.9, 106.8, 110.1, 115.6, 124, 135.2, 148.9,
301 165.2, 181.3, 198, 211.8, 223.5, 233.8, 242.9, 251.5, 259, 266.2,
302 273.1, 279.2, 286.2, 292.8, 299.6, 306, 311.1, 315.5, 318.8, 322.6,
303 325.3, 325.8, 325.8},
304 {220.1, 218.1, 210.8, 207.2, 207.6, 210.5, 211.4, 213.5, 217.3,
305 222.4, 227.9, 232.8, 237.4, 240.8, 242.8, 243, 241.5, 238.6, 234.2,
306 228.5, 221, 210.7, 195.1, 172.9, 147.8, 127.6, 115.6, 109.9, 107.1,
307 105.7, 105, 104.8, 104.8, 104.9, 105, 105.1, 105.3, 105.5, 105.8,
308 106.4, 107, 107.6, 108.1, 108.8, 110, 111.8, 114.2, 117.4, 121.6,
309 127.9, 137.3, 151.2, 169.5, 189, 205.8, 218.9, 229.1, 237.8, 245,
310 251.5, 257.1, 262.3, 268.2, 274, 280.4, 286.7, 292.4, 297.9, 302.9,
311 308.5, 312.2, 313.1, 313.3},
312 {187.4, 184.5, 173.3, 166.1, 165.4, 167.8, 169.6, 173.6, 179.6,
313 187.9, 198.9, 210, 220.5, 229.2, 235.7, 239.9, 241.8, 241.6, 239.6,
314 235.8, 229.4, 218.6, 200.9, 175.9, 149.4, 129.4, 118.3, 113.1,
315 110.8, 109.7, 109.3, 109.4, 109.7, 110, 110.2, 110.4, 110.5, 110.7,
316 111, 111.4, 111.8, 112.1, 112.3, 112.7, 113.2, 113.9, 115, 116.4,
317 117.9, 120.4, 124.1, 130.9, 142.2, 159.6, 179.6, 198.5, 212.9,
318 224.2, 232.7, 239.1, 243.8, 247.7, 252.4, 257.3, 263.2, 269.5,
319 275.4, 281.1, 286.3, 292, 296.3, 298.2, 298.8},
320 {166, 166.4, 155.7, 148.3, 147.1, 149, 152.1, 157, 163.6, 172.4,
321 185.3, 199.2, 212.6, 224, 233.2, 239.6, 243.3, 244.6, 243.6, 240.3,
322 233.9, 222.6, 203.7, 177, 149.5, 129.7, 119, 114, 111.7, 110.7,
323 110.3, 110.3, 110.6, 110.9, 111.1, 111.3, 111.5, 111.6, 111.9,
324 112.2, 112.5, 112.6, 112.8, 113, 113.4, 114, 115.1, 116.5, 118.3,
325 120.9, 124.4, 130.2, 139.4, 154.6, 173.8, 193.1, 208.1, 220.4,
326 230.1, 238.2, 244.7, 249.5, 254.5, 259.3, 264.5, 269.4, 273.7,
327 278.2, 282.6, 287.4, 290.9, 292.5, 293},
328 {171.9, 172.8, 166.2, 162.3, 161.4, 162.5, 165.2, 169.6, 175.3,
329 183.1, 193.8, 205.9, 218.3, 229.6, 238.5, 244.3, 246.9, 246.7,
330 243.8, 238.4, 230.2, 217.9, 199.6, 174.9, 148.9, 129.8, 119.5,
331 114.8, 112.3, 110.9, 110.3, 110.1, 110.2, 110.3, 110.4, 110.5,
332 110.6, 110.8, 111, 111.4, 111.8, 112, 112.2, 112.4, 112.9, 113.6,
333 114.7, 116.3, 118.4, 121.9, 127.1, 136.1, 149.8, 168.4, 186.9,
334 203.3, 217, 229.1, 238.7, 247, 254, 259.3, 264.3, 268.3, 272.5,
335 276.6, 280.4, 284.4, 288.4, 293.3, 297.2, 298.7, 299.1},
336 {191.6, 192.2, 189, 188.1, 190.2, 193.7, 197.8, 202.9, 208.5,
337 215.6, 224.2, 233.1, 241.2, 247.3, 250.8, 251.3, 248.9, 244.2,
338 237.3, 228.4, 217.2, 202.9, 184.5, 162.5, 140.7, 124.8, 116.2,
339 111.8, 109.4, 107.9, 107, 106.7, 106.6, 106.6, 106.7, 106.7,
340 106.8, 107, 107.4, 108, 108.7, 109.3, 109.8, 110.4, 111.2,
341 112.4, 114.2, 116.9, 121.1, 127.9, 139.3, 155.2, 173.6, 190.7,
342 206.1, 220.1, 232.3, 243, 251.8, 259.2, 265.7, 270.6, 275.3,
343 279.3, 283.3, 286.9, 289.7, 292.8, 296.1, 300.5, 303.9, 304.8,
344 305.1},
345 {241.5, 239.6, 236.8, 237.4, 239.4, 242.3, 244.2, 246.4, 249.2,
346 253.6, 258.6, 262.7, 264.8, 264.2, 260.6, 254.1, 245.5, 235.3,
347 223.9, 211.7, 198.3, 183.1, 165.6, 147.1, 130.5, 118.7, 111.9,
348 108.1, 105.8, 104.3, 103.4, 102.8, 102.5, 102.4, 102.5, 102.5,
349 102.5, 102.7, 103.1, 103.8, 104.6, 105.4, 106.1, 107, 108.2,
350 109.9, 112.8, 117.5, 126, 140.4, 161, 181.9, 201.2, 216.8, 230.4,
351 241.8, 251.4, 259.9, 266.9, 272.8, 277.4, 280.4, 282.9, 284.6,
352 286.1, 287.4, 288.3, 289.5, 290.9, 294.2, 296.9, 297.5, 297.6},
353 {301.2, 300.3, 296.6, 295.4, 295, 294.3, 291.2, 287.4, 284.9, 284.7,
354 284.1, 281.5, 277.1, 270.4, 261.7, 250.6, 237.6, 223.1, 207.9, 192,
355 175.8, 158.8, 142.1, 127.6, 116.8, 109.9, 106, 103.6, 102.1, 101.1,
356 100.4, 99.96, 99.6, 99.37, 99.32, 99.32, 99.31, 99.46, 99.77, 100.2,
357 100.7, 101.3, 101.8, 102.7, 104.1, 106.8, 111.9, 121, 136.7, 160,
358 186.9, 209.9, 228.1, 241.2, 251.5, 259.5, 265.7, 270.9, 274.8, 278,
359 280.3, 281.8, 283, 283.3, 283.7, 283.8, 283, 282.2, 281.2, 281.4,
360 281.7, 281.1, 281.2}
361 };
362 memcpy(clim->tropo, tropo, sizeof(clim->tropo));
363
364 /* Get range... */
365 double tropomin = 1e99, tropomax = -1e99;
366 for (int it = 0; it < clim->tropo_ntime; it++)
367 for (int iy = 0; iy < clim->tropo_nlat; iy++) {
368 tropomin = MIN(tropomin, clim->tropo[it][iy]);
369 tropomax = MAX(tropomax, clim->tropo[it][iy]);
370 }
371
372 /* Write info... */
373 LOG(2, "Number of time steps: %d", clim->tropo_ntime);
374 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
375 clim->tropo_time[0], clim->tropo_time[1],
376 clim->tropo_time[clim->tropo_ntime - 1]);
377 LOG(2, "Number of latitudes: %d", clim->tropo_nlat);
378 LOG(2, "Latitudes: %g, %g ... %g deg",
379 clim->tropo_lat[0], clim->tropo_lat[1],
380 clim->tropo_lat[clim->tropo_nlat - 1]);
381 LOG(2, "Tropopause altitude range: %g ... %g hPa", Z(tropomax),
382 Z(tropomin));
383 LOG(2, "Tropopause pressure range: %g ... %g hPa", tropomin, tropomax);
384}
385
386/*****************************************************************************/
387
388double clim_ts(
389 const clim_ts_t *ts,
390 const double t) {
391
392 /* Interpolate... */
393 if (t <= ts->time[0])
394 return ts->vmr[0];
395 else if (t >= ts->time[ts->ntime - 1])
396 return ts->vmr[ts->ntime - 1];
397 else {
398 const int idx = locate_irr(ts->time, ts->ntime, t);
399 return LIN(ts->time[idx], ts->vmr[idx],
400 ts->time[idx + 1], ts->vmr[idx + 1], t);
401 }
402}
403
404/*****************************************************************************/
405
406double clim_zm(
407 const clim_zm_t *zm,
408 const double t,
409 const double lat,
410 const double p) {
411
412 /* Get seconds since begin of year... */
413 double sec = FMOD(t, 365.25 * 86400.);
414 while (sec < 0)
415 sec += 365.25 * 86400.;
416
417 /* Check pressure range... */
418 double p_help = p;
419 if (p < zm->p[zm->np - 1])
420 p_help = zm->p[zm->np - 1];
421 else if (p > zm->p[0])
422 p_help = zm->p[0];
423
424 /* Check latitude range... */
425 double lat_help = lat;
426 if (lat < zm->lat[0])
427 lat_help = zm->lat[0];
428 else if (lat > zm->lat[zm->nlat - 1])
429 lat_help = zm->lat[zm->nlat - 1];
430
431 /* Get indices... */
432 const int isec = locate_irr(zm->time, zm->ntime, sec);
433 const int ilat = locate_reg(zm->lat, zm->nlat, lat_help);
434 const int ip = locate_irr(zm->p, zm->np, p_help);
435
436 /* Interpolate climatology data... */
437 const double aux00 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat],
438 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat],
439 p_help);
440 const double aux01 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat + 1],
441 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat + 1],
442 p_help);
443 const double aux10 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat],
444 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat],
445 p_help);
446 const double aux11 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat + 1],
447 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat + 1],
448 p_help);
449 const double aux0 =
450 LIN(zm->lat[ilat], aux00, zm->lat[ilat + 1], aux01, lat_help);
451 const double aux1 =
452 LIN(zm->lat[ilat], aux10, zm->lat[ilat + 1], aux11, lat_help);
453 const double aux = LIN(zm->time[isec], aux0, zm->time[isec + 1], aux1, sec);
454 return MAX(aux, 0.0);
455}
456
457/*****************************************************************************/
458
459#ifdef CMS
460void compress_cms(
461 const ctl_t *ctl,
462 const char *varname,
463 float *array,
464 const size_t nx,
465 const size_t ny,
466 const size_t np,
467 const int decompress,
468 FILE *inout) {
469
470 /* Set lon-lat grid... */
471 const size_t nxy = nx * ny;
472 double lon[EX], lat[EY];
473 for (size_t ix = 0; ix < nx; ix++)
474 lon[ix] = 360. * (double) ix / ((double) nx - 1.);
475 for (size_t iy = 0; iy < ny; iy++)
476 lat[iy] = 90. - 180. * (double) iy / ((double) ny - 1.);
477
478 /* Set multiscale parameters... */
479 const char domain[] = "[0.0, 360.0]x[-90.0, 90.0]";
480 const int Nd0_x = 48;
481 const int Nd0_y = 24;
482 const int max_level_grid = 6;
483 cms_param_t *cms_param
484 = cms_set_parameters(nx, ny, max_level_grid, Nd0_x, Nd0_y, domain);
485
486 /* Init... */
487 double cr = 0, t_coars = 0, t_eval = 0;
488
489 /* Read compressed stream and decompress array... */
490 if (decompress) {
491
492 /* Loop over levels... */
493 for (size_t ip = 0; ip < np; ip++) {
494
495 /* Initialize multiscale module... */
496 cms_module_t *cms_ptr = cms_init(cms_param);
497
498 /* Read binary data... */
499 cms_sol_t *cms_sol;
500 if (ctl->met_cms_zstd == 1)
501 cms_sol = cms_read_zstd_sol(cms_ptr, inout);
502 else
503 cms_sol = cms_read_sol(cms_ptr, inout);
504
505 /* Evaluate... */
506#pragma omp parallel for collapse(2) default(shared)
507 for (size_t ix = 0; ix < nx; ix++)
508 for (size_t iy = 0; iy < ny; iy++) {
509 double val;
510 const double x[] = { lon[ix], lat[iy] };
511 cms_eval(cms_ptr, cms_sol, x, &val);
512 array[ARRAY_3D(ix, iy, ny, ip, np)] = (float) val;
513 }
514
515 /* Calculate mean compression ratio... */
516 cr += cms_compression_rate(cms_ptr, cms_sol) / (double) np;
517
518 /* Free... */
519 cms_delete_sol(cms_sol);
520 cms_delete_module(cms_ptr);
521 }
522
523 /* Write info... */
524 LOG(2, "Read 3-D variable: %s (CMS, RATIO= %g)", varname, cr);
525 }
526
527 /* Compress array and output compressed stream... */
528 else {
529
530 /* Init... */
531 cms_module_t *cms_ptr[EP];
532 cms_sol_t *cms_sol[EP];
533
534 /* Loop over batches... */
535 const size_t dip = (ctl->met_cms_batch <= 0
536 ? (size_t) omp_get_max_threads()
537 : (size_t) ctl->met_cms_batch);
538 for (size_t ip0 = 0; ip0 < np; ip0 += dip) {
539
540 /* Measure time... */
541 double t0 = omp_get_wtime();
542
543 /* Loop over levels... */
544#pragma omp parallel for default(shared)
545 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
546
547 /* Allocate... */
548 float *tmp_arr;
549 ALLOC(tmp_arr, float,
550 nxy);
551
552 /* Copy level data... */
553 for (size_t ix = 0; ix < nx; ++ix)
554 for (size_t iy = 0; iy < ny; ++iy)
555 tmp_arr[ARRAY_2D(ix, iy, ny)] =
556 array[ARRAY_3D(ix, iy, ny, ip, np)];
557
558 /* Set eps threshold value... */
559 double c_thresh_test;
560 if (strcasecmp(varname, "Z") == 0)
561 c_thresh_test = ctl->met_cms_eps_z;
562 else if (strcasecmp(varname, "T") == 0)
563 c_thresh_test = ctl->met_cms_eps_t;
564 else if (strcasecmp(varname, "U") == 0)
565 c_thresh_test = ctl->met_cms_eps_u;
566 else if (strcasecmp(varname, "V") == 0)
567 c_thresh_test = ctl->met_cms_eps_v;
568 else if (strcasecmp(varname, "W") == 0)
569 c_thresh_test = ctl->met_cms_eps_w;
570 else if (strcasecmp(varname, "PV") == 0)
571 c_thresh_test = ctl->met_cms_eps_pv;
572 else if (strcasecmp(varname, "H2O") == 0)
573 c_thresh_test = ctl->met_cms_eps_h2o;
574 else if (strcasecmp(varname, "O3") == 0)
575 c_thresh_test = ctl->met_cms_eps_o3;
576 else if (strcasecmp(varname, "LWC") == 0)
577 c_thresh_test = ctl->met_cms_eps_lwc;
578 else if (strcasecmp(varname, "RWC") == 0)
579 c_thresh_test = ctl->met_cms_eps_rwc;
580 else if (strcasecmp(varname, "IWC") == 0)
581 c_thresh_test = ctl->met_cms_eps_iwc;
582 else if (strcasecmp(varname, "SWC") == 0)
583 c_thresh_test = ctl->met_cms_eps_swc;
584 else if (strcasecmp(varname, "CC") == 0)
585 c_thresh_test = ctl->met_cms_eps_cc;
586 else
587 ERRMSG("Variable name unknown!");
588
589 /* Initialize multiscale module... */
590 cms_ptr[ip] = cms_init(cms_param);
591
592 /* Coarsening... */
593 cms_sol[ip] =
594 cms_read_arr_new(cms_ptr[ip], tmp_arr, lon, lat,
595 nx, ny, c_thresh_test);
596
597 /* Free... */
598 free(tmp_arr);
599 }
600
601 /* Measure time... */
602 t_coars += (omp_get_wtime() - t0);
603
604 /* Loop over levels... */
605 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
606
607 /* Allocate... */
608 double *tmp_cms, *tmp_org, *tmp_diff;
609 ALLOC(tmp_cms, double,
610 nxy);
611 ALLOC(tmp_org, double,
612 nxy);
613 ALLOC(tmp_diff, double,
614 nxy);
615
616 /* Measure time... */
617 t0 = omp_get_wtime();
618
619 /* Evaluate... */
620#pragma omp parallel for collapse(2) default(shared)
621 for (size_t ix = 0; ix < nx; ix++)
622 for (size_t iy = 0; iy < ny; iy++) {
623 const size_t idx = ARRAY_2D(ix, iy, ny);
624 const double x[] = { lon[ix], lat[iy] };
625 cms_eval(cms_ptr[ip], cms_sol[ip], x, &tmp_cms[idx]);
626 tmp_org[idx] = array[ARRAY_3D(ix, iy, ny, ip, np)];
627 tmp_diff[idx] = tmp_cms[idx] - tmp_org[idx];
628 }
629
630 /* Measure time... */
631 t_eval += (omp_get_wtime() - t0);
632
633 /* Write info... */
634 LOG(2,
635 "cmultiscale: var= %s / lev= %lu / ratio= %g / rho= %g"
636 " / mean= %g / sd= %g / min= %g / max= %g", varname, ip,
637 cms_compression_rate(cms_ptr[ip], cms_sol[ip]),
638 gsl_stats_correlation(tmp_cms, 1, tmp_org, 1, nxy),
639 gsl_stats_mean(tmp_diff, 1, nxy), gsl_stats_sd(tmp_diff, 1, nxy),
640 gsl_stats_min(tmp_diff, 1, nxy), gsl_stats_max(tmp_diff, 1, nxy));
641
642 /* Calculate mean compression ratio... */
643 cr += cms_compression_rate(cms_ptr[ip], cms_sol[ip]) / (double) np;
644
645 /* Save binary data... */
646 if (ctl->met_cms_zstd == 1)
647 cms_save_zstd_sol(cms_sol[ip], inout, 3);
648 else
649 cms_save_sol(cms_sol[ip], inout);
650
651 /* Free... */
652 cms_delete_sol(cms_sol[ip]);
653 cms_delete_module(cms_ptr[ip]);
654 free(tmp_cms);
655 free(tmp_org);
656 free(tmp_diff);
657 }
658 }
659
660 /* Write info... */
661 LOG(2, "Write 3-D variable: %s"
662 " (CMS, RATIO= %g, T_COARS= %g s, T_EVAL= %g s)",
663 varname, cr, t_coars, t_eval);
664 }
665
666 /* Free... */
667 cms_delete_param(cms_param);
668}
669#endif
670
671/*****************************************************************************/
672
674 const char *varname,
675 float *array,
676 const size_t nxy,
677 const size_t nz,
678 const int decompress,
679 FILE *inout) {
680
681 double min[EP], max[EP], off[EP], scl[EP];
682
683 unsigned short *sarray;
684
685 /* Allocate... */
686 ALLOC(sarray, unsigned short,
687 nxy * nz);
688
689 /* Read compressed stream and decompress array... */
690 if (decompress) {
691
692 /* Write info... */
693 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
694 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
695
696 /* Read data... */
697 FREAD(&scl, double,
698 nz,
699 inout);
700 FREAD(&off, double,
701 nz,
702 inout);
703 FREAD(sarray, unsigned short,
704 nxy * nz,
705 inout);
706
707 /* Convert to float... */
708#pragma omp parallel for default(shared)
709 for (size_t ixy = 0; ixy < nxy; ixy++)
710 for (size_t iz = 0; iz < nz; iz++)
711 array[ixy * nz + iz]
712 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
713 }
714
715 /* Compress array and output compressed stream... */
716 else {
717
718 /* Write info... */
719 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
720 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
721
722 /* Get range... */
723 for (size_t iz = 0; iz < nz; iz++) {
724 min[iz] = array[iz];
725 max[iz] = array[iz];
726 }
727 for (size_t ixy = 1; ixy < nxy; ixy++)
728 for (size_t iz = 0; iz < nz; iz++) {
729 if (array[ixy * nz + iz] < min[iz])
730 min[iz] = array[ixy * nz + iz];
731 if (array[ixy * nz + iz] > max[iz])
732 max[iz] = array[ixy * nz + iz];
733 }
734
735 /* Get offset and scaling factor... */
736 for (size_t iz = 0; iz < nz; iz++) {
737 scl[iz] = (max[iz] - min[iz]) / 65533.;
738 off[iz] = min[iz];
739 }
740
741 /* Convert to short... */
742#pragma omp parallel for default(shared)
743 for (size_t ixy = 0; ixy < nxy; ixy++)
744 for (size_t iz = 0; iz < nz; iz++)
745 if (scl[iz] != 0)
746 sarray[ixy * nz + iz] = (unsigned short)
747 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
748 else
749 sarray[ixy * nz + iz] = 0;
750
751 /* Write data... */
752 FWRITE(&scl, double,
753 nz,
754 inout);
755 FWRITE(&off, double,
756 nz,
757 inout);
758 FWRITE(sarray, unsigned short,
759 nxy * nz,
760 inout);
761 }
762
763 /* Free... */
764 free(sarray);
765}
766
767/*****************************************************************************/
768
769#ifdef SZ3
770void compress_sz3(
771 const char *varname,
772 float *array,
773 int nx,
774 int ny,
775 int nz,
776 int precision,
777 double tolerance,
778 int decompress,
779 FILE *inout) {
780 if ((precision > 0) == (tolerance > 0.0))
781 ERRMSG("Exactly one of precision or tolerance must be set for SZ3!");
782
783 size_t r1 = (size_t) nx, r2 = (size_t) ny, r3 = (size_t) nz,
784 outSize = 0, total_elems = r1 * r2 * r3;
785
786 unsigned char *bytes = NULL;
787
788 /* Read compressed stream and decompress array... */
789 if (decompress) {
790
791 size_t sz3size;
792 FREAD(&sz3size, size_t,
793 1,
794 inout);
795 ALLOC(bytes, char,
796 sz3size);
797 FREAD(bytes, unsigned char,
798 sz3size,
799 inout);
800
801 void *outData = SZ_decompress(SZ_FLOAT, bytes, sz3size, 0, 0, r3, r2, r1);
802 if (!outData)
803 ERRMSG("Decompression failed!");
804
805 memcpy(array, outData, total_elems * sizeof(float));
806
807 free(outData);
808 free(bytes);
809
810 LOG(2, "Read 3-D variable: %s (SZ3, PREC=%d, TOL=%g, RATIO=%g)",
811 varname, precision, tolerance,
812 (double) (total_elems * sizeof(float)) / (double) sz3size);
813 }
814
815 /* Compress array and output compressed stream... */
816 else {
817
818 const int errBoundMode = (precision > 0) ? REL : ABS;
819 const double absBound = (errBoundMode == ABS) ? tolerance : 0.0;
820 const double relBound =
821 (errBoundMode == REL) ? pow(2.0, -(double) precision) : 0.0;
822
823 bytes = SZ_compress_args(SZ_FLOAT, array, &outSize,
824 errBoundMode, absBound, relBound, 0.0,
825 0, 0, r3, r2, r1);
826 if (!bytes || outSize == 0)
827 ERRMSG("Compression failed!");
828
829 FWRITE(&outSize, size_t,
830 1,
831 inout);
832 FWRITE(bytes, unsigned char,
833 outSize,
834 inout);
835
836 free(bytes);
837
838 LOG(2, "Write 3-D variable: %s (SZ3, PREC=%d, TOL=%g, RATIO=%g)",
839 varname, precision, tolerance,
840 (double) (total_elems * sizeof(float)) / (double) outSize);
841 }
842}
843#endif
844
845/*****************************************************************************/
846
847#ifdef ZFP
848void compress_zfp(
849 const char *varname,
850 float *array,
851 const int nx,
852 const int ny,
853 const int nz,
854 const int precision,
855 const double tolerance,
856 const int decompress,
857 FILE *inout) {
858
859 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
860 const size_t snx = (size_t) nx;
861 const size_t sny = (size_t) ny;
862 const size_t snz = (size_t) nz;
863 const zfp_type type = zfp_type_float;
864 zfp_field *field = zfp_field_3d(array, type, snx, sny, snz);
865
866 /* Allocate meta data for a compressed stream... */
867 zfp_stream *zfp = zfp_stream_open(NULL);
868 if (!field || !zfp)
869 ERRMSG("Failed to allocate zfp structures!");
870
871 /* Set compression mode... */
872 int actual_prec = 0;
873 double actual_tol = 0;
874 if ((precision > 0 && tolerance > 0) || (precision <= 0 && tolerance <= 0)) {
875 ERRMSG("Exactly one of precision or tolerance must be set for zfp!");
876 } else if (precision > 0)
877 actual_prec =
878 (int) zfp_stream_set_precision(zfp, (unsigned int) precision);
879 else if (tolerance > 0)
880 actual_tol = zfp_stream_set_accuracy(zfp, tolerance);
881
882 /* Allocate buffer for compressed data... */
883 const size_t bufsize = zfp_stream_maximum_size(zfp, field);
884 void *buffer;
885 ALLOC(buffer, char,
886 bufsize);
887
888 /* Associate bit stream with allocated buffer... */
889 bitstream *stream = stream_open(buffer, bufsize);
890 zfp_stream_set_bit_stream(zfp, stream);
891 zfp_stream_rewind(zfp);
892
893 /* Read compressed stream and decompress array... */
894 size_t zfpsize;
895 if (decompress) {
896 FREAD(&zfpsize, size_t,
897 1,
898 inout);
899 if (zfpsize > bufsize)
900 ERRMSG("Compressed data size exceeds allocated buffer!");
901 FREAD(buffer, unsigned char,
902 zfpsize,
903 inout);
904 if (!zfp_decompress(zfp, field)) {
905 ERRMSG("Decompression failed!");
906 }
907 const double cr =
908 ((double) (snx * sny * snz * sizeof(float))) / (double) zfpsize;
909 const double bpv = (8.0 * (double) zfpsize) / (double) (snx * sny * snz);
910 LOG(2,
911 "Read 3-D variable: %s (ZFP, PREC= %d, TOL= %g, RATIO= %g, BPV= %g)",
912 varname, actual_prec, actual_tol, cr, bpv);
913 }
914
915 /* Compress array and output compressed stream... */
916 else {
917 zfpsize = zfp_compress(zfp, field);
918 if (!zfpsize) {
919 ERRMSG("Compression failed!");
920 } else {
921 FWRITE(&zfpsize, size_t,
922 1,
923 inout);
924 FWRITE(buffer, unsigned char,
925 zfpsize,
926 inout);
927 }
928 const double cr =
929 ((double) (snx * sny * snz * sizeof(float))) / (double) zfpsize;
930 const double bpv = (8.0 * (double) zfpsize) / (double) (snx * sny * snz);
931 LOG(2,
932 "Write 3-D variable: %s (ZFP, PREC= %d, TOL= %g, RATIO= %g, BPV= %g)",
933 varname, actual_prec, actual_tol, cr, bpv);
934 }
935
936 /* Free... */
937 zfp_field_free(field);
938 stream_close(stream);
939 zfp_stream_close(zfp);
940 free(buffer);
941}
942#endif
943
944/*****************************************************************************/
945
946#ifdef ZSTD
947void compress_zstd(
948 const char *varname,
949 float *array,
950 const size_t n,
951 const int decompress,
952 const int level,
953 FILE *inout) {
954
955 /* Get buffer sizes... */
956 const size_t uncomprLen = n * sizeof(float);
957 size_t compsize, comprLen = ZSTD_compressBound(uncomprLen);
958
959 /* Allocate... */
960 char *compr = calloc(comprLen, 1);
961 if (!compr)
962 ERRMSG("Memory allocation failed!");
963 char *uncompr = (char *) array;
964
965 /* Read compressed stream and decompress array... */
966 if (decompress) {
967 FREAD(&comprLen, size_t,
968 1,
969 inout);
970 FREAD(compr, unsigned char,
971 comprLen,
972 inout);
973 compsize = ZSTD_decompress(uncompr, uncomprLen, compr, comprLen);
974 if (ZSTD_isError(compsize) || compsize != uncomprLen)
975 ERRMSG("Decompression failed or size mismatch!");
976 LOG(2, "Read 3-D variable: %s (ZSTD, RATIO= %g)",
977 varname, ((double) uncomprLen) / (double) comprLen);
978 }
979
980 /* Compress array and output compressed stream... */
981 else {
982 compsize = ZSTD_compress(compr, comprLen, uncompr, uncomprLen, level);
983 if (ZSTD_isError(compsize)) {
984 ERRMSG("Compression failed!");
985 } else {
986 FWRITE(&compsize, size_t,
987 1,
988 inout);
989 FWRITE(compr, unsigned char,
990 compsize,
991 inout);
992 }
993 LOG(2, "Write 3-D variable: %s (ZSTD, RATIO= %g)",
994 varname, ((double) uncomprLen) / (double) compsize);
995 }
996
997 /* Free... */
998 free(compr);
999}
1000#endif
1001
1002/*****************************************************************************/
1003
1005 const int year,
1006 const int mon,
1007 const int day,
1008 int *doy) {
1009
1010 const int
1011 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1012 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1013
1014 /* Get day of year... */
1015 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
1016 *doy = d0l[mon - 1] + day - 1;
1017 else
1018 *doy = d0[mon - 1] + day - 1;
1019}
1020
1021/*****************************************************************************/
1022
1024 const int year,
1025 const int doy,
1026 int *mon,
1027 int *day) {
1028
1029 const int
1030 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1031 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1032
1033 int i;
1034
1035 /* Get month and day... */
1036 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
1037 for (i = 11; i > 0; i--)
1038 if (d0l[i] <= doy)
1039 break;
1040 *mon = i + 1;
1041 *day = doy - d0l[i] + 1;
1042 } else {
1043 for (i = 11; i > 0; i--)
1044 if (d0[i] <= doy)
1045 break;
1046 *mon = i + 1;
1047 *day = doy - d0[i] + 1;
1048 }
1049}
1050
1051/*****************************************************************************/
1052
1054 double *fcReal,
1055 double *fcImag,
1056 const int n) {
1057
1058 double data[2 * EX];
1059
1060 /* Check size... */
1061 if (n > EX)
1062 ERRMSG("Too many data points!");
1063
1064 /* Allocate... */
1065 gsl_fft_complex_wavetable *wavetable =
1066 gsl_fft_complex_wavetable_alloc((size_t) n);
1067 gsl_fft_complex_workspace *workspace =
1068 gsl_fft_complex_workspace_alloc((size_t) n);
1069
1070 /* Set data (real, complex)... */
1071 for (int i = 0; i < n; i++) {
1072 data[2 * i] = fcReal[i];
1073 data[2 * i + 1] = fcImag[i];
1074 }
1075
1076 /* Calculate FFT... */
1077 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
1078
1079 /* Copy data... */
1080 for (int i = 0; i < n; i++) {
1081 fcReal[i] = data[2 * i];
1082 fcImag[i] = data[2 * i + 1];
1083 }
1084
1085 /* Free... */
1086 gsl_fft_complex_wavetable_free(wavetable);
1087 gsl_fft_complex_workspace_free(workspace);
1088}
1089
1090/*****************************************************************************/
1091
1093 const double z,
1094 const double lon,
1095 const double lat,
1096 double *x) {
1097
1098 const double radius = z + RE;
1099 const double latrad = DEG2RAD(lat);
1100 const double lonrad = DEG2RAD(lon);
1101 const double coslat = cos(latrad);
1102
1103 x[0] = radius * coslat * cos(lonrad);
1104 x[1] = radius * coslat * sin(lonrad);
1105 x[2] = radius * sin(latrad);
1106}
1107
1108/*****************************************************************************/
1109
1111 const ctl_t *ctl,
1112 const double t,
1113 const int direct,
1114 const char *metbase,
1115 const double dt_met,
1116 char *filename) {
1117
1118 char repl[LEN];
1119
1120 double t6, r;
1121
1122 int year, mon, day, hour, min, sec;
1123
1124 /* Round time to fixed intervals... */
1125 if (direct == -1)
1126 t6 = floor(t / dt_met) * dt_met;
1127 else
1128 t6 = ceil(t / dt_met) * dt_met;
1129
1130 /* Decode time... */
1131 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1132
1133 /* Set filename of MPTRAC meteo files... */
1134 if (ctl->met_clams == 0) {
1135 if (ctl->met_type == 0)
1136 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1137 else if (ctl->met_type == 1)
1138 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1139 else if (ctl->met_type == 2)
1140 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1141 else if (ctl->met_type == 3)
1142 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1143 else if (ctl->met_type == 4)
1144 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1145 else if (ctl->met_type == 5)
1146 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1147 else if (ctl->met_type == 7)
1148 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
1149 sprintf(repl, "%d", year);
1150 get_met_replace(filename, "YYYY", repl);
1151 sprintf(repl, "%02d", mon);
1152 get_met_replace(filename, "MM", repl);
1153 sprintf(repl, "%02d", day);
1154 get_met_replace(filename, "DD", repl);
1155 sprintf(repl, "%02d", hour);
1156 get_met_replace(filename, "HH", repl);
1157 }
1158
1159 /* Set filename of CLaMS meteo files... */
1160 else {
1161 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1162 sprintf(repl, "%d", year);
1163 get_met_replace(filename, "YYYY", repl);
1164 sprintf(repl, "%02d", year % 100);
1165 get_met_replace(filename, "YY", repl);
1166 sprintf(repl, "%02d", mon);
1167 get_met_replace(filename, "MM", repl);
1168 sprintf(repl, "%02d", day);
1169 get_met_replace(filename, "DD", repl);
1170 sprintf(repl, "%02d", hour);
1171 get_met_replace(filename, "HH", repl);
1172 }
1173}
1174
1175/*****************************************************************************/
1176
1178 char *orig,
1179 char *search,
1180 char *repl) {
1181
1182 char buffer[LEN];
1183
1184 /* Iterate... */
1185 for (int i = 0; i < 3; i++) {
1186
1187 /* Replace sub-string... */
1188 char *ch;
1189 if (!(ch = strstr(orig, search)))
1190 return;
1191 strncpy(buffer, orig, (size_t) (ch - orig));
1192 buffer[ch - orig] = 0;
1193 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1194 orig[0] = 0;
1195 strcpy(orig, buffer);
1196 }
1197}
1198
1199/*****************************************************************************/
1200
1202 const int met_tropo,
1203 ctl_t *ctl,
1204 clim_t *clim,
1205 met_t *met,
1206 const double *lons,
1207 const int nx,
1208 const double *lats,
1209 const int ny,
1210 double *pt,
1211 double *zt,
1212 double *tt,
1213 double *qt,
1214 double *o3t,
1215 double *ps,
1216 double *zs) {
1217
1219
1220 ctl->met_tropo = met_tropo;
1221 read_met_tropo(ctl, clim, met);
1222#pragma omp parallel for default(shared) private(ci,cw)
1223 for (int ix = 0; ix < nx; ix++)
1224 for (int iy = 0; iy < ny; iy++) {
1225 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1226 &pt[iy * nx + ix], ci, cw, 1);
1227 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1228 &ps[iy * nx + ix], ci, cw, 0);
1229 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1230 &zs[iy * nx + ix], ci, cw, 0);
1231 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1232 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1233 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1234 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1235 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1236 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1237 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1238 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1239 }
1240}
1241
1242/*****************************************************************************/
1243
1245 const double *lons,
1246 const int nlon,
1247 const double *lats,
1248 const int nlat,
1249 const double lon,
1250 const double lat,
1251 double *lon2,
1252 double *lat2) {
1253
1254 /* Check longitude... */
1255 *lon2 = FMOD(lon, 360.);
1256 if (*lon2 < lons[0])
1257 *lon2 += 360;
1258 else if (*lon2 > lons[nlon - 1])
1259 *lon2 -= 360;
1260
1261 /* Check latitude... */
1262 *lat2 = lat;
1263 if (lats[0] < lats[nlat - 1])
1264 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
1265 else
1266 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
1267}
1268
1269/*****************************************************************************/
1270
1272 const met_t *met0,
1273 float heights0[EX][EY][EP],
1274 float array0[EX][EY][EP],
1275 const met_t *met1,
1276 float heights1[EX][EY][EP],
1277 float array1[EX][EY][EP],
1278 const double ts,
1279 const double height,
1280 const double lon,
1281 const double lat,
1282 double *var,
1283 int *ci,
1284 double *cw,
1285 const int init) {
1286
1287 if (init) {
1288
1289 /* Check longitude and latitude... */
1290 double lon2, lat2;
1291 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
1292 &lon2, &lat2);
1293
1294 /* Get horizontal indizes... */
1295 ci[0] = locate_irr(met0->lon, met0->nx, lon2);
1296 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
1297
1298 /* Locate the vertical indizes for each edge of the column... */
1299 int ind[2][4];
1300 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1301 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1302
1303 /* Find minimum and maximum indizes... */
1304 ci[2] = ind[0][0];
1305 int k_max = ind[0][0];
1306 for (int i = 0; i < 2; i++)
1307 for (int j = 0; j < 4; j++) {
1308 if (ci[2] > ind[i][j])
1309 ci[2] = ind[i][j];
1310 if (k_max < ind[i][j])
1311 k_max = ind[i][j];
1312 }
1313
1314 /* Get weighting factors for time, longitude and latitude... */
1315 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1316 cw[0] = (lon2 - met0->lon[ci[0]]) /
1317 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1318 cw[1] = (lat2 - met0->lat[ci[1]]) /
1319 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1320
1321 /* Interpolate in time at the lowest level... */
1322 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1323 - heights0[ci[0]][ci[1]][ci[2]])
1324 + heights0[ci[0]][ci[1]][ci[2]];
1325 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1326 - heights0[ci[0]][ci[1] + 1][ci[2]])
1327 + heights0[ci[0]][ci[1] + 1][ci[2]];
1328 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1329 - heights0[ci[0] + 1][ci[1]][ci[2]])
1330 + heights0[ci[0] + 1][ci[1]][ci[2]];
1331 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1332 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1333 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1334
1335 /* Interpolate in latitude direction... */
1336 double height0 = cw[1] * (height01 - height00) + height00;
1337 double height1 = cw[1] * (height11 - height10) + height10;
1338
1339 /* Interpolate in longitude direction... */
1340 double height_bot = cw[0] * (height1 - height0) + height0;
1341
1342 /* Interpolate in time at the upper 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 double height_top = cw[0] * (height1 - height0) + height0;
1362
1363 /* Search at higher levels if height is not in box... */
1364 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1365 ((height_bot <= height) || (height_top > height))
1366 && (height_bot >= height) && (ci[2] < k_max))
1367 ||
1368 ((heights0[0][0][0] < heights0[0][0][1]) &&
1369 ((height_bot >= height) || (height_top < height))
1370 && (height_bot <= height) && (ci[2] < k_max))
1371 ) {
1372
1373 ci[2]++;
1374 height_bot = height_top;
1375
1376 /* Interpolate in time at the next level... */
1377 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1378 - heights0[ci[0]][ci[1]][ci[2] + 1])
1379 + heights0[ci[0]][ci[1]][ci[2] + 1];
1380 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1381 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1382 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1383 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1384 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1385 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1386 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1387 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1388 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1389
1390 /* Interpolate in latitude direction... */
1391 height0 = cw[1] * (height01 - height00) + height00;
1392 height1 = cw[1] * (height11 - height10) + height10;
1393
1394 /* Interpolate in longitude direction... */
1395 height_top = cw[0] * (height1 - height0) + height0;
1396 }
1397
1398 /* Get vertical weighting factors... */
1399 cw[2] = (height - height_bot)
1400 / (height_top - height_bot);
1401 }
1402
1403 /* Calculate the needed array values... */
1404 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1405 - array0[ci[0]][ci[1]][ci[2]])
1406 + array0[ci[0]][ci[1]][ci[2]];
1407 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1408 - array0[ci[0] + 1][ci[1]][ci[2]])
1409 + array0[ci[0] + 1][ci[1]][ci[2]];
1410 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1411 - array0[ci[0]][ci[1] + 1][ci[2]])
1412 + array0[ci[0]][ci[1] + 1][ci[2]];
1413 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1414 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1415 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1416 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1417 - array0[ci[0]][ci[1]][ci[2] + 1])
1418 + array0[ci[0]][ci[1]][ci[2] + 1];
1419 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
1420 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
1421 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
1422 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
1423 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
1424 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
1425 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1426 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1427 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1428
1429 const double array00 = cw[0] * (array100 - array000) + array000;
1430 const double array10 = cw[0] * (array110 - array010) + array010;
1431 const double array01 = cw[0] * (array101 - array001) + array001;
1432 const double array11 = cw[0] * (array111 - array011) + array011;
1433
1434 const double aux0 = cw[1] * (array10 - array00) + array00;
1435 const double aux1 = cw[1] * (array11 - array01) + array01;
1436
1437 /* Interpolate vertically... */
1438 *var = cw[2] * (aux1 - aux0) + aux0;
1439}
1440
1441/*****************************************************************************/
1442
1444 const met_t *met,
1445 float array[EX][EY][EP],
1446 const double p,
1447 const double lon,
1448 const double lat,
1449 double *var,
1450 int *ci,
1451 double *cw,
1452 const int init) {
1453
1454 /* Initialize interpolation... */
1455 if (init) {
1456
1457 /* Check longitude and latitude... */
1458 double lon2, lat2;
1459 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1460 &lon2, &lat2);
1461
1462 /* Get interpolation indices... */
1463 ci[0] = locate_irr(met->p, met->np, p);
1464 ci[1] = locate_reg(met->lon, met->nx, lon2);
1465 ci[2] = locate_irr(met->lat, met->ny, lat2);
1466
1467 /* Get interpolation weights... */
1468 cw[0] = (met->p[ci[0] + 1] - p)
1469 / (met->p[ci[0] + 1] - met->p[ci[0]]);
1470 cw[1] = (met->lon[ci[1] + 1] - lon2)
1471 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1472 cw[2] = (met->lat[ci[2] + 1] - lat2)
1473 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1474 }
1475
1476 /* Interpolate vertically... */
1477 const double aux00 =
1478 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
1479 + array[ci[1]][ci[2]][ci[0] + 1];
1480 const double aux01 =
1481 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
1482 array[ci[1]][ci[2] + 1][ci[0] + 1])
1483 + array[ci[1]][ci[2] + 1][ci[0] + 1];
1484 const double aux10 =
1485 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
1486 array[ci[1] + 1][ci[2]][ci[0] + 1])
1487 + array[ci[1] + 1][ci[2]][ci[0] + 1];
1488 const double aux11 =
1489 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
1490 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
1491 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
1492
1493 /* Interpolate horizontally... */
1494 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
1495 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
1496 *var = cw[1] * (aux0 - aux1) + aux1;
1497}
1498
1499/*****************************************************************************/
1500
1502 const met_t *met,
1503 float zs[EX][EY][EP],
1504 float array[EX][EY][EP],
1505 const double z,
1506 const double lon,
1507 const double lat,
1508 double *var) {
1509
1510 /* Check longitude and latitude... */
1511 double lon2, lat2;
1512 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat, &lon2,
1513 &lat2);
1514
1515 /* Get horizontal indices... */
1516 const int ix = locate_reg(met->lon, met->nx, lon2);
1517 const int iy = locate_irr(met->lat, met->ny, lat2);
1518
1519 /* Interpolate vertically... */
1520 int iz = locate_irr_float(zs[ix][iy], met->npl, z, 0);
1521 double aux00;
1522 if (z >= zs[ix][iy][iz + 1])
1523 aux00 = array[ix][iy][iz + 1];
1524 else if (z <= zs[ix][iy][iz])
1525 aux00 = array[ix][iy][iz];
1526 else
1527 aux00 = LIN(zs[ix][iy][iz], array[ix][iy][iz],
1528 zs[ix][iy][iz + 1], array[ix][iy][iz + 1], z);
1529
1530 iz = locate_irr_float(zs[ix][iy + 1], met->npl, z, iz);
1531 double aux01;
1532 if (z >= zs[ix][iy + 1][iz + 1])
1533 aux01 = array[ix][iy + 1][iz + 1];
1534 else if (z <= zs[ix][iy + 1][iz])
1535 aux01 = array[ix][iy + 1][iz];
1536 else
1537 aux01 = LIN(zs[ix][iy + 1][iz], array[ix][iy + 1][iz],
1538 zs[ix][iy + 1][iz + 1], array[ix][iy + 1][iz + 1], z);
1539
1540 iz = locate_irr_float(zs[ix + 1][iy], met->npl, z, iz);
1541 double aux10;
1542 if (z >= zs[ix + 1][iy][iz + 1])
1543 aux10 = array[ix + 1][iy][iz + 1];
1544 else if (z <= zs[ix + 1][iy][iz])
1545 aux10 = array[ix + 1][iy][iz];
1546 else
1547 aux10 = LIN(zs[ix + 1][iy][iz], array[ix + 1][iy][iz],
1548 zs[ix + 1][iy][iz + 1], array[ix + 1][iy][iz + 1], z);
1549
1550 iz = locate_irr_float(zs[ix + 1][iy + 1], met->npl, z, iz);
1551 double aux11;
1552 if (z >= zs[ix + 1][iy + 1][iz + 1])
1553 aux11 = array[ix + 1][iy + 1][iz + 1];
1554 else if (z <= zs[ix + 1][iy + 1][iz])
1555 aux11 = array[ix + 1][iy + 1][iz];
1556 else
1557 aux11 = LIN(zs[ix + 1][iy + 1][iz], array[ix + 1][iy + 1][iz],
1558 zs[ix + 1][iy + 1][iz + 1], array[ix + 1][iy + 1][iz + 1], z);
1559
1560 /* Interpolate horizontally... */
1561 const double aux0 = LIN(met->lat[iy], aux00, met->lat[iy + 1], aux01, lat2);
1562 const double aux1 = LIN(met->lat[iy], aux10, met->lat[iy + 1], aux11, lat2);
1563 *var = LIN(met->lon[ix], aux0, met->lon[ix + 1], aux1, lon2);
1564}
1565
1566/*****************************************************************************/
1567
1569 const met_t *met,
1570 float array[EX][EY],
1571 const double lon,
1572 const double lat,
1573 double *var,
1574 int *ci,
1575 double *cw,
1576 const int init) {
1577
1578 /* Initialize interpolation... */
1579 if (init) {
1580
1581 /* Check longitude and latitude... */
1582 double lon2, lat2;
1583 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1584 &lon2, &lat2);
1585
1586 /* Get interpolation indices... */
1587 ci[1] = locate_reg(met->lon, met->nx, lon2);
1588 ci[2] = locate_irr(met->lat, met->ny, lat2);
1589
1590 /* Get interpolation weights... */
1591 cw[1] = (met->lon[ci[1] + 1] - lon2)
1592 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1593 cw[2] = (met->lat[ci[2] + 1] - lat2)
1594 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1595 }
1596
1597 /* Set variables... */
1598 const double aux00 = array[ci[1]][ci[2]];
1599 const double aux01 = array[ci[1]][ci[2] + 1];
1600 const double aux10 = array[ci[1] + 1][ci[2]];
1601 const double aux11 = array[ci[1] + 1][ci[2] + 1];
1602
1603 /* Interpolate horizontally... */
1604 if (isfinite(aux00) && isfinite(aux01)
1605 && isfinite(aux10) && isfinite(aux11)) {
1606 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
1607 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
1608 *var = cw[1] * (aux0 - aux1) + aux1;
1609 } else {
1610 if (cw[2] < 0.5) {
1611 if (cw[1] < 0.5)
1612 *var = aux11;
1613 else
1614 *var = aux01;
1615 } else {
1616 if (cw[1] < 0.5)
1617 *var = aux10;
1618 else
1619 *var = aux00;
1620 }
1621 }
1622}
1623
1624/*****************************************************************************/
1625
1627 const met_t *met0,
1628 float array0[EX][EY][EP],
1629 const met_t *met1,
1630 float array1[EX][EY][EP],
1631 const double ts,
1632 const double p,
1633 const double lon,
1634 const double lat,
1635 double *var,
1636 int *ci,
1637 double *cw,
1638 const int init) {
1639
1640 double var0, var1;
1641
1642 /* Spatial interpolation... */
1643 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
1644 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
1645
1646 /* Get weighting factor... */
1647 const double wt = (met1->time - ts) / (met1->time - met0->time);
1648
1649 /* Interpolate... */
1650 *var = wt * (var0 - var1) + var1;
1651}
1652
1653/*****************************************************************************/
1654
1656 const met_t *met0,
1657 float zs0[EX][EY][EP],
1658 float array0[EX][EY][EP],
1659 const met_t *met1,
1660 float zs1[EX][EY][EP],
1661 float array1[EX][EY][EP],
1662 const double ts,
1663 const double p,
1664 const double lon,
1665 const double lat,
1666 double *var) {
1667
1668 double var0, var1;
1669
1670 /* Spatial interpolation... */
1671 intpol_met_space_3d_ml(met0, zs0, array0, p, lon, lat, &var0);
1672 intpol_met_space_3d_ml(met1, zs1, array1, p, lon, lat, &var1);
1673
1674 /* Interpolate... */
1675 *var = LIN(met0->time, var0, met1->time, var1, ts);
1676}
1677
1678/*****************************************************************************/
1679
1681 const met_t *met0,
1682 float array0[EX][EY],
1683 const met_t *met1,
1684 float array1[EX][EY],
1685 const double ts,
1686 const double lon,
1687 const double lat,
1688 double *var,
1689 int *ci,
1690 double *cw,
1691 const int init) {
1692
1693 double var0, var1;
1694
1695 /* Spatial interpolation... */
1696 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
1697 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
1698
1699 /* Get weighting factor... */
1700 const double wt = (met1->time - ts) / (met1->time - met0->time);
1701
1702 /* Interpolate... */
1703 if (isfinite(var0) && isfinite(var1))
1704 *var = wt * (var0 - var1) + var1;
1705 else if (wt < 0.5)
1706 *var = var1;
1707 else
1708 *var = var0;
1709}
1710
1711/*****************************************************************************/
1712
1714 const double time0,
1715 float array0[EX][EY],
1716 const double time1,
1717 float array1[EX][EY],
1718 const double lons[EX],
1719 const double lats[EY],
1720 const int nlon,
1721 const int nlat,
1722 const double time,
1723 const double lon,
1724 const double lat,
1725 const int method,
1726 double *var,
1727 double *sigma) {
1728
1729 double mean = 0;
1730
1731 int n = 0;
1732
1733 /* Check longitude and latitude... */
1734 double lon2, lat2;
1735 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
1736
1737 /* Get indices... */
1738 const int ix = locate_reg(lons, (int) nlon, lon2);
1739 const int iy = locate_irr(lats, (int) nlat, lat2);
1740
1741 /* Calculate standard deviation... */
1742 *sigma = 0;
1743 for (int dx = 0; dx < 2; dx++)
1744 for (int dy = 0; dy < 2; dy++) {
1745 if (isfinite(array0[ix + dx][iy + dy])) {
1746 mean += array0[ix + dx][iy + dy];
1747 *sigma += SQR(array0[ix + dx][iy + dy]);
1748 n++;
1749 }
1750 if (isfinite(array1[ix + dx][iy + dy])) {
1751 mean += array1[ix + dx][iy + dy];
1752 *sigma += SQR(array1[ix + dx][iy + dy]);
1753 n++;
1754 }
1755 }
1756 if (n > 0)
1757 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
1758
1759 /* Linear interpolation... */
1760 if (method == 1 && isfinite(array0[ix][iy])
1761 && isfinite(array0[ix][iy + 1])
1762 && isfinite(array0[ix + 1][iy])
1763 && isfinite(array0[ix + 1][iy + 1])
1764 && isfinite(array1[ix][iy])
1765 && isfinite(array1[ix][iy + 1])
1766 && isfinite(array1[ix + 1][iy])
1767 && isfinite(array1[ix + 1][iy + 1])) {
1768
1769 const double aux00 = LIN(lons[ix], array0[ix][iy],
1770 lons[ix + 1], array0[ix + 1][iy], lon2);
1771 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
1772 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1773 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1774
1775 const double aux10 = LIN(lons[ix], array1[ix][iy],
1776 lons[ix + 1], array1[ix + 1][iy], lon2);
1777 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
1778 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1779 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1780
1781 *var = LIN(time0, aux0, time1, aux1, time);
1782 }
1783
1784 /* Nearest neighbor interpolation... */
1785 else {
1786 const double aux00 = NN(lons[ix], array0[ix][iy],
1787 lons[ix + 1], array0[ix + 1][iy], lon2);
1788 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
1789 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1790 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1791
1792 const double aux10 = NN(lons[ix], array1[ix][iy],
1793 lons[ix + 1], array1[ix + 1][iy], lon2);
1794 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
1795 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1796 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1797
1798 *var = NN(time0, aux0, time1, aux1, time);
1799 }
1800}
1801
1802/*****************************************************************************/
1803
1805 const double jsec,
1806 int *year,
1807 int *mon,
1808 int *day,
1809 int *hour,
1810 int *min,
1811 int *sec,
1812 double *remain) {
1813
1814 struct tm t0, *t1;
1815
1816 t0.tm_year = 100;
1817 t0.tm_mon = 0;
1818 t0.tm_mday = 1;
1819 t0.tm_hour = 0;
1820 t0.tm_min = 0;
1821 t0.tm_sec = 0;
1822
1823 const time_t jsec0 = (time_t) jsec + timegm(&t0);
1824 t1 = gmtime(&jsec0);
1825
1826 *year = t1->tm_year + 1900;
1827 *mon = t1->tm_mon + 1;
1828 *day = t1->tm_mday;
1829 *hour = t1->tm_hour;
1830 *min = t1->tm_min;
1831 *sec = t1->tm_sec;
1832 *remain = jsec - floor(jsec);
1833}
1834
1835/*****************************************************************************/
1836
1838 const double kz[EP],
1839 const double kw[EP],
1840 const int nk,
1841 const double p) {
1842
1843 /* Check number of data points... */
1844 if (nk < 2)
1845 return 1.0;
1846
1847 /* Get altitude... */
1848 const double z = Z(p);
1849
1850 /* Get weighting factor... */
1851 if (z < kz[0])
1852 return kw[0];
1853 else if (z > kz[nk - 1])
1854 return kw[nk - 1];
1855 else {
1856 const int idx = locate_irr(kz, nk, z);
1857 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
1858 }
1859}
1860
1861/*****************************************************************************/
1862
1864 const double t,
1865 const double h2o) {
1866
1867 /*
1868 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
1869 and water vapor volume mixing ratio [1].
1870
1871 Reference: https://en.wikipedia.org/wiki/Lapse_rate
1872 */
1873
1874 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
1875
1876 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
1877}
1878
1879/*****************************************************************************/
1880
1882 ctl_t *ctl) {
1883
1884 if (0 == ctl->met_press_level_def) {
1885
1886 ctl->met_np = 138;
1887
1888 const double press[138] = {
1889 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1890 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1891 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1892 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1893 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1894 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1895 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1896 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1897 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1898 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1899 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1900 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1901 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1902 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1903 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1904 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1905 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1906 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1907 1010.8487, 1013.2500, 1044.45
1908 };
1909
1910 for (int ip = 0; ip < ctl->met_np; ip++)
1911 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1912
1913 } else if (1 == ctl->met_press_level_def) {
1914
1915 ctl->met_np = 92;
1916
1917 const double press[92] = {
1918 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1919 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1920 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1921 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1922 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1923 113.6382,
1924 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1925 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1926 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1927 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1928 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1929 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1930 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1931 1007.4431, 1010.8487, 1013.2500, 1044.45
1932 };
1933
1934 for (int ip = 0; ip < ctl->met_np; ip++)
1935 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1936
1937 } else if (2 == ctl->met_press_level_def) {
1938
1939 ctl->met_np = 60;
1940
1941 const double press[60] = {
1942 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1943 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1944 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1945 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1946 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1947 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1948 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1949 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1044.45
1950 };
1951
1952 for (int ip = 0; ip < ctl->met_np; ip++)
1953 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1954
1955 } else if (3 == ctl->met_press_level_def) {
1956
1957 ctl->met_np = 147;
1958
1959 const double press[147] = {
1960 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1961 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1962 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1963 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1964 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1965 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1966 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1967 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1968 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1969 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1970 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1971 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1972 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1973 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1974 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1975 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1976 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1977 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1978 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
1979 1031.97,
1980 1035.09, 1038.21, 1041.33, 1044.45
1981 };
1982
1983 for (int ip = 0; ip < ctl->met_np; ip++)
1984 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1985
1986 } else if (4 == ctl->met_press_level_def) {
1987
1988 ctl->met_np = 101;
1989
1990 const double press[101] = {
1991 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1992 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1993 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1994 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1995 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1996 113.6382,
1997 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1998 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1999 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2000 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2001 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2002 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2003 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2004 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
2005 1028.85, 1031.97,
2006 1035.09, 1038.21, 1041.33, 1044.45
2007 };
2008
2009 for (int ip = 0; ip < ctl->met_np; ip++)
2010 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2011
2012 } else if (5 == ctl->met_press_level_def) {
2013
2014 ctl->met_np = 62;
2015
2016 const double press[62] = {
2017 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2018 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2019 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2020 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2021 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2022 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2023 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2024 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
2025 1044.45
2026 };
2027
2028 for (int ip = 0; ip < ctl->met_np; ip++)
2029 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2030
2031 } else if (6 == ctl->met_press_level_def) {
2032
2033 ctl->met_np = 137;
2034
2035 const double press[137] = {
2036 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
2037 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
2038 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
2039 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
2040 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
2041 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2042 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
2043 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
2044 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
2045 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
2046 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
2047 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
2048 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
2049 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
2050 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
2051 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
2052 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
2053 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
2054 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
2055 1030.06, 1037.25, 1044.45
2056 };
2057
2058 for (int ip = 0; ip < ctl->met_np; ip++)
2059 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2060
2061 } else if (7 == ctl->met_press_level_def) {
2062
2063 ctl->met_np = 59;
2064
2065 const double press[59] = {
2066 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2067 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2068 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2069 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2070 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2071 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2072 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2073 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2074 1028.53, 1046.13
2075 };
2076
2077 for (int ip = 0; ip < ctl->met_np; ip++)
2078 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2079
2080 } else {
2081 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.");
2082 }
2083
2084 if (ctl->met_np > EP) {
2085 ERRMSG("Recompile with larger EP to use this pressure level definition.");
2086 }
2087}
2088
2089/*****************************************************************************/
2090
2092 const double *xx,
2093 const int n,
2094 const double x) {
2095
2096 int ilo = 0;
2097 int ihi = n - 1;
2098 int i = (ihi + ilo) >> 1;
2099
2100 if (xx[i] < xx[i + 1])
2101 while (ihi > ilo + 1) {
2102 i = (ihi + ilo) >> 1;
2103 if (xx[i] > x)
2104 ihi = i;
2105 else
2106 ilo = i;
2107 } else
2108 while (ihi > ilo + 1) {
2109 i = (ihi + ilo) >> 1;
2110 if (xx[i] <= x)
2111 ihi = i;
2112 else
2113 ilo = i;
2114 }
2115
2116 return ilo;
2117}
2118
2119/*****************************************************************************/
2120
2122 const float *xx,
2123 const int n,
2124 const double x,
2125 const int ig) {
2126
2127 int ilo = 0;
2128 int ihi = n - 1;
2129 int i = (ihi + ilo) >> 1;
2130
2131 if (x >= xx[ig] && x < xx[ig + 1])
2132 return ig;
2133
2134 if (xx[i] < xx[i + 1])
2135 while (ihi > ilo + 1) {
2136 i = (ihi + ilo) >> 1;
2137 if (xx[i] > x)
2138 ihi = i;
2139 else
2140 ilo = i;
2141 } else
2142 while (ihi > ilo + 1) {
2143 i = (ihi + ilo) >> 1;
2144 if (xx[i] <= x)
2145 ihi = i;
2146 else
2147 ilo = i;
2148 }
2149
2150 return ilo;
2151}
2152
2153/*****************************************************************************/
2154
2156 const double *xx,
2157 const int n,
2158 const double x) {
2159
2160 /* Calculate index... */
2161 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2162
2163 /* Check range... */
2164 if (i < 0)
2165 return 0;
2166 else if (i > n - 2)
2167 return n - 2;
2168 else
2169 return i;
2170}
2171
2172/*****************************************************************************/
2173
2175 float profiles[EX][EY][EP],
2176 const int np,
2177 const int lon_ap_ind,
2178 const int lat_ap_ind,
2179 const double height_ap,
2180 int *ind) {
2181
2182 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2183 np, height_ap, 0);
2184 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2185 np, height_ap, ind[0]);
2186 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2187 np, height_ap, ind[1]);
2188 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2189 np, height_ap, ind[2]);
2190}
2191
2192/*****************************************************************************/
2193
2195 const ctl_t *ctl,
2196 const cache_t *cache,
2197 met_t *met0,
2198 met_t *met1,
2199 atm_t *atm) {
2200
2201 /* Set timer... */
2202 SELECT_TIMER("MODULE_ADVECT", "PHYSICS", NVTX_GPU);
2203
2204 /* Use omega vertical velocity... */
2205 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2206
2207 /* Loop over particles... */
2208 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2209
2210 /* Init... */
2212 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2213 x[3] = { 0, 0, 0 };
2214
2215 /* Loop over integration nodes... */
2216 for (int i = 0; i < ctl->advect; i++) {
2217
2218 /* Set position... */
2219 if (i == 0) {
2220 dts = 0.0;
2221 x[0] = atm->lon[ip];
2222 x[1] = atm->lat[ip];
2223 x[2] = atm->p[ip];
2224 } else {
2225 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2226 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2227 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2228 x[2] = atm->p[ip] + dts * w[i - 1];
2229 }
2230 const double tm = atm->time[ip] + dts;
2231
2232 /* Interpolate meteo data on pressure levels... */
2233 if (ctl->advect_vert_coord == 0) {
2234 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2235 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2236 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2237 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2238 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2239 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2240 }
2241
2242 /* Interpolate meteo data on model levels... */
2243 else {
2244 intpol_met_time_3d_ml(met0, met0->pl, met0->ul,
2245 met1, met1->pl, met1->ul,
2246 tm, x[2], x[0], x[1], &u[i]);
2247 intpol_met_time_3d_ml(met0, met0->pl, met0->vl,
2248 met1, met1->pl, met1->vl,
2249 tm, x[2], x[0], x[1], &v[i]);
2250 intpol_met_time_3d_ml(met0, met0->pl, met0->wl,
2251 met1, met1->pl, met1->wl,
2252 tm, x[2], x[0], x[1], &w[i]);
2253 }
2254
2255 /* Get mean wind... */
2256 double k = 1.0;
2257 if (ctl->advect == 2)
2258 k = (i == 0 ? 0.0 : 1.0);
2259 else if (ctl->advect == 4)
2260 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2261 um += k * u[i];
2262 vm += k * v[i];
2263 wm += k * w[i];
2264 }
2265
2266 /* Set new position... */
2267 atm->time[ip] += cache->dt[ip];
2268 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2269 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2270 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2271 atm->p[ip] += cache->dt[ip] * wm;
2272 }
2273 }
2274
2275 /* Use zetadot vertical velocity... */
2276 else if (ctl->advect_vert_coord == 1) {
2277
2278 /* Loop over particles... */
2279 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2280
2281 /* Convert pressure to zeta... */
2283 intpol_met_4d_coord(met0, met0->pl, met0->zetal, met1,
2284 met1->pl, met1->zetal, atm->time[ip], atm->p[ip],
2285 atm->lon[ip], atm->lat[ip],
2286 &atm->q[ctl->qnt_zeta][ip], ci, cw, 1);
2287
2288 /* Init... */
2289 double dts, u[4], um = 0, v[4], vm = 0, zeta_dot[4],
2290 zeta_dotm = 0, x[3] = { 0, 0, 0 };
2291
2292 /* Loop over integration nodes... */
2293 for (int i = 0; i < ctl->advect; i++) {
2294
2295 /* Set position... */
2296 if (i == 0) {
2297 dts = 0.0;
2298 x[0] = atm->lon[ip];
2299 x[1] = atm->lat[ip];
2300 x[2] = atm->q[ctl->qnt_zeta][ip];
2301 } else {
2302 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2303 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2304 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2305 x[2] = atm->q[ctl->qnt_zeta][ip] + dts * zeta_dot[i - 1];
2306 }
2307 const double tm = atm->time[ip] + dts;
2308
2309 /* Interpolate meteo data... */
2310 intpol_met_4d_coord(met0, met0->zetal, met0->ul, met1, met1->zetal,
2311 met1->ul, tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2312 intpol_met_4d_coord(met0, met0->zetal, met0->vl, met1, met1->zetal,
2313 met1->vl, tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2314 intpol_met_4d_coord(met0, met0->zetal, met0->zeta_dotl, met1,
2315 met1->zetal, met1->zeta_dotl, tm, x[2], x[0],
2316 x[1], &zeta_dot[i], ci, cw, 0);
2317
2318 /* Get mean wind... */
2319 double k = 1.0;
2320 if (ctl->advect == 2)
2321 k = (i == 0 ? 0.0 : 1.0);
2322 else if (ctl->advect == 4)
2323 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2324 um += k * u[i];
2325 vm += k * v[i];
2326 zeta_dotm += k * zeta_dot[i];
2327 }
2328
2329 /* Set new position... */
2330 atm->time[ip] += cache->dt[ip];
2331 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2332 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2333 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2334 atm->q[ctl->qnt_zeta][ip] += cache->dt[ip] * zeta_dotm;
2335
2336 /* Convert zeta to pressure... */
2337 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2338 met1->pl, atm->time[ip],
2339 atm->q[ctl->qnt_zeta][ip], atm->lon[ip],
2340 atm->lat[ip], &atm->p[ip], ci, cw, 1);
2341 }
2342 }
2343}
2344
2345/*****************************************************************************/
2346
2348 const ctl_t *ctl,
2349 const cache_t *cache,
2350 met_t *met0,
2351 met_t *met1,
2352 atm_t *atm) {
2353
2354 /* Check parameters... */
2355 if (ctl->advect_vert_coord != 1)
2356 return;
2357
2358 /* Set timer... */
2359 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS", NVTX_GPU);
2360
2361 /* Loop over particles... */
2362 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
2363
2364 /* Initialize pressure consistent with zeta... */
2366 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2367 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2368 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2369 }
2370}
2371
2372/*****************************************************************************/
2373
2375 const ctl_t *ctl,
2376 const cache_t *cache,
2377 const clim_t *clim,
2378 met_t *met0,
2379 met_t *met1,
2380 atm_t *atm) {
2381
2382 /* Set timer... */
2383 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS", NVTX_GPU);
2384
2385 /* Check quantity flags... */
2386 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2387 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2388 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2389 return;
2390
2391 /* Loop over particles... */
2392 PARTICLE_LOOP(0, atm->np, 1,
2393 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2394
2395 /* Check latitude and pressure range... */
2396 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2397 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2398 continue;
2399
2400 /* Check surface layer... */
2401 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2402 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2403
2404 /* Get surface pressure... */
2405 double ps;
2407 INTPOL_2D(ps, 1);
2408
2409 /* Check pressure... */
2410 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2411 continue;
2412
2413 /* Check height... */
2414 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2415 continue;
2416
2417 /* Check zeta range... */
2418 if (ctl->bound_zetas > 0) {
2419 double t;
2420 INTPOL_3D(t, 1);
2421 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2422 continue;
2423 }
2424
2425 /* Check planetary boundary layer... */
2426 if (ctl->bound_pbl) {
2427 double pbl;
2428 INTPOL_2D(pbl, 0);
2429 if (atm->p[ip] < pbl)
2430 continue;
2431 }
2432 }
2433
2434 /* Set mass and volume mixing ratio... */
2435 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2436 atm->q[ctl->qnt_m][ip] =
2437 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2438 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2439 atm->q[ctl->qnt_vmr][ip] =
2440 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2441
2442 /* Set CFC-10 volume mixing ratio... */
2443 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2444 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2445
2446 /* Set CFC-11 volume mixing ratio... */
2447 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2448 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2449
2450 /* Set CFC-12 volume mixing ratio... */
2451 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2452 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2453
2454 /* Set N2O volume mixing ratio... */
2455 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2456 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2457
2458 /* Set SF6 volume mixing ratio... */
2459 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2460 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2461
2462 /* Set age of air... */
2463 if (ctl->qnt_aoa >= 0)
2464 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2465 }
2466}
2467
2468/*****************************************************************************/
2469
2471 const ctl_t *ctl,
2472 met_t *met0,
2473 met_t *met1,
2474 atm_t *atm,
2475 const double tt) {
2476
2477 /* Check quantities... */
2478 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
2479 return;
2480 if (ctl->molmass <= 0)
2481 ERRMSG("Molar mass is not defined!");
2482
2483 /* Set timer... */
2484 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS", NVTX_GPU);
2485
2486 /* Allocate... */
2487 const int ensemble_mode = (ctl->nens > 0);
2488 const int np = atm->np;
2489 const int nz = ctl->chemgrid_nz;
2490 const int nx = ctl->chemgrid_nx;
2491 const int ny = ctl->chemgrid_ny;
2492 const int ngrid = nx * ny * nz;
2493 const int nens = ensemble_mode ? ctl->nens : 1;
2494
2495 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2496 double *restrict const press =
2497 (double *) malloc((size_t) nz * sizeof(double));
2498 double *restrict const mass =
2499 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
2500 double *restrict const area =
2501 (double *) malloc((size_t) ny * sizeof(double));
2502 double *restrict const lon =
2503 (double *) malloc((size_t) nx * sizeof(double));
2504 double *restrict const lat =
2505 (double *) malloc((size_t) ny * sizeof(double));
2506
2507 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2508 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2509 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2510
2511 /* Set grid box size... */
2512 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2513 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2514 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2515
2516 /* Set vertical coordinates... */
2517#ifdef _OPENACC
2518#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np],z[0:nz],press[0:nz],mass[0:ngrid*nens],area[0:ny],lon[0:nx],lat[0:ny])
2519#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2520#pragma acc parallel loop independent gang vector
2521#else
2522#pragma omp parallel for default(shared)
2523#endif
2524 for (int iz = 0; iz < nz; iz++) {
2525 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2526 press[iz] = P(z[iz]);
2527 }
2528
2529 /* Set time interval for output... */
2530 const double t0 = tt - 0.5 * ctl->dt_mod;
2531 const double t1 = tt + 0.5 * ctl->dt_mod;
2532
2533 /* Get indices... */
2534#ifdef _OPENACC
2535#pragma acc parallel loop independent gang vector
2536#else
2537#pragma omp parallel for default(shared)
2538#endif
2539 for (int ip = 0; ip < np; ip++) {
2540 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2541 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2542 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2543 if (atm->time[ip] < t0 || atm->time[ip] > t1
2544 || ixs[ip] < 0 || ixs[ip] >= nx
2545 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2546 izs[ip] = -1;
2547 }
2548
2549 /* Set horizontal coordinates... */
2550#ifdef _OPENACC
2551#pragma acc parallel loop independent gang vector
2552#else
2553#pragma omp parallel for default(shared)
2554#endif
2555 for (int ix = 0; ix < nx; ix++)
2556 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
2557
2558#ifdef _OPENACC
2559#pragma acc parallel loop independent gang vector
2560#else
2561#pragma omp parallel for default(shared)
2562#endif
2563 for (int iy = 0; iy < ny; iy++) {
2564 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
2565 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
2566 }
2567
2568 /* Get mass per grid box... */
2569#ifdef _OPENACC
2570#pragma acc parallel loop independent gang vector
2571#endif
2572 for (int ip = 0; ip < np; ip++) {
2573 if (izs[ip] >= 0) {
2574 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
2575 if (ensemble_mode) {
2576 const int ens = (int) atm->q[ctl->qnt_ens][ip];
2577 mass_idx += ens * ngrid;
2578 }
2579#ifdef _OPENACC
2580#pragma acc atomic update
2581#endif
2582 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
2583 }
2584 }
2585
2586 /* Assign grid data to air parcels ... */
2587#ifdef _OPENACC
2588#pragma acc parallel loop independent gang vector
2589#else
2590#pragma omp parallel for default(shared)
2591#endif
2592 for (int ip = 0; ip < np; ip++)
2593 if (izs[ip] >= 0) {
2594
2595 /* Interpolate temperature... */
2596 double temp;
2598 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
2599 press[izs[ip]],
2600 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
2601
2602 /* Set mass... */
2603 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
2604 if (ensemble_mode) {
2605 const int ens = (int) atm->q[ctl->qnt_ens][ip];
2606 mass_idx += ens * ngrid;
2607 }
2608
2609 /* Calculate volume mixing ratio... */
2610 const double m = mass[mass_idx];
2611 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
2612 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
2613 }
2614
2615 /* Free... */
2616#ifdef _OPENACC
2617#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
2618#endif
2619 free(mass);
2620 free(lon);
2621 free(lat);
2622 free(area);
2623 free(z);
2624 free(press);
2625 free(ixs);
2626 free(iys);
2627 free(izs);
2628}
2629
2630/*****************************************************************************/
2631
2633 const ctl_t *ctl,
2634 const cache_t *cache,
2635 const clim_t *clim,
2636 met_t *met0,
2637 met_t *met1,
2638 atm_t *atm) {
2639
2640 /* Set timer... */
2641 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS", NVTX_GPU);
2642
2643 /* Loop over particles... */
2644 PARTICLE_LOOP(0, atm->np, 0,
2645 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2646
2647 /* Set H2O and O3 using meteo data... */
2649 if (ctl->qnt_Ch2o >= 0) {
2650 double h2o;
2651 INTPOL_3D(h2o, 1);
2652 SET_ATM(qnt_Ch2o, h2o);
2653 }
2654 if (ctl->qnt_Co3 >= 0) {
2655 double o3;
2656 INTPOL_3D(o3, 1);
2657 SET_ATM(qnt_Co3, o3);
2658 }
2659
2660 /* Set radical species... */
2661 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
2662 atm->lon[ip], atm->lat[ip], atm->p[ip]));
2663 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
2664 atm->lat[ip], atm->p[ip]));
2665 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
2666 atm->lat[ip], atm->p[ip]));
2667 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
2668 atm->lat[ip], atm->p[ip]));
2669 }
2670}
2671
2672/*****************************************************************************/
2673
2675 const ctl_t *ctl,
2676 cache_t *cache,
2677 met_t *met0,
2678 met_t *met1,
2679 atm_t *atm) {
2680
2681 /* Set timer... */
2682 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
2683
2684 /* Create random numbers... */
2685 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
2686
2687 /* Loop over particles... */
2688 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2689
2690 /* Interpolate CAPE... */
2691 double ps;
2693 INTPOL_2D(ps, 1);
2694
2695 /* Initialize pressure range for vertical mixing... */
2696 double pbot = ps, ptop = ps;
2697
2698 /* Mixing in the PBL... */
2699 if (ctl->conv_mix_pbl) {
2700
2701 /* Interpolate PBL... */
2702 double pbl;
2703 INTPOL_2D(pbl, 0);
2704
2705 /* Set pressure range... */
2706 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
2707 }
2708
2709 /* Convective mixing... */
2710 if (ctl->conv_cape >= 0) {
2711
2712 /* Interpolate CAPE, CIN, and equilibrium level... */
2713 double cape, cin, pel;
2714 INTPOL_2D(cape, 0);
2715 INTPOL_2D(cin, 0);
2716 INTPOL_2D(pel, 0);
2717
2718 /* Set pressure range... */
2719 if (isfinite(cape) && cape >= ctl->conv_cape
2720 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
2721 ptop = GSL_MIN(ptop, pel);
2722 }
2723
2724 /* Apply vertical mixing... */
2725 if (ptop != pbot && atm->p[ip] >= ptop) {
2726
2727 /* Get density range... */
2728 double tbot, ttop;
2729 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2730 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
2731 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
2732 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
2733 const double rhobot = pbot / tbot;
2734 const double rhotop = ptop / ttop;
2735
2736 /* Get new density... */
2737 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
2738
2739 /* Get pressure... */
2740 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
2741 }
2742 }
2743}
2744
2745/*****************************************************************************/
2746
2748 const ctl_t *ctl,
2749 const cache_t *cache,
2750 const clim_t *clim,
2751 atm_t *atm) {
2752
2753 /* Set timer... */
2754 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
2755
2756 /* Check quantity flags... */
2757 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2758 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2759
2760 /* Loop over particles... */
2761 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
2762
2763 /* Get weighting factor... */
2764 const double w = tropo_weight(clim, atm, ip);
2765
2766 /* Set lifetime... */
2767 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
2768
2769 /* Calculate exponential decay... */
2770 const double aux = exp(-cache->dt[ip] / tdec);
2771 if (ctl->qnt_m >= 0) {
2772 if (ctl->qnt_mloss_decay >= 0)
2773 atm->q[ctl->qnt_mloss_decay][ip]
2774 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2775 atm->q[ctl->qnt_m][ip] *= aux;
2776 if (ctl->qnt_loss_rate >= 0)
2777 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
2778 }
2779 if (ctl->qnt_vmr >= 0)
2780 atm->q[ctl->qnt_vmr][ip] *= aux;
2781 }
2782}
2783
2784/*****************************************************************************/
2785
2787 const ctl_t *ctl,
2788 cache_t *cache,
2789 met_t *met0,
2790 met_t *met1,
2791 atm_t *atm) {
2792
2793 /* Set timer... */
2794 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS", NVTX_GPU);
2795
2796 /* Create random numbers... */
2797 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2798
2799 /* Loop over particles... */
2800 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2801
2802 /* Get indices... */
2803 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
2804 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
2805 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
2806
2807 /* Get standard deviations of local wind data... */
2808 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
2809 for (int i = 0; i < 2; i++)
2810 for (int j = 0; j < 2; j++)
2811 for (int k = 0; k < 2; k++) {
2812 umean += met0->u[ix + i][iy + j][iz + k];
2813 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
2814 vmean += met0->v[ix + i][iy + j][iz + k];
2815 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
2816 wmean += met0->w[ix + i][iy + j][iz + k];
2817 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
2818
2819 umean += met1->u[ix + i][iy + j][iz + k];
2820 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
2821 vmean += met1->v[ix + i][iy + j][iz + k];
2822 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
2823 wmean += met1->w[ix + i][iy + j][iz + k];
2824 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
2825 }
2826 usig = usig / 16.f - SQR(umean / 16.f);
2827 usig = (usig > 0 ? sqrtf(usig) : 0);
2828 vsig = vsig / 16.f - SQR(vmean / 16.f);
2829 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
2830 wsig = wsig / 16.f - SQR(wmean / 16.f);
2831 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
2832
2833 /* Set temporal correlations for mesoscale fluctuations... */
2834 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
2835 const double r2 = sqrt(1 - r * r);
2836
2837 /* Calculate horizontal mesoscale wind fluctuations... */
2838 if (ctl->turb_mesox > 0) {
2839 cache->uvwp[ip][0] =
2840 (float) (r * cache->uvwp[ip][0] +
2841 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
2842 atm->lon[ip] +=
2843 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2844
2845 cache->uvwp[ip][1] =
2846 (float) (r * cache->uvwp[ip][1] +
2847 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
2848 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2849 }
2850
2851 /* Calculate vertical mesoscale wind fluctuations... */
2852 if (ctl->turb_mesoz > 0) {
2853 cache->uvwp[ip][2] =
2854 (float) (r * cache->uvwp[ip][2] +
2855 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
2856 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
2857 }
2858 }
2859}
2860
2861/*****************************************************************************/
2862
2864 const ctl_t *ctl,
2865 cache_t *cache,
2866 met_t *met0,
2867 met_t *met1,
2868 atm_t *atm) {
2869
2870 /* Set timer... */
2871 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS", NVTX_GPU);
2872
2873 /* Create random numbers... */
2874 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2875
2876 /* Loop over particles... */
2877 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2878
2879 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
2880 tau_u = 300., tau_w = 100.;
2881
2882 /* Get surface and PBL pressure... */
2883 double pbl, ps;
2885 INTPOL_2D(ps, 1);
2886 INTPOL_2D(pbl, 0);
2887
2888 /* Boundary layer... */
2889 if (atm->p[ip] >= pbl) {
2890
2891 /* Calculate heights... */
2892 const double p = MIN(atm->p[ip], ps);
2893 const double zs = Z(ps);
2894 const double z = 1e3 * (Z(p) - zs);
2895 const double zi = 1e3 * (Z(pbl) - zs);
2896 const double zratio = z / zi;
2897
2898 /* Calculate friction velocity... */
2899 double ess, nss, h2o, t;
2900 INTPOL_2D(ess, 0);
2901 INTPOL_2D(nss, 0);
2902 INTPOL_3D(t, 1);
2903 INTPOL_3D(h2o, 0);
2904 const double rho = RHO(p, TVIRT(t, h2o));
2905 const double tau = sqrt(SQR(ess) + SQR(nss));
2906 const double ustar = sqrt(tau / rho);
2907
2908 /* Get surface sensible heat flux... */
2909 double shf;
2910 INTPOL_2D(shf, 1);
2911
2912 /* Stable or neutral conditions... */
2913 if (shf <= 0) {
2914
2915 /* Calcalute turbulent velocity variances... */
2916 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
2917 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
2918
2919 /* Calculate derivative dsig_w/dz... */
2920 dsigw_dz = -1.3 * ustar / zi;
2921
2922 /* Calcalute Lagrangian timescales... */
2923 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
2924 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
2925 }
2926
2927 /* Unstable conditions... */
2928 else {
2929
2930 /* Convective velocity... */
2931 const double wstar =
2932 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
2933
2934 /* Calcalute turbulent velocity variances... */
2935 sig_u = 1e-2
2936 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
2937 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
2938 * pow(zratio, 2.0 / 3.0)
2939 + (1.8 - 1.4 * zratio) * SQR(ustar));
2940
2941 /* Calculate derivative dsig_w/dz... */
2942 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
2943 * (0.8 *
2944 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
2945 - 1.8 * pow(zratio, 2.0 / 3.0)));
2946
2947 /* Calcalute Lagrangian timescales... */
2948 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
2949 const double eps =
2950 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
2951 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
2952 tau_u = 2 * SQR(sig_u) / (C0 * eps);
2953 tau_w = 2 * SQR(sig_w) / (C0 * eps);
2954 }
2955 }
2956
2957 /* Set minimum values... */
2958 sig_u = MAX(sig_u, 0.25);
2959 sig_w = MAX(sig_w, 0.1);
2960 tau_u = MAX(tau_u, 300.);
2961 tau_w = MAX(tau_w, 100.);
2962
2963 /* Update perturbations... */
2964 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
2965 const double ru2 = sqrt(1.0 - SQR(ru));
2966 cache->uvwp[ip][0]
2967 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
2968 cache->uvwp[ip][1]
2969 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
2970
2971 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
2972 const double rw2 = sqrt(1.0 - SQR(rw));
2973 cache->uvwp[ip][2]
2974 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
2975 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
2976
2977 /* Calculate new air parcel position... */
2978 atm->lon[ip] +=
2979 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2980 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2981 atm->p[ip] +=
2982 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
2983 }
2984}
2985
2986/*****************************************************************************/
2987
2989 const ctl_t *ctl,
2990 cache_t *cache,
2991 const clim_t *clim,
2992 met_t *met0,
2993 met_t *met1,
2994 atm_t *atm) {
2995
2996 /* Set timer... */
2997 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS", NVTX_GPU);
2998
2999 /* Create random numbers... */
3000 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3001
3002 /* Loop over particles... */
3003 PARTICLE_LOOP(0, atm->np, 1,
3004 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3005
3006 /* Get PBL and surface pressure... */
3007 double pbl, ps;
3009 INTPOL_2D(pbl, 1);
3010 INTPOL_2D(ps, 0);
3011
3012 /* Get weighting factors... */
3013 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
3014 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
3015 const double wstrat = 1.0 - wpbl - wtrop;
3016
3017 /* Set diffusivity... */
3018 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
3019 + wstrat * ctl->turb_dx_strat;
3020 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
3021 + wstrat * ctl->turb_dz_strat;
3022
3023 /* Horizontal turbulent diffusion... */
3024 if (dx > 0) {
3025 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
3026 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
3027 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
3028 }
3029
3030 /* Vertical turbulent diffusion... */
3031 if (dz > 0) {
3032 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
3033 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
3034 }
3035 }
3036}
3037
3038/*****************************************************************************/
3039
3041 const ctl_t *ctl,
3042 const cache_t *cache,
3043 met_t *met0,
3044 met_t *met1,
3045 atm_t *atm) {
3046
3047 /* Set timer... */
3048 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS", NVTX_GPU);
3049
3050 /* Check quantity flags... */
3051 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3052 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3053
3054 /* Loop over particles... */
3055 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3056
3057 /* Get surface pressure... */
3058 double ps;
3060 INTPOL_2D(ps, 1);
3061
3062 /* Check whether particle is above the surface layer... */
3063 if (atm->p[ip] < ps - ctl->dry_depo_dp)
3064 continue;
3065
3066 /* Set depth of surface layer... */
3067 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
3068
3069 /* Calculate sedimentation velocity for particles... */
3070 double v_dep;
3071 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
3072
3073 /* Get temperature... */
3074 double t;
3075 INTPOL_3D(t, 1);
3076
3077 /* Set deposition velocity... */
3078 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3079 atm->q[ctl->qnt_rhop][ip]);
3080 }
3081
3082 /* Use explicit sedimentation velocity for gases... */
3083 else
3084 v_dep = ctl->dry_depo_vdep;
3085
3086 /* Calculate loss of mass based on deposition velocity... */
3087 const double aux = exp(-cache->dt[ip] * v_dep / dz);
3088 if (ctl->qnt_m >= 0) {
3089 if (ctl->qnt_mloss_dry >= 0)
3090 atm->q[ctl->qnt_mloss_dry][ip]
3091 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3092 atm->q[ctl->qnt_m][ip] *= aux;
3093 if (ctl->qnt_loss_rate >= 0)
3094 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
3095 }
3096 if (ctl->qnt_vmr >= 0)
3097 atm->q[ctl->qnt_vmr][ip] *= aux;
3098 }
3099}
3100
3101/*****************************************************************************/
3102
3104 const ctl_t *ctl,
3105 const cache_t *cache,
3106 const clim_t *clim,
3107 met_t *met0,
3108 met_t *met1,
3109 atm_t *atm) {
3110
3111 /* Set timer... */
3112 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS", NVTX_GPU);
3113
3114 /* Check quantity flags... */
3115 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3116 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3117
3118 /* Parameter of SO2 correction... */
3119 const double a = 3.12541941e-06;
3120 const double b = -5.72532259e-01;
3121 const double low = pow(1. / a, 1. / b);
3122
3123 /* Loop over particles... */
3124 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3125
3126 /* Check whether particle is inside cloud... */
3127 double lwc, rwc;
3129 INTPOL_3D(lwc, 1);
3130 INTPOL_3D(rwc, 0);
3131 if (!(lwc > 0 || rwc > 0))
3132 continue;
3133
3134 /* Get temperature... */
3135 double t;
3136 INTPOL_3D(t, 0);
3137
3138 /* Get molecular density... */
3139 const double M = MOLEC_DENS(atm->p[ip], t);
3140
3141 /* Reaction rate (Berglen et al., 2004)... */
3142 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3143
3144 /* Henry constant of SO2... */
3145 const double H_SO2 =
3146 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3147 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3148
3149 /* Henry constant of H2O2... */
3150 const double H_h2o2 =
3151 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3152
3153 /* Correction factor for high SO2 concentration
3154 (if qnt_Cx is defined, the correction is switched on)... */
3155 double cor = 1.0;
3156 if (ctl->qnt_Cx >= 0)
3157 cor = atm->q[ctl->qnt_Cx][ip] >
3158 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3159
3160 const double h2o2 = H_h2o2
3161 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3162 * M * cor * 1000. / AVO; /* unit: mol/L */
3163
3164 /* Volume water content in cloud [m^3 m^(-3)]... */
3165 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3166 const double CWC = (lwc + rwc) * rho_air / 1e3;
3167
3168 /* Calculate exponential decay (Rolph et al., 1992)... */
3169 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3170 const double aux = exp(-cache->dt[ip] * rate_coef);
3171 if (ctl->qnt_m >= 0) {
3172 if (ctl->qnt_mloss_h2o2 >= 0)
3173 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3174 atm->q[ctl->qnt_m][ip] *= aux;
3175 if (ctl->qnt_loss_rate >= 0)
3176 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3177 }
3178 if (ctl->qnt_vmr >= 0)
3179 atm->q[ctl->qnt_vmr][ip] *= aux;
3180 }
3181}
3182
3183/*****************************************************************************/
3184
3186 const ctl_t *ctl,
3187 cache_t *cache,
3188 met_t *met0,
3189 met_t *met1,
3190 atm_t *atm) {
3191
3192 double t;
3193
3194 /* Set timer... */
3195 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS", NVTX_GPU);
3196
3197 /* Save pressure... */
3198 if (ctl->isosurf == 1) {
3199 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
3200 cache->iso_var[ip] = atm->p[ip];
3201 }
3202 }
3203
3204 /* Save density... */
3205 else if (ctl->isosurf == 2) {
3206 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3208 INTPOL_3D(t, 1);
3209 cache->iso_var[ip] = atm->p[ip] / t;
3210 }
3211 }
3212
3213 /* Save potential temperature... */
3214 else if (ctl->isosurf == 3) {
3215 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3217 INTPOL_3D(t, 1);
3218 cache->iso_var[ip] = THETA(atm->p[ip], t);
3219 }
3220 }
3221
3222 /* Read balloon pressure data... */
3223 else if (ctl->isosurf == 4) {
3224
3225 /* Write info... */
3226 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3227
3228 /* Open file... */
3229 FILE *in;
3230 if (!(in = fopen(ctl->balloon, "r")))
3231 ERRMSG("Cannot open file!");
3232
3233 /* Read pressure time series... */
3234 char line[LEN];
3235 while (fgets(line, LEN, in))
3236 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3237 &(cache->iso_ps[cache->iso_n])) == 2)
3238 if ((++cache->iso_n) > NP)
3239 ERRMSG("Too many data points!");
3240
3241 /* Check number of points... */
3242 if (cache->iso_n < 1)
3243 ERRMSG("Could not read any data!");
3244
3245 /* Close file... */
3246 fclose(in);
3247
3248 /* Update of cache data on device... */
3249 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
3250 }
3251}
3252
3253/*****************************************************************************/
3254
3256 const ctl_t *ctl,
3257 const cache_t *cache,
3258 met_t *met0,
3259 met_t *met1,
3260 atm_t *atm) {
3261
3262 /* Set timer... */
3263 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3264
3265 /* Loop over particles... */
3266 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
3267
3268 /* Init... */
3269 double t;
3271
3272 /* Restore pressure... */
3273 if (ctl->isosurf == 1)
3274 atm->p[ip] = cache->iso_var[ip];
3275
3276 /* Restore density... */
3277 else if (ctl->isosurf == 2) {
3278 INTPOL_3D(t, 1);
3279 atm->p[ip] = cache->iso_var[ip] * t;
3280 }
3281
3282 /* Restore potential temperature... */
3283 else if (ctl->isosurf == 3) {
3284 INTPOL_3D(t, 1);
3285 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3286 }
3287
3288 /* Interpolate pressure... */
3289 else if (ctl->isosurf == 4) {
3290 if (atm->time[ip] <= cache->iso_ts[0])
3291 atm->p[ip] = cache->iso_ps[0];
3292 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3293 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3294 else {
3295 const int idx =
3296 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3297 atm->p[ip] =
3298 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
3299 cache->iso_ps[idx + 1], atm->time[ip]);
3300 }
3301 }
3302 }
3303}
3304
3305/*****************************************************************************/
3306
3307#ifdef KPP
3308void module_kpp_chem(
3309 ctl_t *ctl,
3310 cache_t *cache,
3311 clim_t *clim,
3312 met_t *met0,
3313 met_t *met1,
3314 atm_t *atm) {
3315
3316 /* Set timer... */
3317 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS", NVTX_GPU);
3318
3319 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
3320 double rtol[1] = { 1.0e-3 };
3321 double atol[1] = { 1.0 };
3322
3323 /* Loop over particles... */
3324#ifdef _OPENACC
3325#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
3326#endif
3327 PARTICLE_LOOP(0, atm->np, 1,
3328 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
3329
3330 /* Initialize... */
3331 double var[nvar], fix[nfix], rconst[nreact];
3332 for (int i = 0; i < nvar; i++)
3333 var[i] = 0.0;
3334 for (int i = 0; i < nfix; i++)
3335 fix[i] = 0.0;
3336 for (int i = 0; i < nreact; i++)
3337 rconst[i] = 0.0;
3338 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
3339
3340 /* Integrate... */
3341 double rpar[20];
3342 int ipar[20];
3343 for (int i = 0; i < 20; i++) {
3344 ipar[i] = 0;
3345 rpar[i] = 0.0;
3346 }
3347 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) */
3348 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
3349 ipar[3] = 4; /* choice of the method:Rodas3 */
3350 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
3351 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
3352
3353 /* Save results.. */
3354 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
3355 }
3356}
3357#endif
3358
3359/*****************************************************************************/
3360
3362 const ctl_t *ctl,
3363 const cache_t *cache,
3364 const clim_t *clim,
3365 met_t *met0,
3366 met_t *met1,
3367 atm_t *atm) {
3368
3369 /* Set timer... */
3370 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
3371
3372 /* Check quantity flags... */
3373 if (ctl->qnt_tsts >= 0)
3374 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3375 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3376
3377 /* Loop over particles... */
3378 PARTICLE_LOOP(0, atm->np, 0,
3379 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3380
3381 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
3382 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
3383 o3, lwc, rwc, iwc, swc, cc, z, zt;
3384
3385 /* Interpolate meteo data... */
3387 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3388
3389 /* Set quantities... */
3390 SET_ATM(qnt_ps, ps);
3391 SET_ATM(qnt_ts, ts);
3392 SET_ATM(qnt_zs, zs);
3393 SET_ATM(qnt_us, us);
3394 SET_ATM(qnt_vs, vs);
3395 SET_ATM(qnt_ess, ess);
3396 SET_ATM(qnt_nss, nss);
3397 SET_ATM(qnt_shf, shf);
3398 SET_ATM(qnt_lsm, lsm);
3399 SET_ATM(qnt_sst, sst);
3400 SET_ATM(qnt_pbl, pbl);
3401 SET_ATM(qnt_pt, pt);
3402 SET_ATM(qnt_tt, tt);
3403 SET_ATM(qnt_zt, zt);
3404 SET_ATM(qnt_h2ot, h2ot);
3405 SET_ATM(qnt_zg, z);
3406 SET_ATM(qnt_p, atm->p[ip]);
3407 SET_ATM(qnt_t, t);
3408 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3409 SET_ATM(qnt_u, u);
3410 SET_ATM(qnt_v, v);
3411 SET_ATM(qnt_w, w);
3412 SET_ATM(qnt_h2o, h2o);
3413 SET_ATM(qnt_o3, o3);
3414 SET_ATM(qnt_lwc, lwc);
3415 SET_ATM(qnt_rwc, rwc);
3416 SET_ATM(qnt_iwc, iwc);
3417 SET_ATM(qnt_swc, swc);
3418 SET_ATM(qnt_cc, cc);
3419 SET_ATM(qnt_pct, pct);
3420 SET_ATM(qnt_pcb, pcb);
3421 SET_ATM(qnt_cl, cl);
3422 SET_ATM(qnt_plcl, plcl);
3423 SET_ATM(qnt_plfc, plfc);
3424 SET_ATM(qnt_pel, pel);
3425 SET_ATM(qnt_cape, cape);
3426 SET_ATM(qnt_cin, cin);
3427 SET_ATM(qnt_o3c, o3c);
3428 SET_ATM(qnt_hno3,
3429 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3430 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3431 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3432 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3433 atm->lat[ip], atm->p[ip]));
3434 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3435 atm->lat[ip], atm->p[ip]));
3436 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3437 atm->lat[ip], atm->p[ip]));
3438 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3439 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3440 SET_ATM(qnt_psat, PSAT(t));
3441 SET_ATM(qnt_psice, PSICE(t));
3442 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3443 SET_ATM(qnt_sh, SH(h2o));
3444 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3445 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3446 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3447 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3448 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3449 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
3450 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3451 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3452 SET_ATM(qnt_pv, pv);
3453 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3454 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3455 SET_ATM(qnt_tnat,
3456 nat_temperature(atm->p[ip], h2o,
3457 clim_zm(&clim->hno3, atm->time[ip],
3458 atm->lat[ip], atm->p[ip])));
3459 SET_ATM(qnt_tsts,
3460 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3461 }
3462}
3463
3464/*****************************************************************************/
3465
3467 const ctl_t *ctl,
3468 const clim_t *clim,
3469 atm_t *atm,
3470 const double t) {
3471
3472 /* Set timer... */
3473 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
3474
3475 /* Allocate... */
3476 const int np = atm->np;
3477 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3478 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3479 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3480
3481 /* Set grid box size... */
3482 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3483 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3484 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3485
3486 /* Set time interval... */
3487 const double t0 = t - 0.5 * ctl->dt_mod;
3488 const double t1 = t + 0.5 * ctl->dt_mod;
3489
3490 /* Get indices... */
3491#ifdef _OPENACC
3492#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3493#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3494#pragma acc parallel loop independent gang vector
3495#else
3496#pragma omp parallel for default(shared)
3497#endif
3498 for (int ip = 0; ip < np; ip++) {
3499 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3500 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3501 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3502 if (atm->time[ip] < t0 || atm->time[ip] > t1
3503 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3504 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3505 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3506 izs[ip] = -1;
3507 }
3508
3509 /* Calculate interparcel mixing... */
3510 const int use_ensemble = (ctl->nens > 0);
3511
3512 const int quantities[] = {
3513 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
3514 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
3515 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
3516 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
3517 ctl->qnt_Csf6, ctl->qnt_aoa
3518 };
3519 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
3520
3521 for (int i = 0; i < n_qnt; i++)
3522 if (quantities[i] >= 0)
3523 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
3524 use_ensemble);
3525
3526 /* Free... */
3527#ifdef _OPENACC
3528#pragma acc exit data delete(ixs,iys,izs)
3529#endif
3530 free(ixs);
3531 free(iys);
3532 free(izs);
3533}
3534
3535/*****************************************************************************/
3536
3538 const ctl_t *ctl,
3539 const clim_t *clim,
3540 atm_t *atm,
3541 const int *ixs,
3542 const int *iys,
3543 const int *izs,
3544 const int qnt_idx,
3545 const int use_ensemble) {
3546
3547 const int np = atm->np;
3548 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
3549 const int nens = use_ensemble ? ctl->nens : 1;
3550 const int total_grid = ngrid * nens;
3551
3552 double *restrict const cmean =
3553 (double *) malloc((size_t) total_grid * sizeof(double));
3554 int *restrict const count =
3555 (int *) malloc((size_t) total_grid * sizeof(int));
3556
3557 /* Init... */
3558#ifdef _OPENACC
3559#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
3560#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
3561#pragma acc parallel loop independent gang vector
3562#else
3563#ifdef __NVCOMPILER
3564#pragma novector
3565#endif
3566#pragma omp parallel for
3567#endif
3568 for (int i = 0; i < total_grid; i++) {
3569 count[i] = 0;
3570 cmean[i] = 0.0;
3571 }
3572
3573 /* Loop over particles... */
3574#ifdef _OPENACC
3575#pragma acc parallel loop independent gang vector
3576#endif
3577 for (int ip = 0; ip < np; ip++)
3578 if (izs[ip] >= 0) {
3579 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
3580 const int idx =
3581 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
3582 ctl->mixing_nz);
3583#ifdef _OPENACC
3584#pragma acc atomic update
3585#endif
3586 cmean[idx] += atm->q[qnt_idx][ip];
3587#ifdef _OPENACC
3588#pragma acc atomic update
3589#endif
3590 count[idx]++;
3591 }
3592
3593 /* Compute means... */
3594#ifdef _OPENACC
3595#pragma acc parallel loop independent gang vector
3596#else
3597#ifdef __NVCOMPILER
3598#pragma novector
3599#endif
3600#pragma omp parallel for
3601#endif
3602 for (int i = 0; i < total_grid; i++)
3603 if (count[i] > 0)
3604 cmean[i] /= count[i];
3605
3606 /* Interparcel mixing... */
3607#ifdef _OPENACC
3608#pragma acc parallel loop independent gang vector
3609#else
3610#pragma omp parallel for
3611#endif
3612 for (int ip = 0; ip < np; ip++) {
3613 if (izs[ip] >= 0) {
3614 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
3615
3616 double mixparam = 1.0;
3617 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
3618 const double w = tropo_weight(clim, atm, ip);
3619 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
3620 }
3621
3622 const int idx =
3623 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
3624 ctl->mixing_nz);
3625 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
3626 }
3627 }
3628
3629 /* Free... */
3630#ifdef _OPENACC
3631#pragma acc exit data delete(cmean,count)
3632#endif
3633 free(cmean);
3634 free(count);
3635}
3636
3637/*****************************************************************************/
3638
3640 const ctl_t *ctl,
3641 const cache_t *cache,
3642 const clim_t *clim,
3643 met_t *met0,
3644 met_t *met1,
3645 atm_t *atm) {
3646
3647 /* Set timer... */
3648 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS", NVTX_GPU);
3649
3650 /* Check quantity flags... */
3651 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3652 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3653
3654 /* Parameter of SO2 correction... */
3655 const double a = 4.71572206e-08;
3656 const double b = -8.28782867e-01;
3657 const double low = pow(1. / a, 1. / b);
3658
3659 /* Loop over particles... */
3660 PARTICLE_LOOP(0, atm->np, 1,
3661 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3662
3663 /* Get temperature... */
3664 double t;
3666 INTPOL_3D(t, 1);
3667
3668 /* Calculate molecular density... */
3669 const double M = MOLEC_DENS(atm->p[ip], t);
3670
3671 /* Use constant reaction rate... */
3672 double k = NAN;
3673 if (ctl->oh_chem_reaction == 1)
3674 k = ctl->oh_chem[0];
3675
3676 /* Calculate bimolecular reaction rate... */
3677 else if (ctl->oh_chem_reaction == 2)
3678 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
3679
3680 /* Calculate termolecular reaction rate... */
3681 if (ctl->oh_chem_reaction == 3) {
3682
3683 /* Calculate rate coefficient for X + OH + M -> XOH + M
3684 (JPL Publication 19-05) ... */
3685 const double k0 =
3686 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
3687 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
3688 const double ki =
3689 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
3690 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
3691 const double c = log10(k0 * M / ki);
3692 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
3693 }
3694
3695 /* Correction factor for high SO2 concentration
3696 (if qnt_Cx is defined, the correction is switched on)... */
3697 double cor = 1;
3698 if (ctl->qnt_Cx >= 0)
3699 cor =
3700 atm->q[ctl->qnt_Cx][ip] >
3701 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3702
3703 /* Calculate exponential decay... */
3704 const double rate_coef =
3705 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
3706 atm->lat[ip], atm->p[ip]) * M * cor;
3707 const double aux = exp(-cache->dt[ip] * rate_coef);
3708 if (ctl->qnt_m >= 0) {
3709 if (ctl->qnt_mloss_oh >= 0)
3710 atm->q[ctl->qnt_mloss_oh][ip]
3711 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3712 atm->q[ctl->qnt_m][ip] *= aux;
3713 if (ctl->qnt_loss_rate >= 0)
3714 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3715 }
3716 if (ctl->qnt_vmr >= 0)
3717 atm->q[ctl->qnt_vmr][ip] *= aux;
3718 }
3719}
3720
3721/*****************************************************************************/
3722
3724 const cache_t *cache,
3725 met_t *met0,
3726 met_t *met1,
3727 atm_t *atm) {
3728
3729 /* Set timer... */
3730 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
3731
3732 /* Loop over particles... */
3733 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
3734
3735 /* Init... */
3736 double ps;
3738
3739 /* Calculate modulo... */
3740 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
3741 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
3742
3743 /* Check latitude... */
3744 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
3745 if (atm->lat[ip] > 90) {
3746 atm->lat[ip] = 180 - atm->lat[ip];
3747 atm->lon[ip] += 180;
3748 }
3749 if (atm->lat[ip] < -90) {
3750 atm->lat[ip] = -180 - atm->lat[ip];
3751 atm->lon[ip] += 180;
3752 }
3753 }
3754
3755 /* Check longitude... */
3756 while (atm->lon[ip] < -180)
3757 atm->lon[ip] += 360;
3758 while (atm->lon[ip] >= 180)
3759 atm->lon[ip] -= 360;
3760
3761 /* Check pressure... */
3762 if (atm->p[ip] < met0->p[met0->np - 1]) {
3763 atm->p[ip] = met0->p[met0->np - 1];
3764 } else if (atm->p[ip] > 300.) {
3765 INTPOL_2D(ps, 1);
3766 if (atm->p[ip] > ps)
3767 atm->p[ip] = ps;
3768 }
3769 }
3770}
3771
3772/*****************************************************************************/
3773
3775 const int ntask) {
3776
3777 /* Initialize GSL random number generators... */
3778 gsl_rng_env_setup();
3779 if (omp_get_max_threads() > NTHREADS)
3780 ERRMSG("Too many threads!");
3781 for (int i = 0; i < NTHREADS; i++) {
3782 rng[i] = gsl_rng_alloc(gsl_rng_default);
3783 gsl_rng_set(rng[i], gsl_rng_default_seed
3784 + (long unsigned) (ntask * NTHREADS + i));
3785 }
3786
3787 /* Initialize cuRAND random number generators... */
3788#ifdef CURAND
3789 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
3790 CURAND_STATUS_SUCCESS)
3791 ERRMSG("Cannot create random number generator!");
3792 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
3793 CURAND_STATUS_SUCCESS)
3794 ERRMSG("Cannot set seed for random number generator!");
3795 if (curandSetStream
3796 (rng_curand,
3797 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
3798 CURAND_STATUS_SUCCESS)
3799 ERRMSG("Cannot set stream for random number generator!");
3800#endif
3801}
3802
3803/*****************************************************************************/
3804
3806 const ctl_t *ctl,
3807 double *rs,
3808 const size_t n,
3809 const int method) {
3810
3811 /* Use GSL random number generators... */
3812 if (ctl->rng_type == 0) {
3813
3814 /* Uniform distribution... */
3815 if (method == 0) {
3816#pragma omp parallel for default(shared)
3817 for (size_t i = 0; i < n; ++i)
3818 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
3819 }
3820
3821 /* Normal distribution... */
3822 else if (method == 1) {
3823#pragma omp parallel for default(shared)
3824 for (size_t i = 0; i < n; ++i)
3825 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
3826 }
3827
3828 /* Update of random numbers on device... */
3829#ifdef _OPENACC
3830 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
3831#pragma acc update device(rs[:n])
3832#endif
3833 }
3834
3835 /* Use Squares random number generator (Widynski, 2022)... */
3836 else if (ctl->rng_type == 1) {
3837
3838 /* Set key (don't change this!)... */
3839 const uint64_t key = 0xc8e4fd154ce32f6d;
3840
3841 /* Uniform distribution... */
3842#ifdef _OPENACC
3843#pragma acc data present(rs)
3844#pragma acc parallel loop independent gang vector
3845#else
3846#pragma omp parallel for default(shared)
3847#endif
3848 for (size_t i = 0; i < n + 1; ++i) {
3849 uint64_t r, t, x, y, z;
3850 y = x = (rng_ctr + i) * key;
3851 z = y + key;
3852 x = x * x + y;
3853 x = (x >> 32) | (x << 32);
3854 x = x * x + z;
3855 x = (x >> 32) | (x << 32);
3856 x = x * x + y;
3857 x = (x >> 32) | (x << 32);
3858 t = x = x * x + z;
3859 x = (x >> 32) | (x << 32);
3860 r = t ^ ((x * x + y) >> 32);
3861 rs[i] = (double) r / (double) UINT64_MAX;
3862 }
3863 rng_ctr += n + 1;
3864
3865 /* Normal distribution... */
3866 if (method == 1) {
3867#ifdef _OPENACC
3868#pragma acc parallel loop independent gang vector
3869#else
3870#pragma omp parallel for default(shared)
3871#endif
3872 for (size_t i = 0; i < n; i += 2) {
3873 const double r = sqrt(-2.0 * log(rs[i]));
3874 const double phi = 2.0 * M_PI * rs[i + 1];
3875 rs[i] = r * cosf((float) phi);
3876 rs[i + 1] = r * sinf((float) phi);
3877 }
3878 }
3879 }
3880
3881 /* Use cuRAND random number generators... */
3882 else if (ctl->rng_type == 2) {
3883#ifdef CURAND
3884#pragma acc host_data use_device(rs)
3885 {
3886
3887 /* Uniform distribution... */
3888 if (method == 0) {
3889 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
3890 CURAND_STATUS_SUCCESS)
3891 ERRMSG("Cannot create random numbers!");
3892 }
3893
3894 /* Normal distribution... */
3895 else if (method == 1) {
3896 if (curandGenerateNormalDouble
3897 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
3898 1.0) != CURAND_STATUS_SUCCESS)
3899 ERRMSG("Cannot create random numbers!");
3900 }
3901 }
3902#else
3903 ERRMSG("MPTRAC was compiled without cuRAND!");
3904#endif
3905 }
3906}
3907
3908/*****************************************************************************/
3909
3911 const ctl_t *ctl,
3912 const cache_t *cache,
3913 met_t *met0,
3914 met_t *met1,
3915 atm_t *atm) {
3916
3917 /* Set timer... */
3918 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
3919
3920 /* Loop over particles... */
3921 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3922
3923 /* Get temperature... */
3924 double t;
3926 INTPOL_3D(t, 1);
3927
3928 /* Sedimentation velocity... */
3929 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3930 atm->q[ctl->qnt_rhop][ip]);
3931
3932 /* Calculate pressure change... */
3933 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
3934 }
3935}
3936
3937/*****************************************************************************/
3938
3940 const ctl_t *ctl,
3941 met_t *met0,
3942 atm_t *atm) {
3943
3944 /* Set timer... */
3945 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
3946
3947 /* Allocate... */
3948 const int np = atm->np;
3949 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
3950 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
3951 if (a == NULL || p == NULL)
3952 ERRMSG("Out of memory!");
3953
3954#ifdef _OPENACC
3955#pragma acc enter data create(a[0:np],p[0:np])
3956#pragma acc data present(ctl,met0,atm,a,p)
3957#endif
3958
3959 /* Get box index... */
3960#ifdef _OPENACC
3961#pragma acc parallel loop independent gang vector
3962#else
3963#pragma omp parallel for default(shared)
3964#endif
3965 for (int ip = 0; ip < np; ip++) {
3966 a[ip] =
3967 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
3968 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
3969 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
3970 p[ip] = ip;
3971 }
3972
3973 /* Sorting... */
3974#ifdef THRUST
3975#ifdef _OPENACC
3976#pragma acc host_data use_device(a,p)
3977#endif
3978 thrustSortWrapper(a, np, p);
3979#else
3980#ifdef _OPENACC
3981 ERRMSG("GSL sort fallback not available on GPU, use THRUST!");
3982#endif
3983 gsl_sort_index((size_t *) p, a, 1, (size_t) np);
3984#endif
3985
3986 /* Sort data... */
3987 module_sort_help(atm->time, p, np);
3988 module_sort_help(atm->p, p, np);
3989 module_sort_help(atm->lon, p, np);
3990 module_sort_help(atm->lat, p, np);
3991 for (int iq = 0; iq < ctl->nq; iq++)
3992 module_sort_help(atm->q[iq], p, np);
3993
3994 /* Free... */
3995#ifdef _OPENACC
3996#pragma acc exit data delete(a,p)
3997#endif
3998 free(a);
3999 free(p);
4000}
4001
4002/*****************************************************************************/
4003
4005 double *a,
4006 const int *p,
4007 const int np) {
4008
4009 /* Allocate... */
4010 double *restrict const help =
4011 (double *) malloc((size_t) np * sizeof(double));
4012 if (help == NULL)
4013 ERRMSG("Out of memory!");
4014
4015 /* Reordering of array... */
4016#ifdef _OPENACC
4017#pragma acc enter data create(help[0:np])
4018#pragma acc data present(a,p,help)
4019#pragma acc parallel loop independent gang vector
4020#else
4021#pragma omp parallel for default(shared)
4022#endif
4023 for (int ip = 0; ip < np; ip++)
4024 help[ip] = a[p[ip]];
4025#ifdef _OPENACC
4026#pragma acc parallel loop independent gang vector
4027#else
4028#pragma omp parallel for default(shared)
4029#endif
4030 for (int ip = 0; ip < np; ip++)
4031 a[ip] = help[ip];
4032
4033 /* Free... */
4034#ifdef _OPENACC
4035#pragma acc exit data delete(help)
4036#endif
4037 free(help);
4038}
4039
4040/*****************************************************************************/
4041
4043 const ctl_t *ctl,
4044 cache_t *cache,
4045 met_t *met0,
4046 atm_t *atm,
4047 const double t) {
4048
4049 /* Set timer... */
4050 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
4051
4052 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
4053 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
4054
4055 const int local =
4056 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
4057
4058 /* Loop over particles... */
4059 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
4060
4061 /* Set time step for each air parcel... */
4062 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
4063 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
4064 && ctl->direction * (atm->time[ip] - t) < 0))
4065 cache->dt[ip] = t - atm->time[ip];
4066 else
4067 cache->dt[ip] = 0.0;
4068
4069 /* Check horizontal boundaries of local meteo data... */
4070#ifndef DD
4071 int dd = 0;
4072#else
4073 int dd = 1;
4074#endif
4075 if (dd) {
4076 if (local && (atm->lon[ip] <= met0->lon[0]
4077 || atm->lon[ip] >= met0->lon[met0->nx - 1]
4078 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
4079 cache->dt[ip] = 0.0;
4080 } else {
4081 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
4082 cache->dt[ip] = 0;
4083 }
4084 }
4085}
4086
4087/*****************************************************************************/
4088
4090 ctl_t *ctl,
4091 const atm_t *atm) {
4092
4093 /* Set timer... */
4094 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS", NVTX_GPU);
4095
4096 /* Set start time... */
4097 if (ctl->direction == 1) {
4098 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4099 if (ctl->t_stop > 1e99)
4100 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4101 } else {
4102 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4103 if (ctl->t_stop > 1e99)
4104 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4105 }
4106
4107 /* Check time interval... */
4108 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
4109 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
4110
4111 /* Round start time... */
4112 if (ctl->direction == 1)
4113 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4114 else
4115 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4116}
4117
4118/*****************************************************************************/
4119
4121 const ctl_t *ctl,
4122 const cache_t *cache,
4123 const clim_t *clim,
4124 met_t *met0,
4125 met_t *met1,
4126 atm_t *atm) {
4127
4128 /* Set timer... */
4129 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS", NVTX_GPU);
4130
4131 /* Loop over particles... */
4132 PARTICLE_LOOP(0, atm->np, 1,
4133 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4134
4135 /* Get temperature... */
4136 double t;
4138 INTPOL_3D(t, 1);
4139
4140 /* Get molecular density... */
4141 const double M = MOLEC_DENS(atm->p[ip], t);
4142
4143 /* Get total column ozone... */
4144 double o3c;
4145 INTPOL_2D(o3c, 1);
4146
4147 /* Get solar zenith angle... */
4148 const double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
4149
4150 /* Get O(1D) volume mixing ratio... */
4151 const double o1d =
4152 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4153
4154 /* Reactions for CFC-10... */
4155 if (ctl->qnt_Cccl4 >= 0) {
4156 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4157 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4158 atm->p[ip], sza, o3c);
4159 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4160 }
4161
4162 /* Reactions for CFC-11... */
4163 if (ctl->qnt_Cccl3f >= 0) {
4164 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4165 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4166 atm->p[ip], sza, o3c);
4167 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4168 }
4169
4170 /* Reactions for CFC-12... */
4171 if (ctl->qnt_Cccl2f2 >= 0) {
4172 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4173 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4174 atm->p[ip], sza, o3c);
4175 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4176 }
4177
4178 /* Reactions for N2O... */
4179 if (ctl->qnt_Cn2o >= 0) {
4180 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4181 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4182 atm->p[ip], sza, o3c);
4183 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4184 }
4185 }
4186}
4187
4188/*****************************************************************************/
4189
4191 const ctl_t *ctl,
4192 const cache_t *cache,
4193 met_t *met0,
4194 met_t *met1,
4195 atm_t *atm) {
4196
4197 /* Set timer... */
4198 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS", NVTX_GPU);
4199
4200 /* Check quantity flags... */
4201 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4202 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4203
4204 /* Loop over particles... */
4205 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4206
4207 /* Check whether particle is below cloud top... */
4208 double pct;
4210 INTPOL_2D(pct, 1);
4211 if (!isfinite(pct) || atm->p[ip] <= pct)
4212 continue;
4213
4214 /* Get cloud bottom pressure... */
4215 double pcb;
4216 INTPOL_2D(pcb, 0);
4217
4218 /* Estimate precipitation rate (Pisso et al., 2019)... */
4219 double cl;
4220 INTPOL_2D(cl, 0);
4221 const double Is =
4222 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4223 if (Is < 0.01)
4224 continue;
4225
4226 /* Check whether particle is inside or below cloud... */
4227 double lwc, rwc, iwc, swc;
4228 INTPOL_3D(lwc, 1);
4229 INTPOL_3D(rwc, 0);
4230 INTPOL_3D(iwc, 0);
4231 INTPOL_3D(swc, 0);
4232 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4233
4234 /* Get temperature... */
4235 double t;
4236 INTPOL_3D(t, 0);
4237
4238 /* Calculate in-cloud scavenging coefficient... */
4239 double lambda = 0;
4240 if (inside) {
4241
4242 /* Calculate retention factor... */
4243 double eta;
4244 if (t > 273.15)
4245 eta = 1;
4246 else if (t <= 238.15)
4247 eta = ctl->wet_depo_ic_ret_ratio;
4248 else
4249 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4250
4251 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4252 if (ctl->wet_depo_ic_a > 0)
4253 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4254
4255 /* Use Henry's law for gases... */
4256 else if (ctl->wet_depo_ic_h[0] > 0) {
4257
4258 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4259 double h = ctl->wet_depo_ic_h[0]
4260 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4261
4262 /* Use effective Henry's constant for SO2
4263 (Berglen, 2004; Simpson, 2012)... */
4264 if (ctl->wet_depo_so2_ph > 0) {
4265 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
4266 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4267 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4268 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
4269 }
4270
4271 /* Estimate depth of cloud layer... */
4272 const double dz = 1e3 * (Z(pct) - Z(pcb));
4273
4274 /* Calculate scavenging coefficient... */
4275 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4276 }
4277 }
4278
4279 /* Calculate below-cloud scavenging coefficient... */
4280 else {
4281
4282 /* Calculate retention factor... */
4283 double eta;
4284 if (t > 270)
4285 eta = 1;
4286 else
4287 eta = ctl->wet_depo_bc_ret_ratio;
4288
4289 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4290 if (ctl->wet_depo_bc_a > 0)
4291 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4292
4293 /* Use Henry's law for gases... */
4294 else if (ctl->wet_depo_bc_h[0] > 0) {
4295
4296 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4297 const double h = ctl->wet_depo_bc_h[0]
4298 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4299
4300 /* Estimate depth of cloud layer... */
4301 const double dz = 1e3 * (Z(pct) - Z(pcb));
4302
4303 /* Calculate scavenging coefficient... */
4304 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4305 }
4306 }
4307
4308 /* Calculate exponential decay of mass... */
4309 const double aux = exp(-cache->dt[ip] * lambda);
4310 if (ctl->qnt_m >= 0) {
4311 if (ctl->qnt_mloss_wet >= 0)
4312 atm->q[ctl->qnt_mloss_wet][ip]
4313 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4314 atm->q[ctl->qnt_m][ip] *= aux;
4315 if (ctl->qnt_loss_rate >= 0)
4316 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4317 }
4318 if (ctl->qnt_vmr >= 0)
4319 atm->q[ctl->qnt_vmr][ip] *= aux;
4320 }
4321}
4322
4323/*****************************************************************************/
4324
4326 ctl_t **ctl,
4327 cache_t **cache,
4328 clim_t **clim,
4329 met_t **met0,
4330 met_t **met1,
4331 atm_t **atm) {
4332
4333 /* Initialize GPU... */
4334#ifdef _OPENACC
4335 SELECT_TIMER("ACC_INIT", "INIT", NVTX_GPU);
4336 int rank = 0;
4337#ifdef MPI
4338 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
4339#endif
4340 if (acc_get_num_devices(acc_device_nvidia) <= 0)
4341 ERRMSG("Not running on a GPU device!");
4342 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
4343 acc_device_nvidia);
4344 acc_device_t device_type = acc_get_device_type();
4345 acc_init(device_type);
4346#endif
4347
4348 /* Allocate... */
4349 SELECT_TIMER("ALLOC", "MEMORY", NVTX_CPU);
4350 ALLOC(*ctl, ctl_t, 1);
4351 ALLOC(*cache, cache_t, 1);
4352 ALLOC(*clim, clim_t, 1);
4353 ALLOC(*met0, met_t, 1);
4354 ALLOC(*met1, met_t, 1);
4355 ALLOC(*atm, atm_t, 1);
4356
4357 /* Create data region on GPU... */
4358#ifdef _OPENACC
4359 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY", NVTX_GPU);
4360 ctl_t *ctlup = *ctl;
4361 cache_t *cacheup = *cache;
4362 clim_t *climup = *clim;
4363 met_t *met0up = *met0;
4364 met_t *met1up = *met1;
4365 atm_t *atmup = *atm;
4366#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
4367#endif
4368}
4369
4370/*****************************************************************************/
4371
4372#ifdef DD
4373void mptrac_free(
4374 ctl_t *ctl,
4375 cache_t *cache,
4376 clim_t *clim,
4377 met_t *met0,
4378 met_t *met1,
4379 atm_t *atm,
4380 mpi_info_t *mpi_info) {
4381#else
4383 ctl_t *ctl,
4384 cache_t *cache,
4385 clim_t *clim,
4386 met_t *met0,
4387 met_t *met1,
4388 atm_t *atm) {
4389#endif
4390
4391 /* Delete data region on GPU... */
4392#ifdef _OPENACC
4393 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY", NVTX_GPU);
4394#pragma acc exit data delete (ctl,cache,clim,met0,met1,atm)
4395#endif
4396
4397 /* Free... */
4398 SELECT_TIMER("FREE", "MEMORY", NVTX_CPU);
4399 free(atm);
4400 free(ctl);
4401 free(cache);
4402 free(clim);
4403 free(met0);
4404 free(met1);
4405
4406 /* Free MPI datatype... */
4407#ifdef DD
4408 MPI_Type_free(&mpi_info->MPI_Particle);
4409#endif
4410}
4411
4412/*****************************************************************************/
4413
4415 ctl_t *ctl,
4416 clim_t *clim,
4417 const double t,
4418 met_t **met0,
4419 met_t **met1) {
4420
4421 static int init;
4422
4423 met_t *mets;
4424
4425 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
4426
4427 /* Set timer... */
4428 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4429
4430 /* Init... */
4431 if (t == ctl->t_start || !init) {
4432 init = 1;
4433
4434 /* Read meteo data... */
4435 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
4436 ctl->metbase, ctl->dt_met, filename);
4437 if (!mptrac_read_met(filename, ctl, clim, *met0))
4438 ERRMSG("Cannot open file!");
4439
4440 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
4441 ctl->metbase, ctl->dt_met, filename);
4442 if (!mptrac_read_met(filename, ctl, clim, *met1))
4443 ERRMSG("Cannot open file!");
4444
4445 /* Update GPU... */
4446 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
4447 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4448
4449 /* Caching... */
4450 if (ctl->met_cache && t != ctl->t_stop) {
4451 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
4452 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
4453 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4454 LOG(1, "Caching: %s", cachefile);
4455 if (system(cmd) != 0)
4456 WARN("Caching command failed!");
4457 }
4458 }
4459
4460 /* Read new data for forward trajectories... */
4461 if (t > (*met1)->time) {
4462
4463 /* Pointer swap... */
4464 mets = *met1;
4465 *met1 = *met0;
4466 *met0 = mets;
4467
4468 /* Read new meteo data... */
4469 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
4470 if (!mptrac_read_met(filename, ctl, clim, *met1))
4471 ERRMSG("Cannot open file!");
4472
4473 /* Update GPU... */
4474 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
4475 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4476
4477 /* Caching... */
4478 if (ctl->met_cache && t != ctl->t_stop) {
4479 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
4480 cachefile);
4481 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4482 LOG(1, "Caching: %s", cachefile);
4483 if (system(cmd) != 0)
4484 WARN("Caching command failed!");
4485 }
4486 }
4487
4488 /* Read new data for backward trajectories... */
4489 if (t < (*met0)->time) {
4490
4491 /* Pointer swap... */
4492 mets = *met1;
4493 *met1 = *met0;
4494 *met0 = mets;
4495
4496 /* Read new meteo data... */
4497 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
4498 if (!mptrac_read_met(filename, ctl, clim, *met0))
4499 ERRMSG("Cannot open file!");
4500
4501 /* Update GPU... */
4502 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
4503 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4504
4505 /* Caching... */
4506 if (ctl->met_cache && t != ctl->t_stop) {
4507 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
4508 cachefile);
4509 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4510 LOG(1, "Caching: %s", cachefile);
4511 if (system(cmd) != 0)
4512 WARN("Caching command failed!");
4513 }
4514 }
4515
4516 /* Check that grids are consistent... */
4517 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
4518 if ((*met0)->nx != (*met1)->nx
4519 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
4520 ERRMSG("Meteo grid dimensions do not match!");
4521 for (int ix = 0; ix < (*met0)->nx; ix++)
4522 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
4523 ERRMSG("Meteo grid longitudes do not match!");
4524 for (int iy = 0; iy < (*met0)->ny; iy++)
4525 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
4526 ERRMSG("Meteo grid latitudes do not match!");
4527 for (int ip = 0; ip < (*met0)->np; ip++)
4528 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
4529 ERRMSG("Meteo grid pressure levels do not match!");
4530 }
4531}
4532
4533/*****************************************************************************/
4534
4536 ctl_t *ctl,
4537 cache_t *cache,
4538 clim_t *clim,
4539 atm_t *atm,
4540 const int ntask) {
4541
4542 /* Initialize timesteps... */
4543 module_timesteps_init(ctl, atm);
4544
4545 /* Initialize random number generator... */
4546 module_rng_init(ntask);
4547
4548 /* Update GPU memory... */
4549 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
4550}
4551
4552/*****************************************************************************/
4553
4555 const char *filename,
4556 const ctl_t *ctl,
4557 atm_t *atm) {
4558
4559 int result;
4560
4561 /* Set timer... */
4562 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
4563
4564 /* Init... */
4565 atm->np = 0;
4566
4567 /* Write info... */
4568 LOG(1, "Read atmospheric data: %s", filename);
4569
4570 /* Read ASCII data... */
4571 if (ctl->atm_type == 0)
4572 result = read_atm_asc(filename, ctl, atm);
4573
4574 /* Read binary data... */
4575 else if (ctl->atm_type == 1)
4576 result = read_atm_bin(filename, ctl, atm);
4577
4578 /* Read netCDF data... */
4579 else if (ctl->atm_type == 2)
4580 result = read_atm_nc(filename, ctl, atm);
4581
4582 /* Read CLaMS data... */
4583 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
4584 result = read_atm_clams(filename, ctl, atm);
4585
4586 /* Error... */
4587 else
4588 ERRMSG("Atmospheric data type not supported!");
4589
4590 /* Check result... */
4591 if (result != 1)
4592 return 0;
4593
4594 /* Check number of air parcels... */
4595 if (atm->np < 1)
4596 ERRMSG("Can not read any data!");
4597
4598 /* Write info... */
4599 double mini, maxi;
4600 LOG(2, "Number of particles: %d", atm->np);
4601 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
4602 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
4603 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
4604 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
4605 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
4606 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
4607 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
4608 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
4609 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
4610 for (int iq = 0; iq < ctl->nq; iq++) {
4611 char msg[5 * LEN];
4612 sprintf(msg, "Quantity %s range: %s ... %s %s",
4613 ctl->qnt_name[iq], ctl->qnt_format[iq],
4614 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
4615 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
4616 LOG(2, msg, mini, maxi);
4617 }
4618
4619 /* Return success... */
4620 return 1;
4621}
4622
4623/*****************************************************************************/
4624
4626 const ctl_t *ctl,
4627 clim_t *clim) {
4628
4629 /* Set timer... */
4630 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
4631
4632 /* Init tropopause climatology... */
4633 clim_tropo_init(clim);
4634
4635 /* Read photolysis rates... */
4636 if (ctl->clim_photo[0] != '-')
4637 read_clim_photo(ctl->clim_photo, &clim->photo);
4638
4639 /* Read HNO3 climatology... */
4640 if (ctl->clim_hno3_filename[0] != '-')
4641 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
4642
4643 /* Read OH climatology... */
4644 if (ctl->clim_oh_filename[0] != '-') {
4645 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
4646 if (ctl->oh_chem_beta > 0)
4647 clim_oh_diurnal_correction(ctl, clim);
4648 }
4649
4650 /* Read H2O2 climatology... */
4651 if (ctl->clim_h2o2_filename[0] != '-')
4652 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
4653
4654 /* Read HO2 climatology... */
4655 if (ctl->clim_ho2_filename[0] != '-')
4656 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
4657
4658 /* Read O(1D) climatology... */
4659 if (ctl->clim_o1d_filename[0] != '-')
4660 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
4661
4662 /* Read CFC-10 time series... */
4663 if (ctl->clim_ccl4_timeseries[0] != '-')
4665
4666 /* Read CFC-11 time series... */
4667 if (ctl->clim_ccl3f_timeseries[0] != '-')
4669
4670 /* Read CFC-12 time series... */
4671 if (ctl->clim_ccl2f2_timeseries[0] != '-')
4673
4674 /* Read N2O time series... */
4675 if (ctl->clim_n2o_timeseries[0] != '-')
4676 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
4677
4678 /* Read SF6 time series... */
4679 if (ctl->clim_sf6_timeseries[0] != '-')
4680 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
4681}
4682
4683/*****************************************************************************/
4684
4686 const char *filename,
4687 int argc,
4688 char *argv[],
4689 ctl_t *ctl) {
4690
4691 /* Set timer... */
4692 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
4693
4694 /* Write info... */
4695 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
4696 "(executable: %s | version: %s | compiled: %s, %s)\n",
4697 argv[0], VERSION, __DATE__, __TIME__);
4698
4699 /* Initialize quantity indices... */
4700 ctl->qnt_idx = -1;
4701 ctl->qnt_ens = -1;
4702 ctl->qnt_stat = -1;
4703 ctl->qnt_m = -1;
4704 ctl->qnt_vmr = -1;
4705 ctl->qnt_rp = -1;
4706 ctl->qnt_rhop = -1;
4707 ctl->qnt_ps = -1;
4708 ctl->qnt_ts = -1;
4709 ctl->qnt_zs = -1;
4710 ctl->qnt_us = -1;
4711 ctl->qnt_vs = -1;
4712 ctl->qnt_ess = -1;
4713 ctl->qnt_nss = -1;
4714 ctl->qnt_shf = -1;
4715 ctl->qnt_lsm = -1;
4716 ctl->qnt_sst = -1;
4717 ctl->qnt_pbl = -1;
4718 ctl->qnt_pt = -1;
4719 ctl->qnt_tt = -1;
4720 ctl->qnt_zt = -1;
4721 ctl->qnt_h2ot = -1;
4722 ctl->qnt_zg = -1;
4723 ctl->qnt_p = -1;
4724 ctl->qnt_t = -1;
4725 ctl->qnt_rho = -1;
4726 ctl->qnt_u = -1;
4727 ctl->qnt_v = -1;
4728 ctl->qnt_w = -1;
4729 ctl->qnt_h2o = -1;
4730 ctl->qnt_o3 = -1;
4731 ctl->qnt_lwc = -1;
4732 ctl->qnt_rwc = -1;
4733 ctl->qnt_iwc = -1;
4734 ctl->qnt_swc = -1;
4735 ctl->qnt_cc = -1;
4736 ctl->qnt_pct = -1;
4737 ctl->qnt_pcb = -1;
4738 ctl->qnt_cl = -1;
4739 ctl->qnt_plcl = -1;
4740 ctl->qnt_plfc = -1;
4741 ctl->qnt_pel = -1;
4742 ctl->qnt_cape = -1;
4743 ctl->qnt_cin = -1;
4744 ctl->qnt_o3c = -1;
4745 ctl->qnt_hno3 = -1;
4746 ctl->qnt_oh = -1;
4747 ctl->qnt_h2o2 = -1;
4748 ctl->qnt_ho2 = -1;
4749 ctl->qnt_o1d = -1;
4750 ctl->qnt_mloss_oh = -1;
4751 ctl->qnt_mloss_h2o2 = -1;
4752 ctl->qnt_mloss_kpp = -1;
4753 ctl->qnt_mloss_wet = -1;
4754 ctl->qnt_mloss_dry = -1;
4755 ctl->qnt_mloss_decay = -1;
4756 ctl->qnt_loss_rate = -1;
4757 ctl->qnt_psat = -1;
4758 ctl->qnt_psice = -1;
4759 ctl->qnt_pw = -1;
4760 ctl->qnt_sh = -1;
4761 ctl->qnt_rh = -1;
4762 ctl->qnt_rhice = -1;
4763 ctl->qnt_theta = -1;
4764 ctl->qnt_zeta = -1;
4765 ctl->qnt_zeta_d = -1;
4766 ctl->qnt_zeta_dot = -1;
4767 ctl->qnt_tvirt = -1;
4768 ctl->qnt_lapse = -1;
4769 ctl->qnt_vh = -1;
4770 ctl->qnt_vz = -1;
4771 ctl->qnt_pv = -1;
4772 ctl->qnt_tdew = -1;
4773 ctl->qnt_tice = -1;
4774 ctl->qnt_tsts = -1;
4775 ctl->qnt_tnat = -1;
4776 ctl->qnt_Cx = -1;
4777 ctl->qnt_Ch2o = -1;
4778 ctl->qnt_Co3 = -1;
4779 ctl->qnt_Cco = -1;
4780 ctl->qnt_Coh = -1;
4781 ctl->qnt_Ch = -1;
4782 ctl->qnt_Cho2 = -1;
4783 ctl->qnt_Ch2o2 = -1;
4784 ctl->qnt_Co1d = -1;
4785 ctl->qnt_Co3p = -1;
4786 ctl->qnt_Cccl4 = -1;
4787 ctl->qnt_Cccl3f = -1;
4788 ctl->qnt_Cccl2f2 = -1;
4789 ctl->qnt_Cn2o = -1;
4790 ctl->qnt_Csf6 = -1;
4791 ctl->qnt_aoa = -1;
4792
4793#ifdef DD
4794 ctl->qnt_destination = -1;
4795 ctl->qnt_subdomain = -1;
4796#endif
4797
4798 /* Read quantities... */
4799 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
4800 if (ctl->nq > NQ)
4801 ERRMSG("Too many quantities!");
4802 for (int iq = 0; iq < ctl->nq; iq++) {
4803
4804 /* Read quantity name and format... */
4805 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
4806 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
4807 ctl->qnt_longname[iq]);
4808 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
4809 ctl->qnt_format[iq]);
4810 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
4811 sprintf(ctl->qnt_format[iq], "%%.2f");
4812
4813 /* Try to identify quantity... */
4814 SET_QNT(qnt_idx, "idx", "particle index", "-")
4815 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
4816 SET_QNT(qnt_stat, "stat", "station flag", "-")
4817 SET_QNT(qnt_m, "m", "mass", "kg")
4818 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
4819 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
4820 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
4821 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
4822 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
4823 SET_QNT(qnt_zs, "zs", "surface height", "km")
4824 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
4825 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
4826 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
4827 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
4828 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
4829 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
4830 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
4831 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
4832 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
4833 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
4834 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
4835 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
4836 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
4837 SET_QNT(qnt_p, "p", "pressure", "hPa")
4838 SET_QNT(qnt_t, "t", "temperature", "K")
4839 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
4840 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
4841 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
4842 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
4843 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
4844 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
4845 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
4846 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
4847 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
4848 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
4849 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
4850 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
4851 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
4852 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
4853 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
4854 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
4855 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
4856 SET_QNT(qnt_cape, "cape", "convective available potential energy",
4857 "J/kg")
4858 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
4859 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
4860 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
4861 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
4862 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
4863 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
4864 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
4865 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
4866 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
4867 "mass loss due to H2O2 chemistry", "kg")
4868 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
4869 "kg")
4870 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
4871 "kg")
4872 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
4873 "kg")
4874 SET_QNT(qnt_mloss_decay, "mloss_decay",
4875 "mass loss due to exponential decay", "kg")
4876 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
4877 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
4878 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
4879 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
4880 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
4881 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
4882 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
4883 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
4884 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
4885 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
4886 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
4887 "K/day")
4888 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
4889 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
4890 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
4891 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
4892 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
4893 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
4894 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
4895 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
4896 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
4897 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
4898 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
4899 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
4900 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
4901 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
4902 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
4903 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
4904 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
4905 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
4906 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
4907 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
4908 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
4909 "ppv")
4910 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
4911 "ppv")
4912 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
4913 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
4914 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
4915#ifdef DD
4916 SET_QNT(qnt_destination, "destination",
4917 "subdomain index of destination", "-")
4918 SET_QNT(qnt_subdomain, "subdomain", "current subdomain index", "-")
4919#endif
4920 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
4921 }
4922
4923 /* Vertical coordinates and velocities... */
4924 ctl->advect_vert_coord =
4925 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
4926 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 2)
4927 ERRMSG("Set ADVECT_VERT_COORD to 0, 1, or 2!");
4928 ctl->met_vert_coord =
4929 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
4930 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
4931 ERRMSG("Set MET_VERT_COORD to 0, 1, 2, 3, or 4!");
4932 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
4933 ERRMSG("Please add zeta to your quantities for diabatic calculations!");
4934 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
4935 ERRMSG
4936 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
4937
4938 /* Time steps of simulation... */
4939 ctl->direction =
4940 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
4941 if (ctl->direction != -1 && ctl->direction != 1)
4942 ERRMSG("Set DIRECTION to -1 or 1!");
4943 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
4944 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
4945
4946 /* Meteo data... */
4947 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
4948 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
4949 ctl->met_convention =
4950 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
4951 ctl->met_type =
4952 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
4953 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
4954 ERRMSG
4955 ("Please use meteo files in netcdf format for diabatic calculations.");
4956 ctl->met_clams =
4957 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
4958 ctl->met_nc_scale =
4959 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
4960 ctl->met_nc_level =
4961 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
4962 ctl->met_nc_quant =
4963 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
4964 ctl->met_zstd_level =
4965 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
4966 for (int i = 0; i < METVAR; i++) {
4967 char defprec[LEN] = "0", deftol[LEN] = "0.0";
4968 if (i == 0) /* geopotential height */
4969 sprintf(deftol, "0.5");
4970 else if (i == 1) /* temperature */
4971 sprintf(deftol, "5.0");
4972 else /* other variables */
4973 sprintf(defprec, "8");
4974 ctl->met_comp_prec[i] =
4975 (int) scan_ctl(filename, argc, argv, "MET_COMP_PREC", i, defprec, NULL);
4976 ctl->met_comp_tol[i] =
4977 scan_ctl(filename, argc, argv, "MET_COMP_TOL", i, deftol, NULL);
4978 }
4979 ctl->met_cms_batch =
4980 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
4981 ctl->met_cms_zstd =
4982 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
4983 ctl->met_cms_heur =
4984 (int) scan_ctl(filename, argc, argv, "MET_CMS_HEUR", -1, "1", NULL);
4985 ctl->met_cms_eps_z =
4986 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
4987 ctl->met_cms_eps_t =
4988 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
4989 ctl->met_cms_eps_u =
4990 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
4991 ctl->met_cms_eps_v =
4992 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
4993 ctl->met_cms_eps_w =
4994 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
4995 ctl->met_cms_eps_pv =
4996 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
4997 ctl->met_cms_eps_h2o =
4998 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
4999 ctl->met_cms_eps_o3 =
5000 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
5001 ctl->met_cms_eps_lwc =
5002 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
5003 ctl->met_cms_eps_rwc =
5004 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
5005 ctl->met_cms_eps_iwc =
5006 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
5007 ctl->met_cms_eps_swc =
5008 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
5009 ctl->met_cms_eps_cc =
5010 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
5011 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
5012 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
5013 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
5014 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
5015 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
5016 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
5017 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
5018 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
5019 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
5020 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
5021 ctl->met_detrend =
5022 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
5023 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
5024 if (ctl->met_np > EP)
5025 ERRMSG("Too many pressure levels!");
5026 ctl->met_press_level_def =
5027 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
5028 NULL);
5029 if (ctl->met_press_level_def >= 0) {
5030 level_definitions(ctl);
5031 } else {
5032 if (ctl->met_np > 0) {
5033 for (int ip = 0; ip < ctl->met_np; ip++)
5034 ctl->met_p[ip] =
5035 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
5036 }
5037 }
5038 ctl->met_nlev =
5039 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
5040 if (ctl->met_nlev > EP)
5041 ERRMSG("Too many model levels!");
5042 for (int ip = 0; ip < ctl->met_nlev; ip++) {
5043 ctl->met_lev_hyam[ip] =
5044 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
5045 ctl->met_lev_hybm[ip] =
5046 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
5047 }
5048 ctl->met_geopot_sx =
5049 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
5050 ctl->met_geopot_sy =
5051 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
5052 ctl->met_relhum =
5053 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
5054 ctl->met_cape =
5055 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
5056 if (ctl->met_cape < 0 || ctl->met_cape > 1)
5057 ERRMSG("Set MET_CAPE to 0 or 1!");
5058 ctl->met_pbl =
5059 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
5060 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
5061 ERRMSG("Set MET_PBL to 0 ... 3!");
5062 ctl->met_pbl_min =
5063 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
5064 ctl->met_pbl_max =
5065 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
5066 ctl->met_tropo =
5067 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
5068 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
5069 ERRMSG("Set MET_TROPO to 0 ... 5!");
5070 ctl->met_tropo_pv =
5071 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
5072 ctl->met_tropo_theta =
5073 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
5074 ctl->met_tropo_spline =
5075 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
5076 ctl->met_dt_out =
5077 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
5078 ctl->met_cache =
5079 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
5080 ctl->met_mpi_share =
5081 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
5082
5083 /* Sorting... */
5084 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
5085
5086 /* Isosurface parameters... */
5087 ctl->isosurf =
5088 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
5089 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
5090
5091 /* Random number generator... */
5092 ctl->rng_type =
5093 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
5094 if (ctl->rng_type < 0 || ctl->rng_type > 2)
5095 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
5096
5097 /* Advection parameters... */
5098 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
5099 if (!
5100 (ctl->advect == 0 || ctl->advect == 1 || ctl->advect == 2
5101 || ctl->advect == 4))
5102 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
5103
5104 /* Diffusion parameters... */
5105 ctl->diffusion
5106 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
5107 if (ctl->diffusion < 0 || ctl->diffusion > 2)
5108 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
5109 ctl->turb_dx_pbl =
5110 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
5111 ctl->turb_dx_trop =
5112 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
5113 ctl->turb_dx_strat =
5114 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
5115 ctl->turb_dz_pbl =
5116 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
5117 ctl->turb_dz_trop =
5118 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
5119 ctl->turb_dz_strat =
5120 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
5121 ctl->turb_mesox =
5122 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
5123 ctl->turb_mesoz =
5124 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5125
5126 /* Convection... */
5127 ctl->conv_mix_pbl
5128 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
5129 ctl->conv_pbl_trans
5130 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
5131 ctl->conv_cape
5132 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5133 ctl->conv_cin
5134 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5135 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5136
5137 /* Boundary conditions... */
5138 ctl->bound_mass =
5139 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5140 ctl->bound_mass_trend =
5141 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5142 ctl->bound_vmr =
5143 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5144 ctl->bound_vmr_trend =
5145 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5146 ctl->bound_lat0 =
5147 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5148 ctl->bound_lat1 =
5149 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5150 ctl->bound_p0 =
5151 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5152 ctl->bound_p1 =
5153 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5154 ctl->bound_dps =
5155 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5156 ctl->bound_dzs =
5157 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
5158 ctl->bound_zetas =
5159 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
5160 ctl->bound_pbl =
5161 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
5162
5163 /* Species parameters... */
5164 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
5165 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
5166 ctl->molmass = 120.907;
5167 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
5168 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5169 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5170 ctl->molmass = 137.359;
5171 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5172 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5173 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5174 ctl->molmass = 16.043;
5175 ctl->oh_chem_reaction = 2;
5176 ctl->oh_chem[0] = 2.45e-12;
5177 ctl->oh_chem[1] = 1775;
5178 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5179 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5180 } else if (strcasecmp(ctl->species, "CO") == 0) {
5181 ctl->molmass = 28.01;
5182 ctl->oh_chem_reaction = 3;
5183 ctl->oh_chem[0] = 6.9e-33;
5184 ctl->oh_chem[1] = 2.1;
5185 ctl->oh_chem[2] = 1.1e-12;
5186 ctl->oh_chem[3] = -1.3;
5187 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5188 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5189 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5190 ctl->molmass = 44.009;
5191 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5192 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5193 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5194 ctl->molmass = 18.01528;
5195 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5196 ctl->molmass = 44.013;
5197 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5198 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5199 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5200 ctl->molmass = 17.031;
5201 ctl->oh_chem_reaction = 2;
5202 ctl->oh_chem[0] = 1.7e-12;
5203 ctl->oh_chem[1] = 710;
5204 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
5205 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
5206 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
5207 ctl->molmass = 63.012;
5208 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
5209 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
5210 } else if (strcasecmp(ctl->species, "NO") == 0) {
5211 ctl->molmass = 30.006;
5212 ctl->oh_chem_reaction = 3;
5213 ctl->oh_chem[0] = 7.1e-31;
5214 ctl->oh_chem[1] = 2.6;
5215 ctl->oh_chem[2] = 3.6e-11;
5216 ctl->oh_chem[3] = 0.1;
5217 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
5218 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5219 } else if (strcasecmp(ctl->species, "NO2") == 0) {
5220 ctl->molmass = 46.005;
5221 ctl->oh_chem_reaction = 3;
5222 ctl->oh_chem[0] = 1.8e-30;
5223 ctl->oh_chem[1] = 3.0;
5224 ctl->oh_chem[2] = 2.8e-11;
5225 ctl->oh_chem[3] = 0.0;
5226 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
5227 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5228 } else if (strcasecmp(ctl->species, "O3") == 0) {
5229 ctl->molmass = 47.997;
5230 ctl->oh_chem_reaction = 2;
5231 ctl->oh_chem[0] = 1.7e-12;
5232 ctl->oh_chem[1] = 940;
5233 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
5234 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
5235 } else if (strcasecmp(ctl->species, "SF6") == 0) {
5236 ctl->molmass = 146.048;
5237 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
5238 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
5239 } else if (strcasecmp(ctl->species, "SO2") == 0) {
5240 ctl->molmass = 64.066;
5241 ctl->oh_chem_reaction = 3;
5242 ctl->oh_chem[0] = 2.9e-31;
5243 ctl->oh_chem[1] = 4.1;
5244 ctl->oh_chem[2] = 1.7e-12;
5245 ctl->oh_chem[3] = -0.2;
5246 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
5247 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
5248 }
5249
5250 /* Molar mass... */
5251 char defstr[LEN];
5252 sprintf(defstr, "%g", ctl->molmass);
5253 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
5254
5255 /* OH chemistry... */
5256 sprintf(defstr, "%d", ctl->oh_chem_reaction);
5257 ctl->oh_chem_reaction =
5258 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
5259 NULL);
5260 for (int ip = 0; ip < 4; ip++) {
5261 sprintf(defstr, "%g", ctl->oh_chem[ip]);
5262 ctl->oh_chem[ip] =
5263 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
5264 }
5265 ctl->oh_chem_beta =
5266 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
5267
5268 /* H2O2 chemistry... */
5269 ctl->h2o2_chem_reaction =
5270 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
5271
5272 /* KPP chemistry... */
5273 ctl->kpp_chem =
5274 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
5275 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
5276
5277 /* First order tracer chemistry... */
5278 ctl->tracer_chem =
5279 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
5280
5281 /* Wet deposition... */
5282 for (int ip = 0; ip < 2; ip++) {
5283 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
5284 ctl->wet_depo_ic_h[ip] =
5285 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
5286 }
5287 for (int ip = 0; ip < 1; ip++) {
5288 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
5289 ctl->wet_depo_bc_h[ip] =
5290 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
5291 }
5292 ctl->wet_depo_so2_ph =
5293 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
5294 ctl->wet_depo_ic_a =
5295 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
5296 ctl->wet_depo_ic_b =
5297 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
5298 ctl->wet_depo_bc_a =
5299 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
5300 ctl->wet_depo_bc_b =
5301 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
5302 ctl->wet_depo_pre[0] =
5303 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
5304 ctl->wet_depo_pre[1] =
5305 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
5307 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
5309 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
5310
5311 /* Dry deposition... */
5312 ctl->dry_depo_vdep =
5313 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
5314 ctl->dry_depo_dp =
5315 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
5316
5317 /* Climatological data... */
5318 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
5319 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
5320 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
5321 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
5322 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
5323 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
5324 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
5325 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
5326 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
5327 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
5328 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
5329 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
5330 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
5331 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
5332 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
5333 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
5334 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
5335 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
5336 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
5337 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
5338 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
5339 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
5340
5341 /* Mixing... */
5342 ctl->mixing_dt =
5343 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
5344 ctl->mixing_trop =
5345 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
5346 ctl->mixing_strat =
5347 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
5348 ctl->mixing_z0 =
5349 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
5350 ctl->mixing_z1 =
5351 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
5352 ctl->mixing_nz =
5353 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
5354 ctl->mixing_lon0 =
5355 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
5356 ctl->mixing_lon1 =
5357 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
5358 ctl->mixing_nx =
5359 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
5360 ctl->mixing_lat0 =
5361 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
5362 ctl->mixing_lat1 =
5363 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
5364 ctl->mixing_ny =
5365 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
5366
5367 /* Chemistry grid... */
5368 ctl->chemgrid_z0 =
5369 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
5370 ctl->chemgrid_z1 =
5371 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
5372 ctl->chemgrid_nz =
5373 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
5374 ctl->chemgrid_lon0 =
5375 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
5376 ctl->chemgrid_lon1 =
5377 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
5378 ctl->chemgrid_nx =
5379 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
5380 ctl->chemgrid_lat0 =
5381 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
5382 ctl->chemgrid_lat1 =
5383 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
5384 ctl->chemgrid_ny =
5385 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
5386
5387 /* Exponential decay... */
5388 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
5389 ctl->tdec_strat =
5390 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
5391
5392 /* PSC analysis... */
5393 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
5394 ctl->psc_hno3 =
5395 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
5396
5397 /* Output of atmospheric data... */
5398 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
5399 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
5400 ctl->atm_dt_out =
5401 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
5402 ctl->atm_filter =
5403 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
5404 ctl->atm_stride =
5405 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
5406 ctl->atm_type =
5407 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
5408 ctl->atm_type_out =
5409 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
5410 if (ctl->atm_type_out == -1)
5411 ctl->atm_type_out = ctl->atm_type;
5412 ctl->atm_nc_level =
5413 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
5414 for (int iq = 0; iq < ctl->nq; iq++)
5415 ctl->atm_nc_quant[iq] =
5416 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
5417 ctl->obs_type =
5418 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
5419
5420 /* Output of CSI data... */
5421 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
5422 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
5423 ctl->csi_dt_out =
5424 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
5425 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
5426 ctl->csi_obsmin =
5427 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
5428 ctl->csi_modmin =
5429 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
5430 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
5431 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
5432 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
5433 ctl->csi_lon0 =
5434 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
5435 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
5436 ctl->csi_nx =
5437 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
5438 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
5439 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
5440 ctl->csi_ny =
5441 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
5442
5443 /* Output of ensemble data... */
5444 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
5445 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
5446 ctl->ens_dt_out =
5447 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
5448
5449 /* Output of grid data... */
5450 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
5451 ctl->grid_basename);
5452 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
5453 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
5454 ctl->grid_dt_out =
5455 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
5456 ctl->grid_sparse =
5457 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
5458 ctl->grid_nc_level =
5459 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
5460 for (int iq = 0; iq < ctl->nq; iq++)
5461 ctl->grid_nc_quant[iq] =
5462 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
5463 ctl->grid_stddev =
5464 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
5465 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
5466 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
5467 ctl->grid_nz =
5468 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
5469 ctl->grid_lon0 =
5470 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
5471 ctl->grid_lon1 =
5472 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
5473 ctl->grid_nx =
5474 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
5475 ctl->grid_lat0 =
5476 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
5477 ctl->grid_lat1 =
5478 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
5479 ctl->grid_ny =
5480 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
5481 ctl->grid_type =
5482 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
5483
5484 /* Output of profile data... */
5485 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
5486 ctl->prof_basename);
5487 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
5488 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
5489 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
5490 ctl->prof_nz =
5491 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
5492 ctl->prof_lon0 =
5493 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
5494 ctl->prof_lon1 =
5495 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
5496 ctl->prof_nx =
5497 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
5498 ctl->prof_lat0 =
5499 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
5500 ctl->prof_lat1 =
5501 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
5502 ctl->prof_ny =
5503 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
5504
5505 /* Output of sample data... */
5506 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
5507 ctl->sample_basename);
5508 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
5509 ctl->sample_kernel);
5510 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
5511 ctl->sample_obsfile);
5512 ctl->sample_dx =
5513 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
5514 ctl->sample_dz =
5515 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
5516
5517 /* Output of station data... */
5518 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
5519 ctl->stat_basename);
5520 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
5521 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
5522 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
5523 ctl->stat_t0 =
5524 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
5525 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
5526
5527 /* Output of VTK data... */
5528 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
5529 ctl->vtk_dt_out =
5530 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
5531 ctl->vtk_stride =
5532 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
5533 ctl->vtk_scale =
5534 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
5535 ctl->vtk_offset =
5536 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
5537 ctl->vtk_sphere =
5538 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
5539
5540#ifdef DD
5541 /* Controle of domain decomposition... */
5543 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1, "1",
5544 NULL);
5545 ctl->dd_subdomains_zonal =
5546 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1, "1",
5547 NULL);
5548 ctl->dd_nbr_neighbours =
5549 (int) scan_ctl(filename, argc, argv, "DD_NBR_NEIGHBOURS", -1, "8", NULL);
5550 ctl->dd_halos_size =
5551 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
5552#endif
5553
5554}
5555
5556/*****************************************************************************/
5557
5559 const char *filename,
5560 const ctl_t *ctl,
5561 const clim_t *clim,
5562 met_t *met) {
5563
5564 /* Write info... */
5565 LOG(1, "Read meteo data: %s", filename);
5566
5567 /* Set rank... */
5568 int rank = 0;
5569#ifdef MPI
5570 if (ctl->met_mpi_share)
5571 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5572#endif
5573
5574 /* Check rank... */
5575 if (!ctl->met_mpi_share || rank == 0) {
5576
5577 /* Read netCDF data... */
5578 if (ctl->met_type == 0) {
5579#ifdef DD
5580 if (read_met_nc_dd(filename, ctl, met) != 1)
5581 return 0;
5582#else
5583 if (read_met_nc(filename, ctl, met) != 1)
5584 return 0;
5585#endif
5586 }
5587
5588 /* Read binary data... */
5589 else if ((ctl->met_type >= 1 && ctl->met_type <= 5) || ctl->met_type == 7) {
5590 if (read_met_bin(filename, ctl, met) != 1)
5591 return 0;
5592 }
5593
5594#ifdef ECCODES
5595 /* Read grib data... */
5596 else if (ctl->met_type == 6) {
5597 if (read_met_grib(filename, ctl, met) != 1)
5598 return 0;
5599 }
5600#endif
5601
5602 /* Not implemented... */
5603 else
5604 ERRMSG("MET_TYPE not implemented!");
5605
5606 /* Preprocessing for netCDF and grib files... */
5607 if (ctl->met_type == 0 || ctl->met_type == 6) {
5608
5609 /* Extrapolate data for lower boundary... */
5611
5612 /* Fix polar winds... */
5614
5615 /* Create periodic boundary conditions... */
5616#ifndef DD
5617 read_met_periodic(met);
5618#endif
5619
5620 /* Downsampling... */
5621 read_met_sample(ctl, met);
5622
5623 /* Calculate geopotential heights... */
5624 read_met_geopot(ctl, met);
5625
5626 /* Calculate potential vorticity... */
5627 read_met_pv(met);
5628
5629 /* Calculate boundary layer data... */
5630 read_met_pbl(ctl, met);
5631
5632 /* Calculate tropopause data... */
5633 read_met_tropo(ctl, clim, met);
5634
5635 /* Calculate cloud properties... */
5636 read_met_cloud(met);
5637
5638 /* Calculate convective available potential energy... */
5639 read_met_cape(ctl, clim, met);
5640
5641 /* Calculate total column ozone... */
5642 read_met_ozone(met);
5643
5644 /* Detrending... */
5645 read_met_detrend(ctl, met);
5646
5647 /* Check meteo data and smooth zeta profiles ... */
5648 read_met_monotonize(ctl, met);
5649 }
5650 }
5651
5652 /* Broadcast data via MPI... */
5653#ifdef MPI
5654 if (ctl->met_mpi_share) {
5655
5656 /* Set timer... */
5657 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
5658 LOG(2, "Broadcast data on rank %d...", rank);
5659
5660 /* Broadcast... */
5661 broadcast_large_data(met, sizeof(met_t));
5662 }
5663#endif
5664
5665 /* Return success... */
5666 return 1;
5667}
5668
5669/*****************************************************************************/
5670
5671#ifdef DD
5673 ctl_t *ctl,
5674 cache_t *cache,
5675 clim_t *clim,
5676 met_t **met0,
5677 met_t **met1,
5678 atm_t *atm,
5679 double t,
5680 mpi_info_t *mpi_info) {
5681#else
5683 ctl_t *ctl,
5684 cache_t *cache,
5685 clim_t *clim,
5686 met_t **met0,
5687 met_t **met1,
5688 atm_t *atm,
5689 double t) {
5690#endif
5691 /* Initialize modules... */
5692 if (t == ctl->t_start) {
5693
5694 /* Initialize isosurface data... */
5695 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5696 module_isosurf_init(ctl, cache, *met0, *met1, atm);
5697
5698 /* Initialize advection... */
5699 module_advect_init(ctl, cache, *met0, *met1, atm);
5700
5701 /* Initialize chemistry... */
5702 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
5703 }
5704
5705 /* Set time steps of air parcels... */
5706 module_timesteps(ctl, cache, *met0, atm, t);
5707
5708#ifndef DD
5709 /* Sort particles... */
5710 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
5711 module_sort(ctl, *met0, atm);
5712#endif
5713
5714 /* Check positions (initial)... */
5715 module_position(cache, *met0, *met1, atm);
5716
5717 /* Advection... */
5718 if (ctl->advect > 0)
5719 module_advect(ctl, cache, *met0, *met1, atm);
5720
5721 /* Turbulent diffusion... */
5722 if (ctl->diffusion == 1
5723 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
5724 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
5725 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
5726 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
5727
5728 /* Mesoscale diffusion... */
5729 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
5730 module_diff_meso(ctl, cache, *met0, *met1, atm);
5731
5732 /* Diffusion... */
5733 if (ctl->diffusion == 2)
5734 module_diff_pbl(ctl, cache, *met0, *met1, atm);
5735
5736 /* Convection... */
5737 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
5738 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
5739 module_convection(ctl, cache, *met0, *met1, atm);
5740
5741 /* Sedimentation... */
5742 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
5743 module_sedi(ctl, cache, *met0, *met1, atm);
5744
5745 /* Isosurface... */
5746 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5747 module_isosurf(ctl, cache, *met0, *met1, atm);
5748
5749 /* Check positions (final)... */
5750 module_position(cache, *met0, *met1, atm);
5751
5752 /* Interpolate meteo data... */
5753 if (ctl->met_dt_out > 0
5754 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
5755 module_meteo(ctl, cache, clim, *met0, *met1, atm);
5756
5757 /* Check boundary conditions (initial)... */
5758 if ((ctl->bound_lat0 < ctl->bound_lat1)
5759 && (ctl->bound_p0 > ctl->bound_p1))
5760 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5761
5762 /* Initialize quantity of total loss rate... */
5763 if (ctl->qnt_loss_rate >= 0) {
5764 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
5765 atm->q[ctl->qnt_loss_rate][ip] = 0;
5766 }
5767 }
5768
5769 /* Decay of particle mass... */
5770 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
5771 module_decay(ctl, cache, clim, atm);
5772
5773 /* Interparcel mixing... */
5774 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
5775 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
5776 module_mixing(ctl, clim, atm, t);
5777
5778 /* Calculate the tracer vmr in the chemistry grid... */
5779 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
5780 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
5781 module_chem_grid(ctl, *met0, *met1, atm, t);
5782
5783 /* OH chemistry... */
5784 if (ctl->oh_chem_reaction != 0)
5785 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
5786
5787 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
5788 if (ctl->h2o2_chem_reaction != 0)
5789 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
5790
5791 /* First-order tracer chemistry... */
5792 if (ctl->tracer_chem)
5793 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
5794
5795 /* Domain decomposition... */
5796#ifdef DD
5798 module_dd(ctl, atm, cache, mpi_info, met0);
5799#endif
5800
5801 /* KPP chemistry... */
5802 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
5803#ifdef KPP
5804 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
5805#else
5806 ERRMSG("Code was compiled without KPP!");
5807#endif
5808 }
5809
5810 /* Wet deposition... */
5811 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
5812 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
5813 module_wet_depo(ctl, cache, *met0, *met1, atm);
5814
5815 /* Dry deposition... */
5816 if (ctl->dry_depo_vdep > 0)
5817 module_dry_depo(ctl, cache, *met0, *met1, atm);
5818
5819 /* Check boundary conditions (final)... */
5820 if ((ctl->bound_lat0 < ctl->bound_lat1)
5821 && (ctl->bound_p0 > ctl->bound_p1))
5822 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5823}
5824
5825/*****************************************************************************/
5826
5828 const ctl_t *ctl,
5829 const cache_t *cache,
5830 const clim_t *clim,
5831 met_t **met0,
5832 met_t **met1,
5833 const atm_t *atm) {
5834
5835 /* Update GPU... */
5836 if (ctl != NULL) {
5837#ifdef _OPENACC
5838 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5839#pragma acc update device(ctl[:1])
5840#endif
5841 }
5842
5843 if (cache != NULL) {
5844#ifdef _OPENACC
5845 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5846#pragma acc update device(cache[:1])
5847#endif
5848 }
5849
5850 if (clim != NULL) {
5851#ifdef _OPENACC
5852 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5853#pragma acc update device(clim[:1])
5854#endif
5855 }
5856
5857 if (met0 != NULL) {
5858#ifdef _OPENACC
5859 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5860 met_t *met0up = *met0;
5861#pragma acc update device(met0up[:1])
5862#endif
5863 }
5864
5865 if (met1 != NULL) {
5866#ifdef _OPENACC
5867 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5868 met_t *met1up = *met1;
5869#pragma acc update device(met1up[:1])
5870#endif
5871 }
5872
5873 if (atm != NULL) {
5874#ifdef _OPENACC
5875 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5876#pragma acc update device(atm[:1])
5877#endif
5878 }
5879}
5880
5881/*****************************************************************************/
5882
5884 const ctl_t *ctl,
5885 const cache_t *cache,
5886 const clim_t *clim,
5887 met_t **met0,
5888 met_t **met1,
5889 const atm_t *atm) {
5890
5891 /* Update GPU... */
5892 if (ctl != NULL) {
5893#ifdef _OPENACC
5894 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5895#pragma acc update host(ctl[:1])
5896#endif
5897 }
5898
5899 if (cache != NULL) {
5900#ifdef _OPENACC
5901 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5902#pragma acc update host(cache[:1])
5903#endif
5904 }
5905
5906 if (clim != NULL) {
5907#ifdef _OPENACC
5908 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5909#pragma acc update host(clim[:1])
5910#endif
5911 }
5912
5913 if (met0 != NULL) {
5914#ifdef _OPENACC
5915 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5916 met_t *met0up = *met0;
5917#pragma acc update host(met0up[:1])
5918#endif
5919 }
5920
5921 if (met1 != NULL) {
5922#ifdef _OPENACC
5923 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5924 met_t *met1up = *met1;
5925#pragma acc update host(met1up[:1])
5926#endif
5927 }
5928
5929 if (atm != NULL) {
5930#ifdef _OPENACC
5931 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5932#pragma acc update host(atm[:1])
5933#endif
5934 }
5935}
5936
5937/*****************************************************************************/
5938
5940 const char *filename,
5941 const ctl_t *ctl,
5942 const atm_t *atm,
5943 const double t) {
5944
5945 /* Set timer... */
5946 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
5947
5948 /* Write info... */
5949 LOG(1, "Write atmospheric data: %s", filename);
5950
5951 /* Write ASCII data... */
5952 if (ctl->atm_type_out == 0)
5953 write_atm_asc(filename, ctl, atm, t);
5954
5955 /* Write binary data... */
5956 else if (ctl->atm_type_out == 1)
5957 write_atm_bin(filename, ctl, atm);
5958
5959 /* Write netCDF data... */
5960 else if (ctl->atm_type_out == 2)
5961 write_atm_nc(filename, ctl, atm);
5962
5963 /* Write CLaMS trajectory data... */
5964 else if (ctl->atm_type_out == 3)
5965 write_atm_clams_traj(filename, ctl, atm, t);
5966
5967 /* Write CLaMS pos data... */
5968 else if (ctl->atm_type_out == 4)
5969 write_atm_clams(filename, ctl, atm);
5970
5971 /* Error... */
5972 else
5973 ERRMSG("Atmospheric data type not supported!");
5974
5975 /* Write info... */
5976 double mini, maxi;
5977 LOG(2, "Number of particles: %d", atm->np);
5978 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5979 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5980 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5981 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5982 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5983 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5984 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5985 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5986 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5987 for (int iq = 0; iq < ctl->nq; iq++) {
5988 char msg[5 * LEN];
5989 sprintf(msg, "Quantity %s range: %s ... %s %s",
5990 ctl->qnt_name[iq], ctl->qnt_format[iq],
5991 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5992 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5993 LOG(2, msg, mini, maxi);
5994 }
5995}
5996
5997/*****************************************************************************/
5998
6000 const char *filename,
6001 const ctl_t *ctl,
6002 met_t *met) {
6003
6004 /* Set timer... */
6005 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
6006
6007 /* Write info... */
6008 LOG(1, "Write meteo data: %s", filename);
6009
6010 /* Check compression flags... */
6011#ifndef ZFP
6012 if (ctl->met_type == 3)
6013 ERRMSG("MPTRAC was compiled without ZFP compression!");
6014#endif
6015#ifndef ZSTD
6016 if (ctl->met_type == 4)
6017 ERRMSG("MPTRAC was compiled without ZSTD compression!");
6018#endif
6019#ifndef CMS
6020 if (ctl->met_type == 5)
6021 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6022#endif
6023#ifndef SZ3
6024 if (ctl->met_type == 7)
6025 ERRMSG("MPTRAC was compiled without SZ3 compression!");
6026#endif
6027
6028 /* Write netCDF data... */
6029 if (ctl->met_type == 0)
6030 write_met_nc(filename, ctl, met);
6031
6032 /* Write binary data... */
6033 else if (ctl->met_type >= 1 && ctl->met_type <= 7)
6034 write_met_bin(filename, ctl, met);
6035
6036 /* Not implemented... */
6037 else
6038 ERRMSG("MET_TYPE not implemented!");
6039}
6040
6041/*****************************************************************************/
6042
6044 const char *dirname,
6045 const ctl_t *ctl,
6046 met_t *met0,
6047 met_t *met1,
6048 atm_t *atm,
6049 const double t) {
6050
6051 char ext[10], filename[2 * LEN];
6052
6053 double r;
6054
6055 int year, mon, day, hour, min, sec;
6056
6057 /* Get time... */
6058 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
6059
6060 /* Update host... */
6061 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
6062 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
6063 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
6064 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
6065 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
6066 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
6067 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
6068
6069 /* Write atmospheric data... */
6070 if (ctl->atm_basename[0] != '-' &&
6071 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
6072 if (ctl->atm_type_out == 0)
6073 sprintf(ext, "tab");
6074 else if (ctl->atm_type_out == 1)
6075 sprintf(ext, "bin");
6076 else if (ctl->atm_type_out == 2)
6077 sprintf(ext, "nc");
6078 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6079 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
6080 mptrac_write_atm(filename, ctl, atm, t);
6081 }
6082
6083 /* Write gridded data... */
6084 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
6085 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6086 dirname, ctl->grid_basename, year, mon, day, hour, min,
6087 ctl->grid_type == 0 ? "tab" : "nc");
6088 write_grid(filename, ctl, met0, met1, atm, t);
6089 }
6090
6091 /* Write CSI data... */
6092 if (ctl->csi_basename[0] != '-') {
6093 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
6094 write_csi(filename, ctl, atm, t);
6095 }
6096
6097 /* Write ensemble data... */
6098 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
6099 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
6100 dirname, ctl->ens_basename, year, mon, day, hour, min);
6101 write_ens(filename, ctl, atm, t);
6102 }
6103
6104 /* Write profile data... */
6105 if (ctl->prof_basename[0] != '-') {
6106 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
6107 write_prof(filename, ctl, met0, met1, atm, t);
6108 }
6109
6110 /* Write sample data... */
6111 if (ctl->sample_basename[0] != '-') {
6112 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
6113 write_sample(filename, ctl, met0, met1, atm, t);
6114 }
6115
6116 /* Write station data... */
6117 if (ctl->stat_basename[0] != '-') {
6118 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
6119 write_station(filename, ctl, atm, t);
6120 }
6121
6122 /* Write VTK data... */
6123 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
6124 static int nvtk;
6125 if (t == ctl->t_start)
6126 nvtk = 0;
6127 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
6128 write_vtk(filename, ctl, atm, t);
6129 }
6130}
6131
6132/*****************************************************************************/
6133
6135 const double p,
6136 const double h2o,
6137 const double hno3) {
6138
6139 /* Check water vapor volume mixing ratio... */
6140 const double h2o_help = MAX(h2o, 0.1e-6);
6141
6142 /* Calculate T_NAT... */
6143 const double p_hno3 = hno3 * p / 1.333224;
6144 const double p_h2o = h2o_help * p / 1.333224;
6145 const double a = 0.009179 - 0.00088 * log10(p_h2o);
6146 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
6147 const double c = -11397.0 / a;
6148 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
6149 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
6150 if (x2 > 0)
6151 tnat = x2;
6152
6153 return tnat;
6154}
6155
6156/*****************************************************************************/
6157
6159 const ctl_t *ctl,
6160 const atm_t *atm,
6161 const int ip,
6162 const double pbl,
6163 const double ps) {
6164
6165 /* Get pressure range... */
6166 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
6167 const double p0 = pbl;
6168
6169 /* Get weighting factor... */
6170 if (atm->p[ip] > p0)
6171 return 1;
6172 else if (atm->p[ip] < p1)
6173 return 0;
6174 else
6175 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
6176}
6177
6178/*****************************************************************************/
6179
6181 const char *filename,
6182 const ctl_t *ctl,
6183 atm_t *atm) {
6184
6185 /* Open file... */
6186 FILE *in;
6187 if (!(in = fopen(filename, "r"))) {
6188 WARN("Cannot open file!");
6189 return 0;
6190 }
6191
6192 /* Read line... */
6193 char line[LEN];
6194 while (fgets(line, LEN, in)) {
6195
6196 /* Read data... */
6197 char *tok;
6198 TOK(line, tok, "%lg", atm->time[atm->np]);
6199 TOK(NULL, tok, "%lg", atm->p[atm->np]);
6200 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
6201 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
6202 for (int iq = 0; iq < ctl->nq; iq++)
6203 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
6204
6205 /* Convert altitude to pressure... */
6206 atm->p[atm->np] = P(atm->p[atm->np]);
6207
6208 /* Increment data point counter... */
6209 if ((++atm->np) > NP)
6210 ERRMSG("Too many data points!");
6211 }
6212
6213 /* Close file... */
6214 fclose(in);
6215
6216 /* Return success... */
6217 return 1;
6218}
6219
6220/*****************************************************************************/
6221
6223 const char *filename,
6224 const ctl_t *ctl,
6225 atm_t *atm) {
6226
6227 /* Open file... */
6228 FILE *in;
6229 if (!(in = fopen(filename, "r")))
6230 return 0;
6231
6232 /* Check version of binary data... */
6233 int version;
6234 FREAD(&version, int,
6235 1,
6236 in);
6237 if (version != 100)
6238 ERRMSG("Wrong version of binary data!");
6239
6240 /* Read data... */
6241 FREAD(&atm->np, int,
6242 1,
6243 in);
6244 FREAD(atm->time, double,
6245 (size_t) atm->np,
6246 in);
6247 FREAD(atm->p, double,
6248 (size_t) atm->np,
6249 in);
6250 FREAD(atm->lon, double,
6251 (size_t) atm->np,
6252 in);
6253 FREAD(atm->lat, double,
6254 (size_t) atm->np,
6255 in);
6256 for (int iq = 0; iq < ctl->nq; iq++)
6257 FREAD(atm->q[iq], double,
6258 (size_t) atm->np,
6259 in);
6260
6261 /* Read final flag... */
6262 int final;
6263 FREAD(&final, int,
6264 1,
6265 in);
6266 if (final != 999)
6267 ERRMSG("Error while reading binary data!");
6268
6269 /* Close file... */
6270 fclose(in);
6271
6272 /* Return success... */
6273 return 1;
6274}
6275
6276/*****************************************************************************/
6277
6279 const char *filename,
6280 const ctl_t *ctl,
6281 atm_t *atm) {
6282
6283 int ncid, varid;
6284
6285 /* Open file... */
6286 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6287 return 0;
6288
6289 /* Get dimensions... */
6290 NC_INQ_DIM("NPARTS", &atm->np, 1, NP);
6291
6292 /* Get time... */
6293 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
6294 NC(nc_get_var_double(ncid, varid, atm->time));
6295 } else {
6296 WARN("TIME_INIT not found use time instead!");
6297 double time_init;
6298 NC_GET_DOUBLE("time", &time_init, 1);
6299 for (int ip = 0; ip < atm->np; ip++) {
6300 atm->time[ip] = time_init;
6301 }
6302 }
6303
6304 /* Read zeta coordinate, pressure is optional... */
6305 if (ctl->advect_vert_coord == 1) {
6306 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
6307 NC_GET_DOUBLE("PRESS", atm->p, 0);
6308 }
6309
6310 /* Read pressure, zeta coordinate is optional... */
6311 else {
6312 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
6313 NC(nc_get_var_double(ncid, varid, atm->p));
6314 } else {
6315 WARN("PRESS_INIT not found use PRESS instead!");
6316 nc_inq_varid(ncid, "PRESS", &varid);
6317 NC(nc_get_var_double(ncid, varid, atm->p));
6318 }
6319 }
6320
6321 /* Read further quantities if requested... */
6322 for (int iq = 0; iq < ctl->nq; iq++)
6323 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6324
6325 /* Read longitude and latitude... */
6326 NC_GET_DOUBLE("LON", atm->lon, 1);
6327 NC_GET_DOUBLE("LAT", atm->lat, 1);
6328
6329 /* Close file... */
6330 NC(nc_close(ncid));
6331
6332 /* Return success... */
6333 return 1;
6334}
6335
6336/*****************************************************************************/
6337
6339 const char *filename,
6340 const ctl_t *ctl,
6341 atm_t *atm) {
6342
6343 int ncid, varid;
6344
6345 /* Open file... */
6346 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6347 return 0;
6348
6349 /* Get dimensions... */
6350 NC_INQ_DIM("obs", &atm->np, 1, NP);
6351
6352 /* Read geolocations... */
6353 NC_GET_DOUBLE("time", atm->time, 1);
6354 NC_GET_DOUBLE("press", atm->p, 1);
6355 NC_GET_DOUBLE("lon", atm->lon, 1);
6356 NC_GET_DOUBLE("lat", atm->lat, 1);
6357
6358 /* Read variables... */
6359 for (int iq = 0; iq < ctl->nq; iq++)
6360 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6361
6362 /* Close file... */
6363 NC(nc_close(ncid));
6364
6365 /* Return success... */
6366 return 1;
6367}
6368
6369/*****************************************************************************/
6370
6372 const char *filename,
6373 clim_photo_t *photo) {
6374
6375 int ncid, varid;
6376
6377 /* Write info... */
6378 LOG(1, "Read photolysis rates: %s", filename);
6379
6380 /* Open netCDF file... */
6381 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6382 WARN("Photolysis rate data are missing!");
6383 return;
6384 }
6385
6386 /* Read pressure data... */
6387 NC_INQ_DIM("press", &photo->np, 2, CP);
6388 NC_GET_DOUBLE("press", photo->p, 1);
6389 if (photo->p[0] < photo->p[1])
6390 ERRMSG("Pressure data are not descending!");
6391
6392 /* Read total column ozone data... */
6393 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3);
6394 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
6395 if (photo->o3c[0] > photo->o3c[1])
6396 ERRMSG("Total column ozone data are not ascending!");
6397
6398 /* Read solar zenith angle data... */
6399 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA);
6400 NC_GET_DOUBLE("sza", photo->sza, 1);
6401 if (photo->sza[0] > photo->sza[1])
6402 ERRMSG("Solar zenith angle data are not ascending!");
6403
6404 /* Read data... */
6405 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
6406 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
6407 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
6408 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
6409 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
6410 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
6411 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
6412 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
6413 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
6414
6415 /* Close netCDF file... */
6416 NC(nc_close(ncid));
6417
6418 /* Write info... */
6419 LOG(2, "Number of pressure levels: %d", photo->np);
6420 LOG(2, "Altitude levels: %g, %g ... %g km",
6421 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
6422 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6423 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
6424 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
6425 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
6426 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
6427 RAD2DEG(photo->sza[photo->nsza - 1]));
6428 LOG(2, "Number of total column ozone values: %d", photo->no3c);
6429 LOG(2, "Total column ozone: %g, %g ... %g DU",
6430 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
6431 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
6432 photo->n2o[0][0][0], photo->n2o[1][0][0],
6433 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6434 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
6435 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
6436 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6437 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
6438 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
6439 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6440 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
6441 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
6442 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6443 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
6444 photo->o2[0][0][0], photo->o2[1][0][0],
6445 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6446 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
6447 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
6448 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6449 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
6450 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
6451 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6452 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
6453 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
6454 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6455 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
6456 photo->h2o[0][0][0], photo->h2o[1][0][0],
6457 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6458}
6459
6460/*****************************************************************************/
6461
6463 const int ncid,
6464 const char *varname,
6465 const clim_photo_t *photo,
6466 double var[CP][CSZA][CO3]) {
6467
6468 /* Allocate... */
6469 double *help;
6470 ALLOC(help, double,
6471 photo->np * photo->nsza * photo->no3c);
6472
6473 /* Read varible... */
6474 int varid;
6475 NC_GET_DOUBLE(varname, help, 1);
6476
6477 /* Copy data... */
6478 for (int ip = 0; ip < photo->np; ip++)
6479 for (int is = 0; is < photo->nsza; is++)
6480 for (int io = 0; io < photo->no3c; io++)
6481 var[ip][is][io] =
6482 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
6483
6484 /* Free... */
6485 free(help);
6486}
6487
6488/*****************************************************************************/
6489
6491 const char *filename,
6492 clim_ts_t *ts) {
6493
6494 /* Write info... */
6495 LOG(1, "Read climatological time series: %s", filename);
6496
6497 /* Open file... */
6498 FILE *in;
6499 if (!(in = fopen(filename, "r"))) {
6500 WARN("Cannot open file!");
6501 return 0;
6502 }
6503
6504 /* Read data... */
6505 char line[LEN];
6506 int nh = 0;
6507 while (fgets(line, LEN, in))
6508 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
6509
6510 /* Convert years to seconds... */
6511 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
6512
6513 /* Check data... */
6514 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
6515 ERRMSG("Time series must be ascending!");
6516
6517 /* Count time steps... */
6518 if ((++nh) >= CTS)
6519 ERRMSG("Too many data points!");
6520 }
6521
6522 /* Close file... */
6523 fclose(in);
6524
6525 /* Check number of data points... */
6526 ts->ntime = nh;
6527 if (nh < 2)
6528 ERRMSG("Not enough data points!");
6529
6530 /* Write info... */
6531 LOG(2, "Number of time steps: %d", ts->ntime);
6532 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
6533 ts->time[nh - 1]);
6534 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
6535 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
6536 (size_t) nh));
6537
6538 /* Exit success... */
6539 return 1;
6540}
6541
6542/*****************************************************************************/
6543
6545 const char *filename,
6546 const char *varname,
6547 clim_zm_t *zm) {
6548
6549 int ncid, varid, it, iy, iz, iz2, nt;
6550
6551 double *help, varmin = 1e99, varmax = -1e99;
6552
6553 /* Write info... */
6554 LOG(1, "Read %s data: %s", varname, filename);
6555
6556 /* Open netCDF file... */
6557 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6558 WARN("%s climatology data are missing!", varname);
6559 return;
6560 }
6561
6562 /* Read pressure data... */
6563 NC_INQ_DIM("press", &zm->np, 2, CP);
6564 NC_GET_DOUBLE("press", zm->p, 1);
6565 if (zm->p[0] < zm->p[1])
6566 ERRMSG("Pressure data are not descending!");
6567
6568 /* Read latitudes... */
6569 NC_INQ_DIM("lat", &zm->nlat, 2, CY);
6570 NC_GET_DOUBLE("lat", zm->lat, 1);
6571 if (zm->lat[0] > zm->lat[1])
6572 ERRMSG("Latitude data are not ascending!");
6573
6574 /* Set time data (for monthly means)... */
6575 zm->ntime = 12;
6576 zm->time[0] = 1209600.00;
6577 zm->time[1] = 3888000.00;
6578 zm->time[2] = 6393600.00;
6579 zm->time[3] = 9072000.00;
6580 zm->time[4] = 11664000.00;
6581 zm->time[5] = 14342400.00;
6582 zm->time[6] = 16934400.00;
6583 zm->time[7] = 19612800.00;
6584 zm->time[8] = 22291200.00;
6585 zm->time[9] = 24883200.00;
6586 zm->time[10] = 27561600.00;
6587 zm->time[11] = 30153600.00;
6588
6589 /* Check number of timesteps... */
6590 NC_INQ_DIM("time", &nt, 12, 12);
6591
6592 /* Read data... */
6593 ALLOC(help, double,
6594 zm->nlat * zm->np * zm->ntime);
6595 NC_GET_DOUBLE(varname, help, 1);
6596 for (it = 0; it < zm->ntime; it++)
6597 for (iz = 0; iz < zm->np; iz++)
6598 for (iy = 0; iy < zm->nlat; iy++)
6599 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
6600 free(help);
6601
6602 /* Fix data gaps... */
6603 for (it = 0; it < zm->ntime; it++)
6604 for (iy = 0; iy < zm->nlat; iy++)
6605 for (iz = 0; iz < zm->np; iz++) {
6606 if (zm->vmr[it][iz][iy] < 0) {
6607 for (iz2 = 0; iz2 < zm->np; iz2++)
6608 if (zm->vmr[it][iz2][iy] >= 0) {
6609 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6610 break;
6611 }
6612 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
6613 if (zm->vmr[it][iz2][iy] >= 0) {
6614 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6615 break;
6616 }
6617 }
6618 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
6619 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
6620 }
6621
6622 /* Close netCDF file... */
6623 NC(nc_close(ncid));
6624
6625 /* Write info... */
6626 LOG(2, "Number of time steps: %d", zm->ntime);
6627 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
6628 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
6629 LOG(2, "Number of pressure levels: %d", zm->np);
6630 LOG(2, "Altitude levels: %g, %g ... %g km",
6631 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
6632 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
6633 zm->p[1], zm->p[zm->np - 1]);
6634 LOG(2, "Number of latitudes: %d", zm->nlat);
6635 LOG(2, "Latitudes: %g, %g ... %g deg",
6636 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
6637 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
6638 varmax);
6639}
6640
6641/*****************************************************************************/
6642
6644 const char *filename,
6645 double kz[EP],
6646 double kw[EP],
6647 int *nk) {
6648
6649 /* Write info... */
6650 LOG(1, "Read kernel function: %s", filename);
6651
6652 /* Open file... */
6653 FILE *in;
6654 if (!(in = fopen(filename, "r")))
6655 ERRMSG("Cannot open file!");
6656
6657 /* Read data... */
6658 char line[LEN];
6659 int n = 0;
6660 while (fgets(line, LEN, in))
6661 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
6662 if (n > 0 && kz[n] < kz[n - 1])
6663 ERRMSG("Height levels must be ascending!");
6664 if ((++n) >= EP)
6665 ERRMSG("Too many height levels!");
6666 }
6667
6668 /* Close file... */
6669 fclose(in);
6670
6671 /* Check number of data points... */
6672 *nk = n;
6673 if (n < 2)
6674 ERRMSG("Not enough height levels!");
6675
6676 /* Normalize kernel function... */
6677 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
6678 for (int iz = 0; iz < n; iz++)
6679 kw[iz] /= kmax;
6680}
6681
6682/*****************************************************************************/
6683
6685 const char *filename,
6686 const ctl_t *ctl,
6687 met_t *met) {
6688
6689 FILE *in;
6690
6691 double r;
6692
6693 int year, mon, day, hour, min, sec;
6694
6695 /* Set timer... */
6696 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
6697
6698 /* Open file... */
6699 if (!(in = fopen(filename, "r"))) {
6700 WARN("Cannot open file!");
6701 return 0;
6702 }
6703
6704 /* Check type of binary data... */
6705 int met_type;
6706 FREAD(&met_type, int,
6707 1,
6708 in);
6709 if (met_type != ctl->met_type)
6710 ERRMSG("Wrong MET_TYPE of binary data!");
6711
6712 /* Check version of binary data... */
6713 int version;
6714 FREAD(&version, int,
6715 1,
6716 in);
6717 if (version != 103)
6718 ERRMSG("Wrong version of binary data!");
6719
6720 /* Read time... */
6721 FREAD(&met->time, double,
6722 1,
6723 in);
6724 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
6725 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
6726 met->time, year, mon, day, hour, min);
6727 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
6728 || day < 1 || day > 31 || hour < 0 || hour > 23)
6729 ERRMSG("Error while reading time!");
6730
6731 /* Read dimensions... */
6732 FREAD(&met->nx, int,
6733 1,
6734 in);
6735 LOG(2, "Number of longitudes: %d", met->nx);
6736 if (met->nx < 2 || met->nx > EX)
6737 ERRMSG("Number of longitudes out of range!");
6738
6739 FREAD(&met->ny, int,
6740 1,
6741 in);
6742 LOG(2, "Number of latitudes: %d", met->ny);
6743 if (met->ny < 2 || met->ny > EY)
6744 ERRMSG("Number of latitudes out of range!");
6745
6746 FREAD(&met->np, int,
6747 1,
6748 in);
6749 LOG(2, "Number of levels: %d", met->np);
6750 if (met->np < 2 || met->np > EP)
6751 ERRMSG("Number of levels out of range!");
6752
6753 /* Read grid... */
6754 FREAD(met->lon, double,
6755 (size_t) met->nx,
6756 in);
6757 LOG(2, "Longitudes: %g, %g ... %g deg",
6758 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
6759
6760 FREAD(met->lat, double,
6761 (size_t) met->ny,
6762 in);
6763 LOG(2, "Latitudes: %g, %g ... %g deg",
6764 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
6765
6766 FREAD(met->p, double,
6767 (size_t) met->np,
6768 in);
6769 LOG(2, "Altitude levels: %g, %g ... %g km",
6770 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
6771 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6772 met->p[0], met->p[1], met->p[met->np - 1]);
6773
6774 /* Read surface data... */
6775 read_met_bin_2d(in, met, met->ps, "PS");
6776 read_met_bin_2d(in, met, met->ts, "TS");
6777 read_met_bin_2d(in, met, met->zs, "ZS");
6778 read_met_bin_2d(in, met, met->us, "US");
6779 read_met_bin_2d(in, met, met->vs, "VS");
6780 read_met_bin_2d(in, met, met->ess, "ESS");
6781 read_met_bin_2d(in, met, met->nss, "NSS");
6782 read_met_bin_2d(in, met, met->shf, "SHF");
6783 read_met_bin_2d(in, met, met->lsm, "LSM");
6784 read_met_bin_2d(in, met, met->sst, "SST");
6785 read_met_bin_2d(in, met, met->pbl, "PBL");
6786 read_met_bin_2d(in, met, met->pt, "PT");
6787 read_met_bin_2d(in, met, met->tt, "TT");
6788 read_met_bin_2d(in, met, met->zt, "ZT");
6789 read_met_bin_2d(in, met, met->h2ot, "H2OT");
6790 read_met_bin_2d(in, met, met->pct, "PCT");
6791 read_met_bin_2d(in, met, met->pcb, "PCB");
6792 read_met_bin_2d(in, met, met->cl, "CL");
6793 read_met_bin_2d(in, met, met->plcl, "PLCL");
6794 read_met_bin_2d(in, met, met->plfc, "PLFC");
6795 read_met_bin_2d(in, met, met->pel, "PEL");
6796 read_met_bin_2d(in, met, met->cape, "CAPE");
6797 read_met_bin_2d(in, met, met->cin, "CIN");
6798 read_met_bin_2d(in, met, met->o3c, "O3C");
6799
6800 /* Read level data... */
6801 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
6802 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
6803 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
6804 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
6805 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
6806 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
6807 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
6808 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
6809 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
6810 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
6811 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
6812 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
6813 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
6814
6815 /* Read final flag... */
6816 int final;
6817 FREAD(&final, int,
6818 1,
6819 in);
6820 if (final != 999)
6821 ERRMSG("Error while reading binary data!");
6822
6823 /* Close file... */
6824 fclose(in);
6825
6826 /* Return success... */
6827 return 1;
6828}
6829
6830/*****************************************************************************/
6831
6833 FILE *in,
6834 const met_t *met,
6835 float var[EX][EY],
6836 const char *varname) {
6837
6838 float *help;
6839
6840 /* Allocate... */
6841 ALLOC(help, float,
6842 EX * EY);
6843
6844 /* Read uncompressed... */
6845 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
6846 FREAD(help, float,
6847 (size_t) (met->nx * met->ny),
6848 in);
6849
6850 /* Copy data... */
6851 for (int ix = 0; ix < met->nx; ix++)
6852 for (int iy = 0; iy < met->ny; iy++)
6853 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
6854
6855 /* Free... */
6856 free(help);
6857}
6858
6859/*****************************************************************************/
6860
6862 FILE *in,
6863 const ctl_t *ctl,
6864 const met_t *met,
6865 float var[EX][EY][EP],
6866 const char *varname,
6867 const float bound_min,
6868 const float bound_max) {
6869
6870 float *help;
6871
6872 /* Allocate... */
6873 ALLOC(help, float,
6874 EX * EY * EP);
6875
6876 /* Read uncompressed data... */
6877 if (ctl->met_type == 1) {
6878 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
6879 FREAD(help, float,
6880 (size_t) (met->nx * met->ny * met->np),
6881 in);
6882 }
6883
6884 /* Read packed data... */
6885 else if (ctl->met_type == 2)
6886 compress_pck(varname, help, (size_t) (met->ny * met->nx),
6887 (size_t) met->np, 1, in);
6888
6889 /* Read ZFP data... */
6890 else if (ctl->met_type == 3) {
6891#ifdef ZFP
6892 int precision;
6893 FREAD(&precision, int,
6894 1,
6895 in);
6896
6897 double tolerance;
6898 FREAD(&tolerance, double,
6899 1,
6900 in);
6901
6902 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
6903 tolerance, 1, in);
6904#else
6905 ERRMSG("MPTRAC was compiled without ZFP compression!");
6906#endif
6907 }
6908
6909 /* Read zstd data... */
6910 else if (ctl->met_type == 4) {
6911#ifdef ZSTD
6912 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
6913 ctl->met_zstd_level, in);
6914#else
6915 ERRMSG("MPTRAC was compiled without ZSTD compression!");
6916#endif
6917 }
6918
6919 /* Read cmultiscale data... */
6920 else if (ctl->met_type == 5) {
6921#ifdef CMS
6922 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
6923 (size_t) met->np, 1, in);
6924#else
6925 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6926#endif
6927 }
6928
6929 /* Read SZ3 data... */
6930 else if (ctl->met_type == 7) {
6931#ifdef SZ3
6932 int precision;
6933 FREAD(&precision, int,
6934 1,
6935 in);
6936
6937 double tolerance;
6938 FREAD(&tolerance, double,
6939 1,
6940 in);
6941
6942 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
6943 tolerance, 1, in);
6944#else
6945 ERRMSG("MPTRAC was compiled without sz3 compression!");
6946#endif
6947 }
6948
6949 /* Copy data... */
6950#pragma omp parallel for default(shared) collapse(2)
6951 for (int ix = 0; ix < met->nx; ix++)
6952 for (int iy = 0; iy < met->ny; iy++)
6953 for (int ip = 0; ip < met->np; ip++) {
6954 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
6955 if (var[ix][iy][ip] < bound_min)
6956 var[ix][iy][ip] = bound_min;
6957 else if (var[ix][iy][ip] > bound_max)
6958 var[ix][iy][ip] = bound_max;
6959 }
6960
6961 /* Free... */
6962 free(help);
6963}
6964
6965/*****************************************************************************/
6966
6968 const ctl_t *ctl,
6969 const clim_t *clim,
6970 met_t *met) {
6971
6972 /* Check parameters... */
6973 if (ctl->met_cape != 1)
6974 return;
6975
6976 /* Set timer... */
6977 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
6978 LOG(2, "Calculate CAPE...");
6979
6980 /* Vertical spacing (about 100 m)... */
6981 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
6982
6983 /* Loop over columns... */
6984#pragma omp parallel for default(shared) collapse(2)
6985 for (int ix = 0; ix < met->nx; ix++)
6986 for (int iy = 0; iy < met->ny; iy++) {
6987
6988 /* Get potential temperature and water vapor at lowest 50 hPa... */
6989 int n = 0;
6990 double h2o = 0, t, theta = 0;
6991 double pbot = MIN(met->ps[ix][iy], met->p[0]);
6992 double ptop = pbot - 50.;
6993 for (int ip = 0; ip < met->np; ip++) {
6994 if (met->p[ip] <= pbot) {
6995 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
6996 h2o += met->h2o[ix][iy][ip];
6997 n++;
6998 }
6999 if (met->p[ip] < ptop && n > 0)
7000 break;
7001 }
7002 theta /= n;
7003 h2o /= n;
7004
7005 /* Cannot compute anything if water vapor is missing... */
7006 met->plcl[ix][iy] = NAN;
7007 met->plfc[ix][iy] = NAN;
7008 met->pel[ix][iy] = NAN;
7009 met->cape[ix][iy] = NAN;
7010 met->cin[ix][iy] = NAN;
7011 if (h2o <= 0)
7012 continue;
7013
7014 /* Find lifted condensation level (LCL)... */
7015 ptop = P(20.);
7016 pbot = met->ps[ix][iy];
7017 do {
7018 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
7019 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
7020 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
7021 ptop = met->plcl[ix][iy];
7022 else
7023 pbot = met->plcl[ix][iy];
7024 } while (pbot - ptop > 0.1);
7025
7026 /* Calculate CIN up to LCL... */
7028 double dcape, dz, h2o_env, t_env;
7029 double p = met->ps[ix][iy];
7030 met->cape[ix][iy] = met->cin[ix][iy] = 0;
7031 do {
7032 dz = dz0 * TVIRT(t, h2o);
7033 p /= pfac;
7034 t = theta / pow(1000. / p, 0.286);
7035 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7036 &t_env, ci, cw, 1);
7037 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7038 &h2o_env, ci, cw, 0);
7039 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7040 TVIRT(t_env, h2o_env) * dz;
7041 if (dcape < 0)
7042 met->cin[ix][iy] += fabsf((float) dcape);
7043 } while (p > met->plcl[ix][iy]);
7044
7045 /* Calculate level of free convection (LFC), equilibrium level (EL),
7046 and convective available potential energy (CAPE)... */
7047 dcape = 0;
7048 p = met->plcl[ix][iy];
7049 t = theta / pow(1000. / p, 0.286);
7050 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
7051 do {
7052 dz = dz0 * TVIRT(t, h2o);
7053 p /= pfac;
7054 t -= lapse_rate(t, h2o) * dz;
7055 double psat = PSAT(t);
7056 h2o = psat / (p - (1. - EPS) * psat);
7057 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7058 &t_env, ci, cw, 1);
7059 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7060 &h2o_env, ci, cw, 0);
7061 double dcape_old = dcape;
7062 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7063 TVIRT(t_env, h2o_env) * dz;
7064 if (dcape > 0) {
7065 met->cape[ix][iy] += (float) dcape;
7066 if (!isfinite(met->plfc[ix][iy]))
7067 met->plfc[ix][iy] = (float) p;
7068 } else if (dcape_old > 0)
7069 met->pel[ix][iy] = (float) p;
7070 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
7071 met->cin[ix][iy] += fabsf((float) dcape);
7072 } while (p > ptop);
7073
7074 /* Check results... */
7075 if (!isfinite(met->plfc[ix][iy]))
7076 met->cin[ix][iy] = NAN;
7077 }
7078}
7079
7080/*****************************************************************************/
7081
7083 met_t *met) {
7084
7085 /* Set timer... */
7086 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
7087 LOG(2, "Calculate cloud data...");
7088
7089 /* Thresholds for cloud detection... */
7090 const double ccmin = 0.01, cwmin = 1e-6;
7091
7092 /* Loop over columns... */
7093#pragma omp parallel for default(shared) collapse(2)
7094 for (int ix = 0; ix < met->nx; ix++)
7095 for (int iy = 0; iy < met->ny; iy++) {
7096
7097 /* Init... */
7098 met->pct[ix][iy] = NAN;
7099 met->pcb[ix][iy] = NAN;
7100 met->cl[ix][iy] = 0;
7101
7102 /* Loop over pressure levels... */
7103 for (int ip = 0; ip < met->np - 1; ip++) {
7104
7105 /* Check pressure... */
7106 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
7107 continue;
7108
7109 /* Check ice water and liquid water content... */
7110 if (met->cc[ix][iy][ip] > ccmin
7111 && (met->lwc[ix][iy][ip] > cwmin
7112 || met->rwc[ix][iy][ip] > cwmin
7113 || met->iwc[ix][iy][ip] > cwmin
7114 || met->swc[ix][iy][ip] > cwmin)) {
7115
7116 /* Get cloud top pressure ... */
7117 met->pct[ix][iy]
7118 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
7119
7120 /* Get cloud bottom pressure ... */
7121 if (!isfinite(met->pcb[ix][iy]))
7122 met->pcb[ix][iy]
7123 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
7124 }
7125
7126 /* Get cloud water... */
7127 met->cl[ix][iy] += (float)
7128 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
7129 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
7130 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
7131 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
7132 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
7133 }
7134 }
7135}
7136
7137/*****************************************************************************/
7138
7140 const ctl_t *ctl,
7141 met_t *met) {
7142
7143 met_t *help;
7144
7145 /* Check parameters... */
7146 if (ctl->met_detrend <= 0)
7147 return;
7148
7149 /* Set timer... */
7150 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
7151 LOG(2, "Detrend meteo data...");
7152
7153 /* Allocate... */
7154 ALLOC(help, met_t, 1);
7155
7156 /* Calculate standard deviation... */
7157 const double sigma = ctl->met_detrend / 2.355;
7158 const double tssq = 2. * SQR(sigma);
7159
7160 /* Calculate box size in latitude... */
7161 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
7162 sy = MIN(MAX(1, sy), met->ny / 2);
7163
7164 /* Calculate background... */
7165#pragma omp parallel for default(shared) collapse(2)
7166 for (int ix = 0; ix < met->nx; ix++) {
7167 for (int iy = 0; iy < met->ny; iy++) {
7168
7169 /* Calculate Cartesian coordinates... */
7170 double x0[3];
7171 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
7172
7173 /* Calculate box size in longitude... */
7174 int sx =
7175 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
7176 fabs(met->lon[1] - met->lon[0]));
7177 sx = MIN(MAX(1, sx), met->nx / 2);
7178
7179 /* Init... */
7180 float wsum = 0;
7181 for (int ip = 0; ip < met->np; ip++) {
7182 help->t[ix][iy][ip] = 0;
7183 help->u[ix][iy][ip] = 0;
7184 help->v[ix][iy][ip] = 0;
7185 help->w[ix][iy][ip] = 0;
7186 }
7187
7188 /* Loop over neighboring grid points... */
7189 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
7190 int ix3 = ix2;
7191 if (ix3 < 0)
7192 ix3 += met->nx;
7193 else if (ix3 >= met->nx)
7194 ix3 -= met->nx;
7195 for (int iy2 = MAX(iy - sy, 0);
7196 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
7197
7198 /* Calculate Cartesian coordinates... */
7199 double x1[3];
7200 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
7201
7202 /* Calculate weighting factor... */
7203 const float w = (float) exp(-DIST2(x0, x1) / tssq);
7204
7205 /* Add data... */
7206 wsum += w;
7207 for (int ip = 0; ip < met->np; ip++) {
7208 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
7209 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
7210 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
7211 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
7212 }
7213 }
7214 }
7215
7216 /* Normalize... */
7217 for (int ip = 0; ip < met->np; ip++) {
7218 help->t[ix][iy][ip] /= wsum;
7219 help->u[ix][iy][ip] /= wsum;
7220 help->v[ix][iy][ip] /= wsum;
7221 help->w[ix][iy][ip] /= wsum;
7222 }
7223 }
7224 }
7225
7226 /* Subtract background... */
7227#pragma omp parallel for default(shared) collapse(3)
7228 for (int ix = 0; ix < met->nx; ix++)
7229 for (int iy = 0; iy < met->ny; iy++)
7230 for (int ip = 0; ip < met->np; ip++) {
7231 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
7232 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
7233 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
7234 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
7235 }
7236
7237 /* Free... */
7238 free(help);
7239}
7240
7241/*****************************************************************************/
7242
7244 met_t *met) {
7245
7246 /* Set timer... */
7247 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
7248 LOG(2, "Extrapolate meteo data...");
7249
7250 /* Loop over columns... */
7251#pragma omp parallel for default(shared) collapse(2)
7252 for (int ix = 0; ix < met->nx; ix++)
7253 for (int iy = 0; iy < met->ny; iy++) {
7254
7255 /* Find lowest valid data point... */
7256 int ip0;
7257 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
7258 if (!isfinite(met->t[ix][iy][ip0])
7259 || !isfinite(met->u[ix][iy][ip0])
7260 || !isfinite(met->v[ix][iy][ip0])
7261 || !isfinite(met->w[ix][iy][ip0]))
7262 break;
7263
7264 /* Extrapolate... */
7265 for (int ip = ip0; ip >= 0; ip--) {
7266 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
7267 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
7268 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
7269 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
7270 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
7271 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
7272 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
7273 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
7274 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
7275 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
7276 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
7277 }
7278 }
7279}
7280
7281/*****************************************************************************/
7282
7284 const ctl_t *ctl,
7285 met_t *met) {
7286
7287 float *help;
7288
7289 double logp[EP];
7290
7291 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
7292
7293 /* Set timer... */
7294 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
7295 LOG(2, "Calculate geopotential heights...");
7296
7297 /* Allocate... */
7298 ALLOC(help, float,
7299 EX * EY * EP);
7300
7301 /* Calculate log pressure... */
7302#pragma omp parallel for default(shared)
7303 for (int ip = 0; ip < met->np; ip++)
7304 logp[ip] = log(met->p[ip]);
7305
7306 /* Apply hydrostatic equation to calculate geopotential heights... */
7307#pragma omp parallel for default(shared) collapse(2)
7308 for (int ix = 0; ix < met->nx; ix++)
7309 for (int iy = 0; iy < met->ny; iy++) {
7310
7311 /* Get surface height and pressure... */
7312 const double zs = met->zs[ix][iy];
7313 const double lnps = log(met->ps[ix][iy]);
7314
7315 /* Get temperature and water vapor at the surface... */
7316 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
7317 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
7318 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
7319 const double h2os =
7320 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
7321 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
7322
7323 /* Upper part of profile... */
7324 met->z[ix][iy][ip0 + 1]
7325 = (float) (zs +
7326 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
7327 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
7328 for (int ip = ip0 + 2; ip < met->np; ip++)
7329 met->z[ix][iy][ip]
7330 = (float) (met->z[ix][iy][ip - 1] +
7331 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
7332 met->h2o[ix][iy][ip - 1], logp[ip],
7333 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7334
7335 /* Lower part of profile... */
7336 met->z[ix][iy][ip0]
7337 = (float) (zs +
7338 ZDIFF(lnps, ts, h2os, logp[ip0],
7339 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
7340 for (int ip = ip0 - 1; ip >= 0; ip--)
7341 met->z[ix][iy][ip]
7342 = (float) (met->z[ix][iy][ip + 1] +
7343 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
7344 met->h2o[ix][iy][ip + 1], logp[ip],
7345 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7346 }
7347
7348 /* Check control parameters... */
7349 if (dx == 0 || dy == 0)
7350 return;
7351
7352 /* Default smoothing parameters... */
7353 if (dx < 0 || dy < 0) {
7354 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
7355 dx = 3;
7356 dy = 2;
7357 } else {
7358 dx = 6;
7359 dy = 4;
7360 }
7361 }
7362
7363 /* Calculate weights for smoothing... */
7364 float ws[dx + 1][dy + 1];
7365#pragma omp parallel for default(shared) collapse(2)
7366 for (int ix = 0; ix <= dx; ix++)
7367 for (int iy = 0; iy < dy; iy++)
7368 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
7369 * (1.0f - (float) iy / (float) dy);
7370
7371 /* Copy data... */
7372#pragma omp parallel for default(shared) collapse(3)
7373 for (int ix = 0; ix < met->nx; ix++)
7374 for (int iy = 0; iy < met->ny; iy++)
7375 for (int ip = 0; ip < met->np; ip++)
7376 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
7377
7378 /* Horizontal smoothing... */
7379#pragma omp parallel for default(shared) collapse(3)
7380 for (int ip = 0; ip < met->np; ip++)
7381 for (int ix = 0; ix < met->nx; ix++)
7382 for (int iy = 0; iy < met->ny; iy++) {
7383 float res = 0, wsum = 0;
7384 int iy0 = MAX(iy - dy + 1, 0);
7385 int iy1 = MIN(iy + dy - 1, met->ny - 1);
7386 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
7387 int ix3 = ix2;
7388 if (ix3 < 0)
7389 ix3 += met->nx;
7390 else if (ix3 >= met->nx)
7391 ix3 -= met->nx;
7392 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
7393 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
7394 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
7395 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
7396 wsum += w;
7397 }
7398 }
7399 if (wsum > 0)
7400 met->z[ix][iy][ip] = res / wsum;
7401 else
7402 met->z[ix][iy][ip] = NAN;
7403 }
7404
7405 /* Free... */
7406 free(help);
7407}
7408
7409/*****************************************************************************/
7410#ifdef DD
7412 const char *filename,
7413 const int ncid,
7414 const ctl_t *ctl,
7415 met_t *met) {
7416
7417 char levname[LEN], tstr[10];
7418
7419 double rtime = 0, r, r2;
7420
7421 int varid, year2, mon2, day2, hour2, min2, sec2,
7422 year, mon, day, hour, min, sec;
7423
7424 size_t np;
7425
7426 /* Set timer... */
7427 SELECT_TIMER("READ_MET_NC_GRID_DD", "INPUT", NVTX_READ);
7428 LOG(2, "Read meteo grid information...");
7429
7430 /* MPTRAC meteo files... */
7431 if (ctl->met_clams == 0) {
7432
7433 /* Get time from filename... */
7434 met->time = time_from_filename(filename, 16);
7435
7436 /* Check time information from data file... */
7437 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7438 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
7439 NC(nc_get_var_double(ncid, varid, &rtime));
7440 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
7441 WARN("Time information in meteo file does not match filename!");
7442 } else
7443 WARN("Time information in meteo file is missing!");
7444 }
7445
7446 /* CLaMS meteo files... */
7447 else {
7448
7449 /* Read time from file... */
7450 NC_GET_DOUBLE("time", &rtime, 0);
7451
7452 /* Get time from filename (considering the century)... */
7453 if (rtime < 0)
7454 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
7455 else
7456 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
7457 year = atoi(tstr);
7458 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
7459 mon = atoi(tstr);
7460 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
7461 day = atoi(tstr);
7462 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
7463 hour = atoi(tstr);
7464 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
7465 }
7466
7467 /* Check time... */
7468 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7469 || day < 1 || day > 31 || hour < 0 || hour > 23)
7470 ERRMSG("Cannot read time from filename!");
7471 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
7472 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7473 met->time, year2, mon2, day2, hour2, min2);
7474
7475 /* Get global and local grid dimensions... */
7476 NC_INQ_DIM("lon", &met->nx_glob, 2, EX_GLOB);
7477 LOG(2, "Number of longitudes: %d", met->nx_glob);
7478 met->nx = (int) floor(met->nx_glob / ctl->dd_subdomains_zonal);
7479
7480 NC_INQ_DIM("lat", &met->ny_glob, 2, EY_GLOB);
7481 LOG(2, "Number of latitudes: %d", met->ny_glob);
7482 met->ny = (int) floor(met->ny_glob / ctl->dd_subdomains_meridional);;
7483
7484 /* Get global coordinates... */
7485 int dimid2;
7486 sprintf(levname, "lev");
7487 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7488 sprintf(levname, "plev");
7489 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7490 sprintf(levname, "hybrid");
7491
7492 NC_INQ_DIM(levname, &met->np_glob, 1, EP_GLOB);
7493 if (met->np_glob == 1) {
7494 sprintf(levname, "lev_2");
7495 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR) {
7496 sprintf(levname, "plev");
7497 NC(nc_inq_dimid(ncid, levname, &dimid2));
7498 }
7499 NC(nc_inq_dimlen(ncid, dimid2, &np));
7500 met->np_glob = (int) np;
7501 }
7502 met->np = met->np_glob;
7503
7504 LOG(2, "Number of levels: %d", met->np);
7505 if (met->np_glob < 2 || met->np_glob > EP_GLOB)
7506 ERRMSG("Number of levels out of range!");
7507
7508 /* Read longitudes and latitudes... */
7509 NC_GET_DOUBLE("lon", met->lon, 1);
7510 LOG(2, "Longitudes: %g, %g ... %g deg",
7511 met->lon[0], met->lon[1], met->lon[met->nx_glob - 1]);
7512 NC_GET_DOUBLE("lat", met->lat, 1);
7513 LOG(2, "Latitudes: %g, %g ... %g deg",
7514 met->lat[0], met->lat[1], met->lat[met->ny_glob - 1]);
7515
7516 /* Check grid spacing... */
7517 for (int ix = 2; ix < met->nx; ix++)
7518 if (fabs
7519 (fabs(met->lon[ix] - met->lon[ix - 1]) -
7520 fabs(met->lon[1] - met->lon[0])) > 0.001)
7521 ERRMSG("No regular grid spacing in longitudes!");
7522 for (int iy = 2; iy < met->ny; iy++)
7523 if (fabs
7524 (fabs(met->lat[iy] - met->lat[iy - 1]) -
7525 fabs(met->lat[1] - met->lat[0])) > 0.001) {
7526 WARN("No regular grid spacing in latitudes!");
7527 break;
7528 }
7529
7530 /* Get the MPI information... */
7531 int rank, size;
7532 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
7533 MPI_Comm_size(MPI_COMM_WORLD, &size);
7534
7535 /* Check for edge cases... */
7536 bool left = (rank <= ctl->dd_subdomains_meridional - 1);
7537 bool right = (rank >= size - ctl->dd_subdomains_meridional);
7538 bool top = (rank % ctl->dd_subdomains_meridional == 0);
7539 bool bottom =
7540 (rank % ctl->dd_subdomains_meridional ==
7541 ctl->dd_subdomains_meridional - 1);
7542
7543 /* Set the hyperslab for the subdomain... */
7544 met->subdomain_start[0] = 0;
7545 met->subdomain_start[1] = 0;
7546 met->subdomain_start[2] =
7547 (size_t) ((rank % ctl->dd_subdomains_meridional) * met->ny);
7548 met->subdomain_start[3] =
7549 (size_t) (floor(rank / ctl->dd_subdomains_meridional) * met->nx);
7550
7551 /* Extend subdomains at the right and bottom to fit the full domain. */
7552 if (right) {
7553 int gap = met->nx_glob - ctl->dd_subdomains_zonal * met->nx;
7554 if (gap > 0) {
7555 met->nx = met->nx + gap;
7556 WARN("Extended subdomains at the right to fit to full domain.");
7557 }
7558 }
7559 if (bottom) {
7560 int gap = met->ny_glob - ctl->dd_subdomains_meridional * met->ny;
7561 if (gap > 0) {
7562 met->ny = met->ny + gap;
7563 WARN("Extended subdomains at the bottom to fit to full domain.");
7564 }
7565 }
7566
7567 /* Block-size, i.e. count */
7568 met->subdomain_count[0] = 1;
7569 met->subdomain_count[1] = (size_t) met->np;
7570 met->subdomain_count[2] = (size_t) met->ny;
7571 met->subdomain_count[3] = (size_t) met->nx;
7572
7573 /* Create halos and include them into the subdomain... */
7574 if (!left && !right) {
7575 // If we are not at the left or right edge extend in zonal direction...
7576 // Move the start one point to the left...
7577 met->subdomain_count[3] =
7578 met->subdomain_count[3] + (size_t) (ctl->dd_halos_size * 2);
7579 met->subdomain_start[3] =
7580 met->subdomain_start[3] - (size_t) ctl->dd_halos_size;
7581 } else {
7582 // If we are at the left or right edge, extend only in one zonal direction...
7583 met->subdomain_count[3] =
7584 met->subdomain_count[3] + (size_t) ctl->dd_halos_size;
7585 if (!left)
7586 // If we are not at the left edge, move the start to the left...
7587 met->subdomain_start[3] =
7588 met->subdomain_start[3] - (size_t) ctl->dd_halos_size;
7589 }
7590
7591 if (!top && !bottom) {
7592 // If we are not at the upper or lower edge extend in meridional direction...
7593 // Move the start point one point down...
7594 met->subdomain_count[2] =
7595 met->subdomain_count[2] + (size_t) (ctl->dd_halos_size * 2);
7596 met->subdomain_start[2] =
7597 met->subdomain_start[2] - (size_t) ctl->dd_halos_size;
7598 } else {
7599 // If we are at the top or the lower edge only extend in one mer. direction...
7600 met->subdomain_count[2] =
7601 met->subdomain_count[2] + (size_t) ctl->dd_halos_size;
7602 if (!top)
7603 // If we are not at the top, move the start one upward...
7604 met->subdomain_start[2] =
7605 met->subdomain_start[2] - (size_t) ctl->dd_halos_size;
7606 }
7607
7608 /* Set boundary halo hyperslabs ... */
7609 double lon_shift = 0;
7610 if (left || right) {
7611
7612 met->nx = met->nx + ctl->dd_halos_size;
7613
7614 met->halo_bnd_start[0] = 0;
7615 met->halo_bnd_start[1] = 0;
7616 met->halo_bnd_start[3] = (size_t) (left ? (met->nx_glob - ctl->dd_halos_size) : (0)); //x
7617 met->halo_bnd_start[2] = met->subdomain_start[2]; //y
7618
7619 met->halo_bnd_count[0] = 1;
7620 met->halo_bnd_count[1] = (size_t) met->np;
7621 met->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
7622 met->halo_bnd_count[2] =
7623 (size_t) met->ny +
7624 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
7625
7626 met->halo_offset_start = (left ? (int) met->halo_bnd_count[3] : 0);
7627 met->halo_offset_end = (left ? 0 : (int) met->subdomain_count[3]);
7628 lon_shift = (left ? -360 : 360);
7629
7630 }
7631
7632 /* Get the range of the entire meteodata... */
7633 double lon_range = met->lon[met->nx_glob - 1] - met->lon[0];
7634 double lat_range = met->lat[met->ny_glob - 1] - met->lat[0];
7635
7636 /* Focus on subdomain longitutes and latitudes... */
7637 for (int iy = 0; iy < (int) met->subdomain_count[2]; iy++) {
7638 const int iy_ = (int) met->subdomain_start[2] + iy;
7639 met->lat[iy] = met->lat[iy_];
7640 }
7641
7642 /* Keep space at the beginning or end of the array for halo... */
7643 double help_lon[EX];
7644
7645 for (int ix = 0; ix < (int) met->subdomain_count[3]; ix++) {
7646 const int ix_ = (int) met->subdomain_start[3] + ix;
7647 help_lon[ix + met->halo_offset_start] = met->lon[ix_];
7648 }
7649
7650 for (int ix = 0; ix < (int) met->halo_bnd_count[3]; ix++) {
7651 const int ix_ = (int) met->halo_bnd_start[3] + ix;
7652 help_lon[ix + met->halo_offset_end] = met->lon[ix_] + lon_shift;
7653 }
7654
7655 /* Reset the grid dimensions... */
7656 met->nx = (int) met->subdomain_count[3] + (int) met->halo_bnd_count[3];
7657 met->ny = (int) met->subdomain_count[2];
7658 for (int ix = 0; ix < (int) met->nx; ix++)
7659 met->lon[ix] = help_lon[ix];
7660
7661 /* Determine subdomain edges... */
7662 met->subdomain_lon_min = floor(rank / ctl->dd_subdomains_meridional)
7663 * (lon_range) / (double) ctl->dd_subdomains_zonal;
7665 + (lon_range) / (double) ctl->dd_subdomains_zonal;
7666 met->subdomain_lat_max = 90 + (rank % ctl->dd_subdomains_meridional)
7667 * (lat_range) / (double) ctl->dd_subdomains_meridional;
7669 + (lat_range) / (double) ctl->dd_subdomains_meridional;
7670
7671 LOG(2, " %d Subdomain longitudes: %g, %g ... %g deg", rank,
7672 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7673 LOG(2, " %d Subdomain latitudes: %g, %g ... %g deg", rank,
7674 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7675
7676 LOG(2, "Define subdomain properties.");
7677 LOG(2, "MPI information: Rank %d, Size %d", rank, size);
7678 LOG(2, "Edge position: l=%d,r=%d,t=%d, b=%d", (int) left, (int) right,
7679 (int) top, (int) bottom);
7680 LOG(2, "Sizes for limits: EX %d EY %d EP %d", EX, EY, EP);
7681 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d", met->nx,
7682 met->ny, met->np);
7683 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
7684 (int) met->halo_bnd_count[3], (int) met->halo_bnd_count[2],
7685 (int) met->halo_bnd_count[1]);
7686 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
7687 (int) met->subdomain_count[3], (int) met->subdomain_count[2],
7688 (int) met->subdomain_count[1]);
7689 LOG(2, "Subdomain start: nx %ld ny %ld np %ld", met->subdomain_start[3],
7690 met->subdomain_start[2], met->subdomain_start[1]);
7691 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld", met->halo_bnd_start[3],
7692 met->halo_bnd_start[2], met->halo_bnd_start[1]);
7693 LOG(2, "Offsets: nx %d ny %d", met->halo_offset_start,
7694 met->halo_offset_end);
7695
7696 /* Read pressure levels... */
7697 if (ctl->met_np <= 0) {
7698 NC_GET_DOUBLE(levname, met->p, 1);
7699 for (int ip = 0; ip < met->np; ip++)
7700 met->p[ip] /= 100.;
7701 LOG(2, "Altitude levels: %g, %g ... %g km",
7702 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7703 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7704 met->p[0], met->p[1], met->p[met->np - 1]);
7705 }
7706
7707 /* Read hybrid levels... */
7708 if (strcasecmp(levname, "hybrid") == 0)
7709 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
7710}
7711#endif
7712
7713/*****************************************************************************/
7714#ifdef DD
7716 const int ncid,
7717 const ctl_t *ctl,
7718 met_t *met) {
7719
7720 /* Set timer... */
7721 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
7722 LOG(2, "Read surface data...");
7723
7724 /* Read surface pressure... */
7726 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, met->ps, 1.0f,
7727 1)) {
7728 for (int ix = 0; ix < met->nx; ix++)
7729 for (int iy = 0; iy < met->ny; iy++)
7730 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
7731 } else
7733 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, met->ps, 0.01f,
7734 1)) {
7735 WARN("Cannot not read surface pressure data (use lowest level)!");
7736 for (int ix = 0; ix < met->nx; ix++)
7737 for (int iy = 0; iy < met->ny; iy++)
7738 met->ps[ix][iy]
7739 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
7740 }
7741
7742 /* MPTRAC meteo data... */
7743 if (ctl->met_clams == 0) {
7744
7745 /* Read geopotential height at the surface... */
7747 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, met->zs,
7748 (float) (1. / (1000. * G0)), 1))
7750 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, met->zs,
7751 (float) (1. / 1000.), 1))
7752 WARN("Cannot read surface geopotential height!");
7753 }
7754
7755 /* CLaMS meteo data... */
7756 else {
7757
7758 /* Read geopotential height at the surface
7759 (use lowermost level of 3-D data field)... */
7760 float *help;
7761 ALLOC(help, float,
7762 EX * EY * EP);
7763 memcpy(help, met->pl, sizeof(met->pl));
7765 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
7766 (float) (1e-3 / G0)))
7767 ERRMSG("Cannot read geopotential height!");
7768 for (int ix = 0; ix < met->nx; ix++)
7769 for (int iy = 0; iy < met->ny; iy++)
7770 met->zs[ix][iy] = met->pl[ix][iy][0];
7771 memcpy(met->pl, help, sizeof(met->pl));
7772 free(help);
7773 }
7774
7775 /* Read temperature at the surface... */
7777 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, met->ts, 1.0, 1))
7778 WARN("Cannot read surface temperature!");
7779
7780 /* Read zonal wind at the surface... */
7782 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, met->us,
7783 1.0, 1))
7784 WARN("Cannot read surface zonal wind!");
7785
7786 /* Read meridional wind at the surface... */
7788 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, met->vs,
7789 1.0, 1))
7790 WARN("Cannot read surface meridional wind!");
7791
7792 /* Read eastward turbulent surface stress... */
7794 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, met->ess, 1.0,
7795 1))
7796 WARN("Cannot read eastward turbulent surface stress!");
7797
7798 /* Read northward turbulent surface stress... */
7800 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, met->nss, 1.0,
7801 1))
7802 WARN("Cannot read nothward turbulent surface stress!");
7803
7804 /* Read surface sensible heat flux... */
7806 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, met->shf, 1.0,
7807 1))
7808 WARN("Cannot read surface sensible heat flux!");
7809
7810 /* Read land-sea mask... */
7812 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, met->lsm, 1.0,
7813 1))
7814 WARN("Cannot read land-sea mask!");
7815
7816 /* Read sea surface temperature... */
7818 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, met->sst,
7819 1.0, 1))
7820 WARN("Cannot read sea surface temperature!");
7821
7822 /* Read PBL... */
7823 if (ctl->met_pbl == 0)
7825 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
7826 0.01f, 1))
7827 WARN("Cannot read planetary boundary layer pressure!");
7828 if (ctl->met_pbl == 1)
7830 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
7831 0.001f, 1))
7832 WARN("Cannot read planetary boundary layer height!");
7833
7834 /* Read CAPE... */
7835 if (ctl->met_cape == 0)
7837 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, met->cape,
7838 1.0, 1))
7839 WARN("Cannot read CAPE!");
7840
7841 /* Read CIN... */
7842 if (ctl->met_cape == 0)
7844 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, met->cin,
7845 1.0, 1))
7846 WARN("Cannot read convective inhibition!");
7847}
7848#endif
7849
7850/*****************************************************************************/
7851
7852#ifdef DD
7854 const int ncid,
7855 const ctl_t *ctl,
7856 met_t *met) {
7857
7858 /* Set timer... */
7859 SELECT_TIMER("READ_MET_NC_LEVELS_DD", "INPUT", NVTX_READ);
7860 LOG(2, "Read level data...");
7861
7862 /* Read temperature... */
7864 (ncid, "t", "T", "temp", "TEMP", ctl, met, met->t, 1.0))
7865 ERRMSG("Cannot read temperature!");
7866
7867 /* Read horizontal wind and vertical velocity... */
7868 if (!read_met_nc_3d_dd(ncid, "u", "U", NULL, NULL, ctl, met, met->u, 1.0))
7869 ERRMSG("Cannot read zonal wind!");
7870 if (!read_met_nc_3d_dd(ncid, "v", "V", NULL, NULL, ctl, met, met->v, 1.0))
7871 ERRMSG("Cannot read meridional wind!");
7873 (ncid, "w", "W", "omega", "OMEGA", ctl, met, met->w, 0.01f))
7874 WARN("Cannot read vertical velocity!");
7875
7876 /* Read water vapor... */
7877 if (!ctl->met_relhum) {
7879 (ncid, "q", "Q", "sh", "SH", ctl, met, met->h2o, (float) (MA / MH2O)))
7880 WARN("Cannot read specific humidity!");
7881 } else {
7883 (ncid, "rh", "RH", NULL, NULL, ctl, met, met->h2o, 0.01f))
7884 WARN("Cannot read relative humidity!");
7885#pragma omp parallel for default(shared) collapse(2)
7886 for (int ix = 0; ix < met->nx; ix++)
7887 for (int iy = 0; iy < met->ny; iy++)
7888 for (int ip = 0; ip < met->np; ip++) {
7889 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
7890 met->h2o[ix][iy][ip] =
7891 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
7892 }
7893 }
7894
7895 /* Read ozone... */
7897 (ncid, "o3", "O3", NULL, NULL, ctl, met, met->o3, (float) (MA / MO3)))
7898 WARN("Cannot read ozone data!");
7899
7900 /* Read cloud data... */
7902 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, met->lwc, 1.0))
7903 WARN("Cannot read cloud liquid water content!");
7905 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, met->rwc, 1.0))
7906 WARN("Cannot read cloud rain water content!");
7908 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, met->iwc, 1.0))
7909 WARN("Cannot read cloud ice water content!");
7911 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, met->swc, 1.0))
7912 WARN("Cannot read cloud snow water content!");
7914 (ncid, "cc", "CC", NULL, NULL, ctl, met, met->cc, 1.0))
7915 WARN("Cannot read cloud cover!");
7916
7917 /* Read zeta and zeta_dot... */
7919 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, met->zetal, 1.0))
7920 WARN("Cannot read ZETA!");
7922 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
7923 NULL, ctl, met, met->zeta_dotl, 0.00001157407f))
7924 WARN("Cannot read ZETA_DOT!");
7925
7926 /* Store velocities on model levels... */
7927 if (ctl->met_vert_coord != 0) {
7928#pragma omp parallel for default(shared)
7929 for (int ix = 0; ix < met->nx; ix++)
7930 for (int iy = 0; iy < met->ny; iy++)
7931 for (int ip = 0; ip < met->np; ip++) {
7932 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
7933 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
7934 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
7935 }
7936
7937 /* Save number of model levels... */
7938 met->npl = met->np;
7939 }
7940
7941 /* Get pressure on model levels... */
7942 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
7943
7944 /* Read 3-D pressure field... */
7945 if (ctl->met_vert_coord == 1) {
7947 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, met->pl,
7948 0.01f))
7950 (ncid, "press", "PRESS", NULL, NULL, ctl, met, met->pl, 1.0))
7951 ERRMSG("Cannot read pressure on model levels!");
7952
7953 }
7954
7955 /* Use a and b coefficients for full levels... */
7956 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
7957
7958 /* Grid level coefficients... */
7959 double hyam[EP], hybm[EP];
7960
7961 /* Read coefficients... */
7962 if (ctl->met_vert_coord == 2) {
7963 int varid;
7964 NC_GET_DOUBLE("hyam", hyam, 1);
7965 NC_GET_DOUBLE("hybm", hybm, 1);
7966 }
7967
7968 /* Use control parameters... */
7969 else if (ctl->met_vert_coord == 3) {
7970
7971 /* Check number of levels... */
7972 if (met->np != ctl->met_nlev)
7973 ERRMSG("Mismatch in number of model levels!");
7974
7975 /* Copy parameters... */
7976 for (int ip = 0; ip < met->np; ip++) {
7977 hyam[ip] = ctl->met_lev_hyam[ip];
7978 hybm[ip] = ctl->met_lev_hybm[ip];
7979 }
7980 }
7981
7982 /* Calculate pressure... */
7983 for (int ix = 0; ix < met->nx; ix++)
7984 for (int iy = 0; iy < met->ny; iy++)
7985 for (int ip = 0; ip < met->np; ip++)
7986 met->pl[ix][iy][ip] =
7987 (float) (hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy]);
7988
7989 }
7990
7991 /* Use a and b coefficients for half levels... */
7992 else if (ctl->met_vert_coord == 4) {
7993
7994 /* Grid level coefficients... */
7995 double hyam[EP], hybm[EP];
7996
7997 /* Use control parameters... */
7998 for (int ip = 0; ip < met->np + 1; ip++) {
7999 hyam[ip] = ctl->met_lev_hyam[ip];
8000 hybm[ip] = ctl->met_lev_hybm[ip];
8001 }
8002
8003 /* Check number of levels... */
8004 if (met->np + 1 != ctl->met_nlev)
8005 ERRMSG("Mismatch in number of model levels!");
8006
8007 /* Calculate pressure... */
8008#pragma omp parallel for default(shared) collapse(2)
8009 for (int ix = 0; ix < met->nx; ix++)
8010 for (int iy = 0; iy < met->ny; iy++)
8011 for (int ip = 0; ip < met->np; ip++) {
8012 const double p0 = hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy];
8013 const double p1 =
8014 hyam[ip + 1] / 100. + hybm[ip + 1] * met->ps[ix][iy];
8015 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
8016 }
8017 }
8018
8019 /* Check ordering of pressure levels... */
8020 for (int ix = 0; ix < met->nx; ix++)
8021 for (int iy = 0; iy < met->ny; iy++)
8022 for (int ip = 1; ip < met->np; ip++)
8023 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
8024 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
8025 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
8026 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
8027 ERRMSG("Pressure profiles are not monotonic!");
8028 }
8029
8030 /* Interpolate from model levels to pressure levels... */
8031 if (ctl->met_np > 0) {
8032
8033 /* Interpolate variables... */
8034 read_met_ml2pl(ctl, met, met->t, "T");
8035 read_met_ml2pl(ctl, met, met->u, "U");
8036 read_met_ml2pl(ctl, met, met->v, "V");
8037 read_met_ml2pl(ctl, met, met->w, "W");
8038 read_met_ml2pl(ctl, met, met->h2o, "H2O");
8039 read_met_ml2pl(ctl, met, met->o3, "O3");
8040 read_met_ml2pl(ctl, met, met->lwc, "LWC");
8041 read_met_ml2pl(ctl, met, met->rwc, "RWC");
8042 read_met_ml2pl(ctl, met, met->iwc, "IWC");
8043 read_met_ml2pl(ctl, met, met->swc, "SWC");
8044 read_met_ml2pl(ctl, met, met->cc, "CC");
8045
8046 /* Set new pressure levels... */
8047 met->np = ctl->met_np;
8048 for (int ip = 0; ip < met->np; ip++)
8049 met->p[ip] = ctl->met_p[ip];
8050 }
8051
8052 /* Check ordering of pressure levels... */
8053 for (int ip = 1; ip < met->np; ip++)
8054 if (met->p[ip - 1] < met->p[ip])
8055 ERRMSG("Pressure levels must be descending!");
8056
8057}
8058#endif
8059
8060/*****************************************************************************/
8061
8062#ifdef DD
8063int read_met_nc_dd(
8064 const char *filename,
8065 const ctl_t *ctl,
8066 met_t *met) {
8067
8068 int ncid;
8069
8070 /* Open netCDF file for parallel access... */
8071 #ifdef MPI
8072 int nc_result = nc_open_par(filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL, &ncid);
8073 if (nc_result != NC_NOERR) {
8074 const char* error_msg;
8075 switch(nc_result) {
8076 case NC_ENOPAR: error_msg = "Library was not built with parallel I/O features"; break;
8077 case NC_EPERM: error_msg = "No permission to access the file"; break;
8078 case NC_ENOTBUILT: error_msg = "Library was not built with NETCDF4 or PnetCDF"; break;
8079 case NC_EINVAL: error_msg = "Invalid parameters"; break;
8080 case NC_ENOTNC: error_msg = "Not a netCDF file"; break;
8081 case NC_ENOMEM: error_msg = "Out of memory"; break;
8082 case NC_EHDFERR: error_msg = "HDF5 error"; break;
8083 case NC_EDIMMETA: error_msg = "Error in netCDF-4 dimension metadata"; break;
8084 default: error_msg = nc_strerror(nc_result); break;
8085 }
8086 WARN("Cannot open file for parallel access! NetCDF error: %s (code: %d)", error_msg, nc_result);
8087 return 0;
8088 }
8089 #else
8090 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8091 WARN("Cannot open file!");
8092 return 0;
8093 }
8094 #endif
8095
8096 /* Read coordinates of meteo data... */
8097 read_met_nc_grid_dd(filename, ncid, ctl, met);
8098
8099 /* Read surface data... */
8100 read_met_nc_surface_dd(ncid, ctl, met);
8101
8102 /* Read meteo data on vertical levels... */
8103 read_met_nc_levels_dd(ncid, ctl, met);
8104
8105 /* Close file... */
8106 NC(nc_close(ncid));
8107
8108 /* Return success... */
8109 return 1;
8110}
8111#endif
8112
8113
8114/*****************************************************************************/
8115
8116#ifdef DD
8118 const int ncid,
8119 const char *varname,
8120 const char *varname2,
8121 const char *varname3,
8122 const char *varname4,
8123 const char *varname5,
8124 const char *varname6,
8125 const ctl_t *ctl,
8126 const met_t *met,
8127 float dest[EX][EY],
8128 const float scl,
8129 const int init) {
8130
8131 char varsel[LEN];
8132
8133 int varid;
8134
8135 /* Check if variable exists... */
8136 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8137 sprintf(varsel, "%s", varname);
8138 else if (varname2 != NULL
8139 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8140 sprintf(varsel, "%s", varname2);
8141 else if (varname3 != NULL
8142 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8143 sprintf(varsel, "%s", varname3);
8144 else if (varname4 != NULL
8145 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8146 sprintf(varsel, "%s", varname4);
8147 else if (varname5 != NULL
8148 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
8149 sprintf(varsel, "%s", varname5);
8150 else if (varname6 != NULL
8151 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
8152 sprintf(varsel, "%s", varname6);
8153 else
8154 return 0;
8155
8156
8157
8158 /* Read fill value and missing value... */
8159 float fillval, missval;
8160 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8161 fillval = 0;
8162 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8163 missval = 0;
8164
8165 /* Write info... */
8166 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8167 varsel, fillval, missval);
8168
8169 /* Define hyperslab... */
8170 int rank, size;
8171 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
8172 MPI_Comm_size(MPI_COMM_WORLD, &size);
8173
8174 /* Allocate... */
8175 float *help;
8176 size_t help_subdomain_start[3];
8177 size_t help_subdomain_count[3];
8178
8179 help_subdomain_start[0] = 0;
8180 help_subdomain_start[1] = met->subdomain_start[2];
8181 help_subdomain_start[2] = met->subdomain_start[3];
8182
8183 help_subdomain_count[0] = 1;
8184 help_subdomain_count[1] = met->subdomain_count[2]; //y
8185 help_subdomain_count[2] = met->subdomain_count[3]; //x
8186
8187 ALLOC(help, float,
8188 (int) met->subdomain_count[2] * (int) met->subdomain_count[3]
8189 );
8190
8191 /* Read data... */
8192 NC(nc_get_vara_float
8193 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
8194
8195 /* Read halos at boundaries... */
8196 size_t help_halo_bnd_start[3];
8197 size_t help_halo_bnd_count[3];
8198
8199 help_halo_bnd_start[0] = 0;
8200 help_halo_bnd_start[1] = met->halo_bnd_start[2];
8201 help_halo_bnd_start[2] = met->halo_bnd_start[3];
8202
8203 help_halo_bnd_count[0] = 1;
8204 help_halo_bnd_count[1] = met->halo_bnd_count[2]; //y
8205 help_halo_bnd_count[2] = met->halo_bnd_count[3]; //x
8206
8207 float *help_halo;
8208 ALLOC(help_halo, float,
8209 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
8210 NC(nc_get_vara_float
8211 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
8212
8213 /* Check meteo data layout... */
8214 if (ctl->met_convention == 0) {
8215
8216 /* Copy and check data (ordering: lat, lon)... */
8217#pragma omp parallel for default(shared) num_threads(12)
8218 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
8219 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
8220 if (init == 1)
8221 dest[ix + met->halo_offset_start][iy] = 0;
8222 const float aux =
8223 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
8224 if ((fillval == 0 || aux != fillval)
8225 && (missval == 0 || aux != missval)
8226 && fabsf(aux) < 1e14f) {
8227 dest[ix + met->halo_offset_start][iy] += scl * aux;
8228 } else
8229 dest[ix + met->halo_offset_start][iy] = NAN;
8230 }
8231
8232 /* Copy and check data (ordering: lat, lon)... */
8233#pragma omp parallel for default(shared) num_threads(12)
8234 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
8235 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
8236 if (init == 1)
8237 dest[ix + met->halo_offset_end][iy] = 0;
8238 const float aux =
8239 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
8240 if ((fillval == 0 || aux != fillval)
8241 && (missval == 0 || aux != missval)
8242 && fabsf(aux) < 1e14f)
8243 dest[ix + met->halo_offset_end][iy] += scl * aux;
8244 else {
8245 dest[ix + met->halo_offset_end][iy] = NAN;
8246 }
8247 }
8248
8249 } else {
8250
8251 /* Copy and check data (ordering: lon, lat)... */
8252#pragma omp parallel for default(shared) num_threads(12)
8253 for (int iy = 0; iy < met->ny; iy++)
8254 for (int ix = 0; ix < met->nx; ix++) {
8255 if (init)
8256 dest[ix][iy] = 0;
8257 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
8258 if ((fillval == 0 || aux != fillval)
8259 && (missval == 0 || aux != missval)
8260 && fabsf(aux) < 1e14f)
8261 dest[ix][iy] += scl * aux;
8262 else
8263 dest[ix][iy] = NAN;
8264 }
8265 }
8266
8267 /* Free... */
8268 free(help);
8269 free(help_halo);
8270
8271 /* Return... */
8272 return 1;
8273}
8274#endif
8275
8276/*****************************************************************************/
8277
8278#ifdef DD
8280 const int ncid,
8281 const char *varname,
8282 const char *varname2,
8283 const char *varname3,
8284 const char *varname4,
8285 const ctl_t *ctl,
8286 const met_t *met,
8287 float dest[EX][EY][EP],
8288 const float scl) {
8289
8290 SELECT_TIMER("READ_MET_NC_3D_DD", "INPUT", NVTX_READ);
8291
8292 char varsel[LEN];
8293
8294 int varid;
8295
8296 /* Check if variable exists... */
8297 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8298 sprintf(varsel, "%s", varname);
8299 else if (varname2 != NULL
8300 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8301 sprintf(varsel, "%s", varname2);
8302 else if (varname3 != NULL
8303 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8304 sprintf(varsel, "%s", varname3);
8305 else if (varname4 != NULL
8306 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8307 sprintf(varsel, "%s", varname4);
8308 else
8309 return 0;
8310
8311 /* Read fill value and missing value... */
8312 float fillval, missval;
8313 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8314 fillval = 0;
8315 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8316 missval = 0;
8317
8318 /* Write info... */
8319 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
8320 varsel, fillval, missval);
8321
8322 SELECT_TIMER("READ_MET_NC_3D_DD_CP1", "INPUT", NVTX_READ);
8323
8324 /* Define hyperslab... */
8325 int rank, size;
8326 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
8327 MPI_Comm_size(MPI_COMM_WORLD, &size);
8328
8329 /* Allocate... */
8330 float *help;
8331 ALLOC(help, float,
8332 (int) met->subdomain_count[0] * (int) met->subdomain_count[1]
8333 * (int) met->subdomain_count[2] * (int) met->subdomain_count[3]);
8334
8335 SELECT_TIMER("READ_MET_NC_3D_DD_CP2", "INPUT", NVTX_READ);
8336
8337 /* Use default NetCDF parallel I/O behavior */
8338 NC(nc_get_vara_float
8339 (ncid, varid, met->subdomain_start, met->subdomain_count, help));
8340
8341 /* Read halos separately at boundaries... */
8342 float *help_halo;
8343 ALLOC(help_halo, float,
8344 met->halo_bnd_count[0] * met->halo_bnd_count[1] *
8345 met->halo_bnd_count[2] * met->halo_bnd_count[3]);
8346
8347 SELECT_TIMER("READ_MET_NC_3D_DD_CP3", "INPUT", NVTX_READ);
8348
8349 /* Halo read also uses independent access */
8350 NC(nc_get_vara_float(ncid,
8351 varid,
8352 met->halo_bnd_start,
8353 met->halo_bnd_count,
8354 help_halo));
8355
8356 SELECT_TIMER("READ_MET_NC_3D_DD_CP4", "INPUT", NVTX_READ);
8357
8358 /* Check meteo data layout... */
8359 if (ctl->met_convention == 0) {
8360 /* Copy and check data (ordering: lev, lat, lon)... */
8361#pragma omp parallel for default(shared) num_threads(12)
8362 for (int ix = 0; ix < (int) met->subdomain_count[3]; ix++)
8363 for (int iy = 0; iy < (int) met->subdomain_count[2]; iy++)
8364 for (int ip = 0; ip < met->np; ip++) {
8365 const float aux =
8366 help[ARRAY_3D(ip, iy, (int) met->subdomain_count[2], ix,
8367 (int) met->subdomain_count[3])];
8368 if ((fillval == 0 || aux != fillval)
8369 && (missval == 0 || aux != missval)
8370 && fabsf(aux) < 1e14f)
8371 dest[ix + met->halo_offset_start][iy][ip] = scl * aux;
8372 else
8373 dest[ix + met->halo_offset_start][iy][ip] = NAN;
8374 }
8375
8376#pragma omp parallel for default(shared) num_threads(12)
8377 for (int ix = 0; ix < (int) met->halo_bnd_count[3]; ix++)
8378 for (int iy = 0; iy < (int) met->halo_bnd_count[2]; iy++)
8379 for (int ip = 0; ip < met->np; ip++) {
8380 const float aux =
8381 help_halo[ARRAY_3D(ip, iy, (int) met->halo_bnd_count[2], ix,
8382 (int) met->halo_bnd_count[3])];
8383 if ((fillval == 0 || aux != fillval)
8384 && (missval == 0 || aux != missval)
8385 && fabsf(aux) < 1e14f)
8386 dest[ix + met->halo_offset_end][iy][ip] = scl * aux;
8387 else
8388 dest[ix + met->halo_offset_end][iy][ip] = NAN;
8389 }
8390
8391 } else {
8392
8393 /* Copy and check data (ordering: lon, lat, lev)... */
8394#pragma omp parallel for default(shared) num_threads(12)
8395 for (int ip = 0; ip < met->np; ip++)
8396 for (int iy = 0; iy < (int) met->subdomain_count[2]; iy++)
8397 for (int ix = 0; ix < (int) met->subdomain_count[3]; ix++) {
8398 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
8399 if ((fillval == 0 || aux != fillval)
8400 && (missval == 0 || aux != missval)
8401 && fabsf(aux) < 1e14f)
8402 dest[ix + met->halo_offset_end][iy][ip] = scl * aux;
8403 else
8404 dest[ix + met->halo_offset_end][iy][ip] = NAN;
8405 }
8406
8407#pragma omp parallel for default(shared) num_threads(12)
8408 for (int ip = 0; ip < met->np; ip++)
8409 for (int iy = 0; iy < (int) met->halo_bnd_count[2]; iy++)
8410 for (int ix = 0; ix < (int) met->halo_bnd_count[3]; ix++) {
8411 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
8412 if ((fillval == 0 || aux != fillval)
8413 && (missval == 0 || aux != missval)
8414 && fabsf(aux) < 1e14f)
8415 dest[ix + met->halo_offset_start][iy][ip] = scl * aux;
8416 else
8417 dest[ix + met->halo_offset_start][iy][ip] = NAN;
8418 }
8419 }
8420
8421 /* Free... */
8422 free(help);
8423 free(help_halo);
8424
8425 /* Return... */
8426 return 1;
8427}
8428#endif
8429
8430/*****************************************************************************/
8431
8432#ifdef ECCODES
8433int read_met_grib(
8434 const char *filename,
8435 const ctl_t *ctl,
8436 met_t *met) {
8437
8438 /* Set filenames... */
8439 size_t filename_len = strlen(filename) + 1;
8440 char sf_filename[filename_len];
8441 char ml_filename[filename_len];
8442 strcpy(sf_filename, filename);
8443 strcpy(ml_filename, filename);
8444 get_met_replace(ml_filename, "XX", "ml");
8445 get_met_replace(sf_filename, "XX", "sf");
8446
8447 /* Open files... */
8448 FILE *ml_file = fopen(ml_filename, "rb");
8449 FILE *sf_file = fopen(sf_filename, "rb");
8450 if (ml_file == NULL || sf_file == NULL) {
8451 if (ml_file != NULL) {
8452 fclose(ml_file);
8453 WARN("Cannot open file: %s", sf_filename);
8454 }
8455 if (sf_file != NULL) {
8456 fclose(sf_file);
8457 WARN("Cannot open file: %s", ml_filename);
8458 }
8459 return 0;
8460 }
8461
8462 /* Get handles for model level data... */
8463 int ml_num_messages = 0, err = 0;
8464 ECC(codes_count_in_file(0, ml_file, &ml_num_messages));
8465 codes_handle **ml_handles =
8466 (codes_handle **) malloc(sizeof(codes_handle *) *
8467 (size_t) ml_num_messages);
8468 for (int i = 0; i < ml_num_messages; i++) {
8469 codes_handle *h = NULL;
8470 if ((h = codes_grib_handle_new_from_file(0, ml_file, &err)) != NULL)
8471 ml_handles[i] = h;
8472 }
8473
8474 /* Get handles for surface data... */
8475 int sf_num_messages = 0;
8476 ECC(codes_count_in_file(0, sf_file, &sf_num_messages));
8477 codes_handle **sf_handles =
8478 (codes_handle **) malloc(sizeof(codes_handle *) *
8479 (size_t) sf_num_messages);
8480 for (int i = 0; i < sf_num_messages; i++) {
8481 codes_handle *h = NULL;
8482 if ((h = codes_grib_handle_new_from_file(0, sf_file, &err)) != NULL)
8483 sf_handles[i] = h;
8484 }
8485
8486 /* Close files... */
8487 fclose(ml_file);
8488 fclose(sf_file);
8489
8490 /* Read grid data... */
8491 read_met_grib_grid(ml_handles, ml_num_messages, met);
8492
8493 /* Read surface data... */
8494 read_met_grib_surface(sf_handles, sf_num_messages, ctl, met);
8495 for (int i = 0; i < sf_num_messages; i++)
8496 codes_handle_delete(sf_handles[i]);
8497 free(sf_handles);
8498
8499 /* Compute 3D pressure field... */
8500 size_t value_count = 0;
8501 ECC(codes_get_size(ml_handles[0], "pv", &value_count));
8502 if (value_count % 2 != 0)
8503 ERRMSG("Unexpected pv array length!");
8504 size_t nlevels = value_count / 2 - 1; /* number of full model levels */
8505 double *values;
8506 ALLOC(values, double,
8507 value_count);
8508 ECC(codes_get_double_array(ml_handles[0], "pv", values, &value_count));
8509 double *a_vals = values;
8510 double *b_vals = values + nlevels;
8511 if (met->npl > (int) nlevels)
8512 ERRMSG("met->npl exceeds number of pressure levels in GRIB!");
8513 for (int nx = 0; nx < met->nx; nx++)
8514 for (int ny = 0; ny < met->ny; ny++)
8515 for (int level = 0; level <= met->npl; level++) {
8516 const float p1 = (float) (a_vals[level] * 0.01f +
8517 met->ps[nx][ny] * b_vals[level]);
8518 const float p2 = (float) (a_vals[level + 1] * 0.01f +
8519 met->ps[nx][ny] * b_vals[level + 1]);
8520 met->pl[nx][ny][level] = 0.5f * (p1 + p2);
8521 }
8522 free(values);
8523
8524 /* Read model level data... */
8525 read_met_grib_levels(ml_handles, ml_num_messages, ctl, met);
8526 for (int i = 0; i < ml_num_messages; i++)
8527 codes_handle_delete(ml_handles[i]);
8528 free(ml_handles);
8529
8530 /* Return success... */
8531 return 1;
8532}
8533#endif
8534
8535/*****************************************************************************/
8536
8537#ifdef ECCODES
8538void read_met_grib_grid(
8539 codes_handle **handles,
8540 int count_handles,
8541 met_t *met) {
8542
8543 /* Set timer... */
8544 SELECT_TIMER("READ_MET_GRIB_GRID", "INPUT", NVTX_READ);
8545 LOG(2, "Read meteo grid information...");
8546
8547 /* Read date and time... */
8548 char datestr[LEN], timestr[LEN];
8549 size_t s_date = sizeof(datestr);
8550 ECC(codes_get_string(handles[0], "dataDate", datestr, &s_date));
8551 size_t s_time = sizeof(timestr);
8552 ECC(codes_get_string(handles[0], "dataTime", timestr, &s_time));
8553 int year, month, day, hour;
8554 if (sscanf(datestr, "%4d%2d%2d", &year, &month, &day) != 3)
8555 ERRMSG("Failed to parse dataDate: %s", datestr);
8556 if (sscanf(timestr, "%2d", &hour) != 1)
8557 ERRMSG("Failed to parse dataTime: %s", timestr);
8558 time2jsec(year, month, day, hour, 0, 0, 0, &(met->time));
8559 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)", met->time, year, month,
8560 day, hour, 0);
8561
8562 /* Read grid information... */
8563 long count_lat = 0, count_lon = 0;
8564 ECC(codes_get_long(handles[0], "Nj", &count_lat));
8565 ECC(codes_get_long(handles[0], "Ni", &count_lon));
8566 met->ny = (int) count_lat;
8567 met->nx = (int) count_lon;
8568
8569 /* Check grid dimensions... */
8570 LOG(2, "Number of longitudes: %d", met->nx);
8571 if (met->nx < 2 || met->nx > EX)
8572 ERRMSG("Number of longitudes out of range!");
8573 LOG(2, "Number of latitudes: %d", met->ny);
8574 if (met->ny < 2 || met->ny > EY)
8575 ERRMSG("Number of latitudes out of range!");
8576
8577 double first_lon, last_lon, first_lat, last_lat, inc_lon, inc_lat;
8578 ECC(codes_get_double
8579 (handles[0], "longitudeOfFirstGridPointInDegrees", &first_lon));
8580 ECC(codes_get_double
8581 (handles[0], "latitudeOfFirstGridPointInDegrees", &first_lat));
8582 ECC(codes_get_double
8583 (handles[0], "longitudeOfLastGridPointInDegrees", &last_lon));
8584 ECC(codes_get_double
8585 (handles[0], "latitudeOfLastGridPointInDegrees", &last_lat));
8586 ECC(codes_get_double(handles[0], "iDirectionIncrementInDegrees", &inc_lon));
8587 ECC(codes_get_double(handles[0], "jDirectionIncrementInDegrees", &inc_lat));
8588
8589 long jscanpos, iscanneg;
8590 ECC(codes_get_long(handles[0], "iScansNegatively", &iscanneg));
8591 ECC(codes_get_long(handles[0], "jScansPositively", &jscanpos));
8592
8593 /* Compute longitude-latitude grid... */
8594 int counter = 0;
8595 if (iscanneg == 0)
8596 for (double i = first_lon; i <= last_lon + 1e-6; i += inc_lon) {
8597 met->lon[counter] = i;
8598 counter++;
8599 } else
8600 for (double i = first_lon; i > last_lon - 1e-6; i -= inc_lon) {
8601 met->lon[counter] = i;
8602 counter++;
8603 }
8604
8605 counter = 0;
8606 if (jscanpos == 0)
8607 for (double i = first_lat; i > last_lat - 1e-6; i -= inc_lat) {
8608 met->lat[counter] = i;
8609 counter++;
8610 } else
8611 for (double i = first_lat; i <= last_lat + 1e-6; i += inc_lat) {
8612 met->lat[counter] = i;
8613 counter++;
8614 }
8615
8616 /* Write info... */
8617 LOG(2, "Longitudes: %g, %g ... %g deg",
8618 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
8619 LOG(2, "Latitudes: %g, %g ... %g deg",
8620 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
8621
8622 /* Read vertical levels... */
8623 int max_level = 0;
8624 for (int i = 0; i < count_handles; i++) {
8625 long level;
8626 ECC(codes_get_long(handles[i], "level", &level));
8627 if (level > max_level)
8628 max_level = (int) level;
8629 }
8630 met->npl = max_level;
8631
8632 /* Check number of levels... */
8633 LOG(2, "Number of levels: %d", met->npl);
8634 if (met->npl < 2 || met->npl > EP)
8635 ERRMSG("Number of levels out of range!");
8636}
8637#endif
8638
8639/*****************************************************************************/
8640
8641#ifdef ECCODES
8642void read_met_grib_levels(
8643 codes_handle **handles,
8644 const int num_messages,
8645 const ctl_t *ctl,
8646 met_t *met) {
8647
8648 /* Set timer... */
8649 SELECT_TIMER("READ_MET_GRIB_LEVELS", "INPUT", NVTX_READ);
8650 LOG(2, "Read level data...");
8651
8652 /* Init... */
8653 int t_flag = 0, u_flag = 0, v_flag = 0, w_flag = 0, o3_flag = 0, h2o_flag =
8654 0, lwc_flag = 0, rwc_flag = 0, iwc_flag = 0, swc_flag = 0, cc_flag = 0;
8655
8656 /* Iterate over all messages... */
8657 for (int i = 0; i < num_messages; i++) {
8658
8659 size_t max_size = LEN;
8660 char short_name[max_size];
8661 size_t value_count;
8662 double *values;
8663
8664 /* Get the current level */
8665 long current_level;
8666 ECC(codes_get_long(handles[i], "level", &current_level));
8667 current_level -= 1;
8668
8669 /* Retrieve data from current message */
8670 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
8671 ECC(codes_get_size(handles[i], "values", &value_count));
8672 ALLOC(values, double,
8673 value_count);
8674 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
8675
8676 /* Read temperature... */
8677 ECC_READ_3D("t", current_level, met->t, 1.0, t_flag);
8678
8679 /* Read horizontal wind and vertical velocity... */
8680 ECC_READ_3D("u", current_level, met->u, 1.0, u_flag);
8681 ECC_READ_3D("v", current_level, met->v, 1.0, v_flag);
8682 ECC_READ_3D("w", current_level, met->w, 0.01f, w_flag);
8683
8684 /* Read water vapor and ozone... */
8685 ECC_READ_3D("q", current_level, met->h2o, (float) (MA / MH2O), h2o_flag);
8686 ECC_READ_3D("o3", current_level, met->o3, (float) (MA / MO3), o3_flag);
8687
8688 /* Read cloud data... */
8689 ECC_READ_3D("clwc", current_level, met->lwc, 1.0, lwc_flag);
8690 ECC_READ_3D("crwc", current_level, met->rwc, 1.0, rwc_flag);
8691 ECC_READ_3D("ciwc", current_level, met->iwc, 1.0, iwc_flag);
8692 ECC_READ_3D("cswc", current_level, met->swc, 1.0, swc_flag);
8693 ECC_READ_3D("cc", current_level, met->cc, 1.0, cc_flag);
8694
8695 /*Free allocated array */
8696 free(values);
8697 }
8698
8699 /* Check whether data were found... */
8700 if (t_flag != met->npl)
8701 ERRMSG("Cannot read temperature!");
8702 if (u_flag != met->npl)
8703 ERRMSG("Cannot read zonal wind!");
8704 if (v_flag != met->npl)
8705 ERRMSG("Cannot read meridional wind!");
8706 if (w_flag != met->npl)
8707 WARN("Cannot read vertical velocity!");
8708 if (h2o_flag != met->npl)
8709 WARN("Cannot read specific humidity!");
8710 if (o3_flag != met->npl)
8711 WARN("Cannot read ozone data!");
8712 if (lwc_flag != met->npl)
8713 WARN("Cannot read cloud liquid water content!");
8714 if (rwc_flag != met->npl)
8715 WARN("Cannot read cloud rain water content!");
8716 if (iwc_flag != met->npl)
8717 WARN("Cannot read cloud ice water content!");
8718 if (swc_flag != met->npl)
8719 WARN("Cannot read cloud snow water content!");
8720 if (cc_flag != met->npl)
8721 WARN("Cannot read cloud cover!");
8722
8723 /* Check ordering of pressure levels... */
8724 for (int ix = 0; ix < met->nx; ix++)
8725 for (int iy = 0; iy < met->ny; iy++)
8726 for (int ip = 1; ip < met->np; ip++)
8727 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
8728 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
8729 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
8730 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip])) {
8731 LOG(1, "%f %f %f %f", met->pl[ix][iy][0], met->pl[ix][iy][1],
8732 met->pl[ix][iy][ip - 1], met->pl[ix][iy][ip]);
8733 ERRMSG("Pressure profiles are not monotonic!");
8734 }
8735
8736 /* Interpolate from model levels to pressure levels... */
8737 if (ctl->met_np > 0) {
8738 met->np = ctl->met_np;
8739
8740 /* Interpolate variables... */
8741 read_met_ml2pl(ctl, met, met->t, "T");
8742 read_met_ml2pl(ctl, met, met->u, "U");
8743 read_met_ml2pl(ctl, met, met->v, "V");
8744 read_met_ml2pl(ctl, met, met->w, "W");
8745 read_met_ml2pl(ctl, met, met->h2o, "H2O");
8746 read_met_ml2pl(ctl, met, met->o3, "O3");
8747 read_met_ml2pl(ctl, met, met->lwc, "LWC");
8748 read_met_ml2pl(ctl, met, met->rwc, "RWC");
8749 read_met_ml2pl(ctl, met, met->iwc, "IWC");
8750 read_met_ml2pl(ctl, met, met->swc, "SWC");
8751 read_met_ml2pl(ctl, met, met->cc, "CC");
8752
8753 /* Set new pressure levels... */
8754 for (int ip = 0; ip < met->np; ip++)
8755 met->p[ip] = ctl->met_p[ip];
8756 }
8757
8758 /* Check ordering of pressure levels... */
8759 for (int ip = 1; ip < met->np; ip++)
8760 if (met->p[ip - 1] < met->p[ip])
8761 ERRMSG("Pressure levels must be descending!");
8762}
8763#endif
8764
8765/*****************************************************************************/
8766
8767#ifdef ECCODES
8768void read_met_grib_surface(
8769 codes_handle **handles,
8770 const int num_messages,
8771 const ctl_t *ctl,
8772 met_t *met) {
8773
8774 /* Set timer... */
8775 SELECT_TIMER("READ_MET_GRIB_SURFACE", "INPUT", NVTX_READ);
8776 LOG(2, "Read surface data...");
8777
8778 /* Init... */
8779 int sp_flag = 0, z_flag = 0, t_flag = 0, u_flag = 0, v_flag = 0, lsm_flag =
8780 0, sst_flag = 0, cape_flag = 0, cin_flag = 0, pbl_flag = 0;
8781
8782 /* Iterate over all messages... */
8783 for (int i = 0; i < num_messages; i++) {
8784
8785 size_t max_size = LEN, value_count;
8786
8787 char short_name[max_size];
8788
8789 /* Store values with shortname... */
8790 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
8791 ECC(codes_get_size(handles[i], "values", &value_count));
8792 double *values = (double *) malloc(value_count * sizeof(double));
8793 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
8794
8795 /*Read surface pressure... */
8796 ECC_READ_2D("sp", met->ps, 0.01f, sp_flag);
8797
8798 /*Read geopotential height at the surface... */
8799 ECC_READ_2D("z", met->zs, (float) (1. / (1000. * G0)), z_flag);
8800
8801 /* Read temperature at the surface... */
8802 ECC_READ_2D("2t", met->ts, 1.0f, t_flag);
8803
8804 /* Read zonal wind at the surface... */
8805 ECC_READ_2D("10u", met->us, 1.0f, u_flag);
8806
8807 /* Read meridional wind at the surface... */
8808 ECC_READ_2D("10v", met->vs, 1.0f, v_flag);
8809
8810 /* Read land-sea mask... */
8811 ECC_READ_2D("lsm", met->lsm, 1.0f, lsm_flag);
8812
8813 /* Read sea surface temperature... */
8814 ECC_READ_2D("sst", met->sst, 1.0f, sst_flag);
8815 if (ctl->met_cape == 0) {
8816
8817 /* Read CAPE... */
8818 ECC_READ_2D("cape", met->cape, 1.0f, cape_flag);
8819
8820 /* Read CIN... */
8821 ECC_READ_2D("cin", met->cin, 1.0f, cin_flag);
8822 }
8823
8824 /* Read PBL... */
8825 if (ctl->met_pbl == 0)
8826 ECC_READ_2D("blh", met->pbl, 0.0001f, pbl_flag);
8827 }
8828
8829 /* Check whether data have been read... */
8830 if (sp_flag == 0)
8831 WARN("Cannot read surface pressure data!");
8832 if (z_flag == 0)
8833 WARN("Cannot read surface geopotential height!");
8834 if (t_flag == 0)
8835 WARN("Cannot read surface temperature!");
8836 if (u_flag == 0)
8837 WARN("Cannot read surface zonal wind!");
8838 if (v_flag == 0)
8839 WARN("Cannot read surface meridional wind!");
8840 if (lsm_flag == 0)
8841 WARN("Cannot read land-sea mask!");
8842 if (sst_flag == 0)
8843 WARN("Cannot read sea surface temperature!");
8844 if (ctl->met_cape == 0) {
8845 if (cape_flag == 0)
8846 WARN("Cannot read CAPE!");
8847 if (cin_flag == 0)
8848 WARN("Cannot read convective inhibition!");
8849 }
8850 if (ctl->met_pbl == 0 && pbl_flag == 0)
8851 WARN("Cannot read planetary boundary layer!");
8852}
8853#endif
8854
8855/*****************************************************************************/
8856
8858 const ctl_t *ctl,
8859 const met_t *met,
8860 float var[EX][EY][EP],
8861 const char *varname) {
8862
8863 double aux[EP], p[EP];
8864
8865 /* Set timer... */
8866 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
8867 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
8868
8869 /* Loop over columns... */
8870#pragma omp parallel for default(shared) private(aux,p) collapse(2)
8871 for (int ix = 0; ix < met->nx; ix++)
8872 for (int iy = 0; iy < met->ny; iy++) {
8873
8874 /* Copy pressure profile... */
8875 for (int ip = 0; ip < met->np; ip++)
8876 p[ip] = met->pl[ix][iy][ip];
8877
8878 /* Interpolate... */
8879 for (int ip = 0; ip < ctl->met_np; ip++) {
8880 double pt = ctl->met_p[ip];
8881 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
8882 pt = p[0];
8883 else if ((pt > p[met->np - 1] && p[1] > p[0])
8884 || (pt < p[met->np - 1] && p[1] < p[0]))
8885 pt = p[met->np - 1];
8886 const int ip2 = locate_irr(p, met->np, pt);
8887 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
8888 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
8889 }
8890
8891 /* Copy data... */
8892 for (int ip = 0; ip < ctl->met_np; ip++)
8893 var[ix][iy][ip] = (float) aux[ip];
8894 }
8895}
8896
8897/*****************************************************************************/
8898
8900 const ctl_t *ctl,
8901 met_t *met) {
8902
8903 /* Check parameters... */
8904 if (ctl->advect_vert_coord != 1)
8905 return;
8906
8907 /* Set timer... */
8908 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
8909 LOG(2, "Make zeta profiles monotone...");
8910
8911 /* Create monotone zeta profiles... */
8912#pragma omp parallel for default(shared) collapse(2)
8913 for (int i = 0; i < met->nx; i++)
8914 for (int j = 0; j < met->ny; j++) {
8915 int k = 1;
8916
8917 while (k < met->npl) { /* Check if there is an inversion at level k... */
8918 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
8919 /* Find the upper level k+l over the inversion... */
8920 int l = 0;
8921 do {
8922 l++;
8923 }
8924 while ((met->zetal[i][j][k - 1] >=
8925 met->zetal[i][j][k + l]) & (k + l < met->npl));
8926
8927 /* Interpolate linear between the top and bottom
8928 of the inversion... */
8929 float s =
8930 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
8931 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
8932
8933 for (int m = k; m < k + l; m++) {
8934 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
8935 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
8936 }
8937
8938 /* Search for more inversions above the last inversion ... */
8939 k = k + l;
8940 } else {
8941 k++;
8942 }
8943 }
8944 }
8945
8946 /* Create monotone pressure profiles... */
8947#pragma omp parallel for default(shared) collapse(2)
8948 for (int i = 0; i < met->nx; i++)
8949 for (int j = 0; j < met->ny; j++) {
8950 int k = 1;
8951
8952 while (k < met->npl) { /* Check if there is an inversion at level k... */
8953 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
8954
8955 /* Find the upper level k+l over the inversion... */
8956 int l = 0;
8957 do {
8958 l++;
8959 }
8960 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
8961 met->npl));
8962
8963 /* Interpolate linear between the top and bottom
8964 of the inversion... */
8965 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
8966 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
8967
8968 for (int m = k; m < k + l; m++) {
8969 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
8970 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
8971 }
8972
8973 /* Search for more inversions above the last inversion ... */
8974 k += l;
8975 } else {
8976 k++;
8977 }
8978 }
8979 }
8980}
8981
8982/*****************************************************************************/
8983
8985 const char *filename,
8986 const ctl_t *ctl,
8987 met_t *met) {
8988
8989 int ncid;
8990
8991 /* Open netCDF file... */
8992 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8993 WARN("Cannot open file!");
8994 return 0;
8995 }
8996
8997 /* Read coordinates of meteo data... */
8998 read_met_nc_grid(filename, ncid, ctl, met);
8999
9000 /* Read surface data... */
9001 read_met_nc_surface(ncid, ctl, met);
9002
9003 /* Read meteo data on vertical levels... */
9004 read_met_nc_levels(ncid, ctl, met);
9005
9006 /* Close file... */
9007 NC(nc_close(ncid));
9008
9009 /* Return success... */
9010 return 1;
9011}
9012
9013/*****************************************************************************/
9014
9016 const int ncid,
9017 const char *varname,
9018 const char *varname2,
9019 const char *varname3,
9020 const char *varname4,
9021 const char *varname5,
9022 const char *varname6,
9023 const ctl_t *ctl,
9024 const met_t *met,
9025 float dest[EX][EY],
9026 const float scl,
9027 const int init) {
9028
9029 char varsel[LEN];
9030
9031 float offset, scalfac;
9032
9033 int varid;
9034
9035 /* Check if variable exists... */
9036 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
9037 sprintf(varsel, "%s", varname);
9038 else if (varname2 != NULL
9039 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
9040 sprintf(varsel, "%s", varname2);
9041 else if (varname3 != NULL
9042 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
9043 sprintf(varsel, "%s", varname3);
9044 else if (varname4 != NULL
9045 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
9046 sprintf(varsel, "%s", varname4);
9047 else if (varname5 != NULL
9048 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
9049 sprintf(varsel, "%s", varname5);
9050 else if (varname6 != NULL
9051 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
9052 sprintf(varsel, "%s", varname6);
9053 else
9054 return 0;
9055
9056 /* Read packed data... */
9057 if (ctl->met_nc_scale
9058 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
9059 && nc_get_att_float(ncid, varid, "scale_factor",
9060 &scalfac) == NC_NOERR) {
9061
9062 /* Allocate... */
9063 short *help;
9064 ALLOC(help, short,
9065 EX * EY * EP);
9066
9067 /* Read fill value and missing value... */
9068 short fillval, missval;
9069 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9070 fillval = 0;
9071 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9072 missval = 0;
9073
9074 /* Write info... */
9075 LOG(2, "Read 2-D variable: %s"
9076 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9077 varsel, fillval, missval, scalfac, offset);
9078
9079 /* Read data... */
9080 NC(nc_get_var_short(ncid, varid, help));
9081
9082 /* Check meteo data layout... */
9083 if (ctl->met_convention != 0)
9084 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9085
9086 /* Copy and check data... */
9087 omp_set_dynamic(1);
9088#pragma omp parallel for default(shared)
9089 for (int ix = 0; ix < met->nx; ix++)
9090 for (int iy = 0; iy < met->ny; iy++) {
9091 if (init)
9092 dest[ix][iy] = 0;
9093 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
9094 if ((fillval == 0 || aux != fillval)
9095 && (missval == 0 || aux != missval)
9096 && fabsf(aux * scalfac + offset) < 1e14f)
9097 dest[ix][iy] += scl * (aux * scalfac + offset);
9098 else
9099 dest[ix][iy] = NAN;
9100 }
9101 omp_set_dynamic(0);
9102
9103 /* Free... */
9104 free(help);
9105 }
9106
9107 /* Unpacked data... */
9108 else {
9109
9110 /* Allocate... */
9111 float *help;
9112 ALLOC(help, float,
9113 EX * EY);
9114
9115 /* Read fill value and missing value... */
9116 float fillval, missval;
9117 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9118 fillval = 0;
9119 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9120 missval = 0;
9121
9122 /* Write info... */
9123 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
9124 varsel, fillval, missval);
9125
9126 /* Read data... */
9127 NC(nc_get_var_float(ncid, varid, help));
9128
9129 /* Check meteo data layout... */
9130 if (ctl->met_convention == 0) {
9131
9132 /* Copy and check data (ordering: lat, lon)... */
9133 omp_set_dynamic(1);
9134#pragma omp parallel for default(shared)
9135 for (int ix = 0; ix < met->nx; ix++)
9136 for (int iy = 0; iy < met->ny; iy++) {
9137 if (init)
9138 dest[ix][iy] = 0;
9139 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
9140 if ((fillval == 0 || aux != fillval)
9141 && (missval == 0 || aux != missval)
9142 && fabsf(aux) < 1e14f)
9143 dest[ix][iy] += scl * aux;
9144 else
9145 dest[ix][iy] = NAN;
9146 }
9147 omp_set_dynamic(0);
9148
9149 } else {
9150
9151 /* Copy and check data (ordering: lon, lat)... */
9152 omp_set_dynamic(1);
9153#pragma omp parallel for default(shared)
9154 for (int iy = 0; iy < met->ny; iy++)
9155 for (int ix = 0; ix < met->nx; ix++) {
9156 if (init)
9157 dest[ix][iy] = 0;
9158 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
9159 if ((fillval == 0 || aux != fillval)
9160 && (missval == 0 || aux != missval)
9161 && fabsf(aux) < 1e14f)
9162 dest[ix][iy] += scl * aux;
9163 else
9164 dest[ix][iy] = NAN;
9165 }
9166 omp_set_dynamic(0);
9167 }
9168
9169 /* Free... */
9170 free(help);
9171 }
9172
9173 /* Return... */
9174 return 1;
9175}
9176
9177/*****************************************************************************/
9178
9180 const int ncid,
9181 const char *varname,
9182 const char *varname2,
9183 const char *varname3,
9184 const char *varname4,
9185 const ctl_t *ctl,
9186 const met_t *met,
9187 float dest[EX][EY][EP],
9188 const float scl) {
9189
9190 char varsel[LEN];
9191
9192 float offset, scalfac;
9193
9194 int varid;
9195
9196 /* Check if variable exists... */
9197 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
9198 sprintf(varsel, "%s", varname);
9199 else if (varname2 != NULL
9200 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
9201 sprintf(varsel, "%s", varname2);
9202 else if (varname3 != NULL
9203 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
9204 sprintf(varsel, "%s", varname3);
9205 else if (varname4 != NULL
9206 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
9207 sprintf(varsel, "%s", varname4);
9208 else
9209 return 0;
9210
9211 /* Read packed data... */
9212 if (ctl->met_nc_scale
9213 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
9214 && nc_get_att_float(ncid, varid, "scale_factor",
9215 &scalfac) == NC_NOERR) {
9216
9217 /* Allocate... */
9218 short *help;
9219 ALLOC(help, short,
9220 EX * EY * EP);
9221
9222 /* Read fill value and missing value... */
9223 short fillval, missval;
9224 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9225 fillval = 0;
9226 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9227 missval = 0;
9228
9229 /* Write info... */
9230 LOG(2, "Read 3-D variable: %s "
9231 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9232 varsel, fillval, missval, scalfac, offset);
9233
9234 /* Read data... */
9235 NC(nc_get_var_short(ncid, varid, help));
9236
9237 /* Check meteo data layout... */
9238 if (ctl->met_convention != 0)
9239 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9240
9241 /* Copy and check data... */
9242 omp_set_dynamic(1);
9243#pragma omp parallel for default(shared)
9244 for (int ix = 0; ix < met->nx; ix++)
9245 for (int iy = 0; iy < met->ny; iy++)
9246 for (int ip = 0; ip < met->np; ip++) {
9247 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9248 if ((fillval == 0 || aux != fillval)
9249 && (missval == 0 || aux != missval)
9250 && fabsf(aux * scalfac + offset) < 1e14f)
9251 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
9252 else
9253 dest[ix][iy][ip] = NAN;
9254 }
9255 omp_set_dynamic(0);
9256
9257 /* Free... */
9258 free(help);
9259 }
9260
9261 /* Unpacked data... */
9262 else {
9263
9264 /* Allocate... */
9265 float *help;
9266 ALLOC(help, float,
9267 EX * EY * EP);
9268
9269 /* Read fill value and missing value... */
9270 float fillval, missval;
9271 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9272 fillval = 0;
9273 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9274 missval = 0;
9275
9276 /* Write info... */
9277 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9278 varsel, fillval, missval);
9279
9280 /* Read data... */
9281 NC(nc_get_var_float(ncid, varid, help));
9282
9283 /* Check meteo data layout... */
9284 if (ctl->met_convention == 0) {
9285
9286 /* Copy and check data (ordering: lev, lat, lon)... */
9287 omp_set_dynamic(1);
9288#pragma omp parallel for default(shared)
9289 for (int ix = 0; ix < met->nx; ix++)
9290 for (int iy = 0; iy < met->ny; iy++)
9291 for (int ip = 0; ip < met->np; ip++) {
9292 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9293 if ((fillval == 0 || aux != fillval)
9294 && (missval == 0 || aux != missval)
9295 && fabsf(aux) < 1e14f)
9296 dest[ix][iy][ip] = scl * aux;
9297 else
9298 dest[ix][iy][ip] = NAN;
9299 }
9300 omp_set_dynamic(0);
9301
9302 } else {
9303
9304 /* Copy and check data (ordering: lon, lat, lev)... */
9305 omp_set_dynamic(1);
9306#pragma omp parallel for default(shared)
9307 for (int ip = 0; ip < met->np; ip++)
9308 for (int iy = 0; iy < met->ny; iy++)
9309 for (int ix = 0; ix < met->nx; ix++) {
9310 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9311 if ((fillval == 0 || aux != fillval)
9312 && (missval == 0 || aux != missval)
9313 && fabsf(aux) < 1e14f)
9314 dest[ix][iy][ip] = scl * aux;
9315 else
9316 dest[ix][iy][ip] = NAN;
9317 }
9318 omp_set_dynamic(0);
9319 }
9320
9321 /* Free... */
9322 free(help);
9323 }
9324
9325 /* Return... */
9326 return 1;
9327}
9328
9329/*****************************************************************************/
9330
9332 const char *filename,
9333 const int ncid,
9334 const ctl_t *ctl,
9335 met_t *met) {
9336
9337 char levname[LEN], tstr[10];
9338
9339 double rtime = 0, r, r2;
9340
9341 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
9342 year, mon, day, hour, min, sec;
9343
9344 size_t dimlen;
9345
9346 /* Set timer... */
9347 SELECT_TIMER("READ_MET_NC_GRID", "INPUT", NVTX_READ);
9348 LOG(2, "Read meteo grid information...");
9349
9350 /* MPTRAC meteo files... */
9351 if (ctl->met_clams == 0) {
9352
9353 /* Get time from filename... */
9354 met->time = time_from_filename(filename, 16);
9355
9356 /* Check time information from data file... */
9357 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
9358 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
9359 NC(nc_get_var_double(ncid, varid, &rtime));
9360 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
9361 WARN("Time information in meteo file does not match filename!");
9362 } else
9363 WARN("Time information in meteo file is missing!");
9364 }
9365
9366 /* CLaMS meteo files... */
9367 else {
9368
9369 /* Read time from file... */
9370 NC_GET_DOUBLE("time", &rtime, 0);
9371
9372 /* Get time from filename (considering the century)... */
9373 if (rtime < 0)
9374 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
9375 else
9376 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
9377 year = atoi(tstr);
9378 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
9379 mon = atoi(tstr);
9380 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
9381 day = atoi(tstr);
9382 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
9383 hour = atoi(tstr);
9384 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
9385 }
9386
9387 /* Check time... */
9388 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
9389 || day < 1 || day > 31 || hour < 0 || hour > 23)
9390 ERRMSG("Cannot read time from filename!");
9391 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
9392 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
9393 met->time, year2, mon2, day2, hour2, min2);
9394
9395 /* Get grid dimensions... */
9396 NC_INQ_DIM("lon", &met->nx, 2, EX);
9397 LOG(2, "Number of longitudes: %d", met->nx);
9398
9399 NC_INQ_DIM("lat", &met->ny, 2, EY);
9400 LOG(2, "Number of latitudes: %d", met->ny);
9401
9402 /* Read longitudes and latitudes... */
9403 NC_GET_DOUBLE("lon", met->lon, 1);
9404 LOG(2, "Longitudes: %g, %g ... %g deg",
9405 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9406 NC_GET_DOUBLE("lat", met->lat, 1);
9407 LOG(2, "Latitudes: %g, %g ... %g deg",
9408 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9409
9410 /* Check grid spacing... */
9411 for (int ix = 2; ix < met->nx; ix++)
9412 if (fabs
9413 (fabs(met->lon[ix] - met->lon[ix - 1]) -
9414 fabs(met->lon[1] - met->lon[0])) > 0.001)
9415 ERRMSG("No regular grid spacing in longitudes!");
9416 for (int iy = 2; iy < met->ny; iy++)
9417 if (fabs
9418 (fabs(met->lat[iy] - met->lat[iy - 1]) -
9419 fabs(met->lat[1] - met->lat[0])) > 0.001) {
9420 WARN("No regular grid spacing in latitudes!");
9421 break;
9422 }
9423
9424 /* Get vertical dimension... */
9425 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
9426 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
9427 ERRMSG
9428 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
9429
9430 NC(nc_inq_varndims(ncid, varid, &ndims));
9431 NC(nc_inq_vardimid(ncid, varid, dimids));
9432
9433 if (ndims == 4) {
9434 NC(nc_inq_dim
9435 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
9436 } else if (ndims == 3) {
9437 NC(nc_inq_dim
9438 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
9439 } else
9440 ERRMSG("Cannot determine vertical dimension!")
9441 met->np = (int) dimlen;
9442
9443 LOG(2, "Number of levels: %d", met->np);
9444 if (met->np < 2 || met->np > EP)
9445 ERRMSG("Number of levels out of range!");
9446
9447 /* Read pressure levels... */
9448 if (ctl->met_np <= 0) {
9449 NC_GET_DOUBLE(levname, met->p, 1);
9450 for (int ip = 0; ip < met->np; ip++)
9451 met->p[ip] /= 100.;
9452 LOG(2, "Altitude levels: %g, %g ... %g km",
9453 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
9454 LOG(2, "Pressure levels: %g, %g ... %g hPa",
9455 met->p[0], met->p[1], met->p[met->np - 1]);
9456 }
9457
9458 /* Read hybrid levels... */
9459 if (strcasecmp(levname, "hybrid") == 0)
9460 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
9461}
9462
9463/*****************************************************************************/
9464
9466 const int ncid,
9467 const ctl_t *ctl,
9468 met_t *met) {
9469
9470 /* Set timer... */
9471 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT", NVTX_READ);
9472 LOG(2, "Read level data...");
9473
9474 /* Read temperature... */
9475 if (!read_met_nc_3d(ncid, "t", "T", "temp", "TEMP", ctl, met, met->t, 1.0))
9476 ERRMSG("Cannot read temperature!");
9477
9478 /* Read horizontal wind and vertical velocity... */
9479 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, met->u, 1.0))
9480 ERRMSG("Cannot read zonal wind!");
9481 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, met->v, 1.0))
9482 ERRMSG("Cannot read meridional wind!");
9483 if (!read_met_nc_3d
9484 (ncid, "w", "W", "omega", "OMEGA", ctl, met, met->w, 0.01f))
9485 WARN("Cannot read vertical velocity!");
9486
9487 /* Read water vapor... */
9488 if (!ctl->met_relhum) {
9489 if (!read_met_nc_3d
9490 (ncid, "q", "Q", "sh", "SH", ctl, met, met->h2o, (float) (MA / MH2O)))
9491 WARN("Cannot read specific humidity!");
9492 } else {
9493 if (!read_met_nc_3d
9494 (ncid, "rh", "RH", NULL, NULL, ctl, met, met->h2o, 0.01f))
9495 WARN("Cannot read relative humidity!");
9496#pragma omp parallel for default(shared) collapse(2)
9497 for (int ix = 0; ix < met->nx; ix++)
9498 for (int iy = 0; iy < met->ny; iy++)
9499 for (int ip = 0; ip < met->np; ip++) {
9500 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
9501 met->h2o[ix][iy][ip] =
9502 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
9503 }
9504 }
9505
9506 /* Read ozone... */
9507 if (!read_met_nc_3d
9508 (ncid, "o3", "O3", NULL, NULL, ctl, met, met->o3, (float) (MA / MO3)))
9509 WARN("Cannot read ozone data!");
9510
9511 /* Read cloud data... */
9512 if (!read_met_nc_3d
9513 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, met->lwc, 1.0))
9514 WARN("Cannot read cloud liquid water content!");
9515 if (!read_met_nc_3d
9516 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, met->rwc, 1.0))
9517 WARN("Cannot read cloud rain water content!");
9518 if (!read_met_nc_3d
9519 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, met->iwc, 1.0))
9520 WARN("Cannot read cloud ice water content!");
9521 if (!read_met_nc_3d
9522 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, met->swc, 1.0))
9523 WARN("Cannot read cloud snow water content!");
9524 if (!read_met_nc_3d(ncid, "cc", "CC", NULL, NULL, ctl, met, met->cc, 1.0))
9525 WARN("Cannot read cloud cover!");
9526
9527 /* Read zeta and zeta_dot... */
9528 if (!read_met_nc_3d
9529 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, met->zetal, 1.0))
9530 WARN("Cannot read ZETA!");
9531 if (!read_met_nc_3d
9532 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
9533 NULL, ctl, met, met->zeta_dotl, 0.00001157407f))
9534 WARN("Cannot read ZETA_DOT!");
9535
9536 /* Store velocities on model levels... */
9537 if (ctl->met_vert_coord != 0) {
9538 for (int ix = 0; ix < met->nx; ix++)
9539 for (int iy = 0; iy < met->ny; iy++)
9540 for (int ip = 0; ip < met->np; ip++) {
9541 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
9542 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
9543 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
9544 }
9545
9546 /* Save number of model levels... */
9547 met->npl = met->np;
9548 }
9549
9550 /* Get pressure on model levels... */
9551 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
9552
9553 /* Read 3-D pressure field... */
9554 if (ctl->met_vert_coord == 1) {
9555 if (!read_met_nc_3d
9556 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, met->pl,
9557 0.01f))
9558 if (!read_met_nc_3d
9559 (ncid, "press", "PRESS", NULL, NULL, ctl, met, met->pl, 1.0))
9560 ERRMSG("Cannot read pressure on model levels!");
9561 }
9562
9563 /* Use a and b coefficients for full levels... */
9564 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
9565
9566 /* Grid level coefficients... */
9567 double hyam[EP], hybm[EP];
9568
9569 /* Read coefficients from file... */
9570 if (ctl->met_vert_coord == 2) {
9571 int varid;
9572 if (nc_inq_varid(ncid, "hyam", &varid) == NC_NOERR
9573 && nc_inq_varid(ncid, "hybm", &varid) == NC_NOERR) {
9574 NC_GET_DOUBLE("hyam", hyam, 1);
9575 NC_GET_DOUBLE("hybm", hybm, 1);
9576 } else if (nc_inq_varid(ncid, "a_hybrid_level", &varid) == NC_NOERR
9577 && nc_inq_varid(ncid, "b_hybrid_level",
9578 &varid) == NC_NOERR) {
9579 NC_GET_DOUBLE("a_hybrid_level", hyam, 1);
9580 NC_GET_DOUBLE("b_hybrid_level", hybm, 1);
9581 } else
9582 ERRMSG("Cannot read a and b level coefficients from netCDF file!");
9583 }
9584
9585 /* Use control parameters... */
9586 else if (ctl->met_vert_coord == 3) {
9587
9588 /* Check number of levels... */
9589 if (met->np != ctl->met_nlev)
9590 ERRMSG("Mismatch in number of model levels!");
9591
9592 /* Copy parameters... */
9593 for (int ip = 0; ip < met->np; ip++) {
9594 hyam[ip] = ctl->met_lev_hyam[ip];
9595 hybm[ip] = ctl->met_lev_hybm[ip];
9596 }
9597 }
9598
9599 /* Calculate pressure... */
9600 for (int ix = 0; ix < met->nx; ix++)
9601 for (int iy = 0; iy < met->ny; iy++)
9602 for (int ip = 0; ip < met->np; ip++)
9603 met->pl[ix][iy][ip] =
9604 (float) (hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy]);
9605 }
9606
9607 /* Use a and b coefficients for half levels... */
9608 else if (ctl->met_vert_coord == 4) {
9609
9610 /* Grid level coefficients... */
9611 double hyam[EP], hybm[EP];
9612
9613 /* Use control parameters... */
9614 for (int ip = 0; ip < met->np + 1; ip++) {
9615 hyam[ip] = ctl->met_lev_hyam[ip];
9616 hybm[ip] = ctl->met_lev_hybm[ip];
9617 }
9618
9619 /* Check number of levels... */
9620 if (met->np + 1 != ctl->met_nlev)
9621 ERRMSG("Mismatch in number of model levels!");
9622
9623 /* Calculate pressure... */
9624#pragma omp parallel for default(shared) collapse(2)
9625 for (int ix = 0; ix < met->nx; ix++)
9626 for (int iy = 0; iy < met->ny; iy++)
9627 for (int ip = 0; ip < met->np; ip++) {
9628 double p0 = hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy];
9629 double p1 = hyam[ip + 1] / 100. + hybm[ip + 1] * met->ps[ix][iy];
9630 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
9631 }
9632 }
9633
9634 /* Check ordering of pressure levels... */
9635 for (int ix = 0; ix < met->nx; ix++)
9636 for (int iy = 0; iy < met->ny; iy++)
9637 for (int ip = 1; ip < met->np; ip++)
9638 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
9639 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
9640 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
9641 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
9642 ERRMSG("Pressure profiles are not monotonic!");
9643 }
9644
9645 /* Interpolate from model levels to pressure levels... */
9646 if (ctl->met_np > 0) {
9647
9648 /* Check pressure on model levels... */
9649 if (met->pl[0][0][0] <= 0)
9650 ERRMSG("Pressure on model levels is missing, check MET_VERT_COORD!");
9651
9652 /* Interpolate variables... */
9653 read_met_ml2pl(ctl, met, met->t, "T");
9654 read_met_ml2pl(ctl, met, met->u, "U");
9655 read_met_ml2pl(ctl, met, met->v, "V");
9656 read_met_ml2pl(ctl, met, met->w, "W");
9657 read_met_ml2pl(ctl, met, met->h2o, "H2O");
9658 read_met_ml2pl(ctl, met, met->o3, "O3");
9659 read_met_ml2pl(ctl, met, met->lwc, "LWC");
9660 read_met_ml2pl(ctl, met, met->rwc, "RWC");
9661 read_met_ml2pl(ctl, met, met->iwc, "IWC");
9662 read_met_ml2pl(ctl, met, met->swc, "SWC");
9663 read_met_ml2pl(ctl, met, met->cc, "CC");
9664
9665 /* Set new pressure levels... */
9666 met->np = ctl->met_np;
9667 for (int ip = 0; ip < met->np; ip++)
9668 met->p[ip] = ctl->met_p[ip];
9669 }
9670
9671 /* Check ordering of pressure levels... */
9672 for (int ip = 1; ip < met->np; ip++)
9673 if (met->p[ip - 1] < met->p[ip])
9674 ERRMSG("Pressure levels must be descending!");
9675}
9676
9677/*****************************************************************************/
9678
9680 const int ncid,
9681 const ctl_t *ctl,
9682 met_t *met) {
9683
9684 /* Set timer... */
9685 SELECT_TIMER("READ_MET_NC_SURFACE", "INPUT", NVTX_READ);
9686 LOG(2, "Read surface data...");
9687
9688 /* Read surface pressure... */
9689 if (read_met_nc_2d
9690 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, met->ps,
9691 1.0f, 1)) {
9692 for (int ix = 0; ix < met->nx; ix++)
9693 for (int iy = 0; iy < met->ny; iy++)
9694 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
9695 } else
9696 if (!read_met_nc_2d
9697 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, met->ps, 0.01f,
9698 1)) {
9699 WARN("Cannot not read surface pressure data (use lowest level)!");
9700 for (int ix = 0; ix < met->nx; ix++)
9701 for (int iy = 0; iy < met->ny; iy++)
9702 met->ps[ix][iy]
9703 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
9704 }
9705
9706 /* MPTRAC meteo data... */
9707 if (ctl->met_clams == 0) {
9708
9709 /* Read geopotential height at the surface... */
9710 if (!read_met_nc_2d
9711 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, met->zs,
9712 (float) (1. / (1000. * G0)), 1))
9713 if (!read_met_nc_2d
9714 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, met->zs,
9715 (float) (1. / 1000.), 1))
9716 WARN("Cannot read surface geopotential height!");
9717 }
9718
9719 /* CLaMS meteo data... */
9720 else {
9721
9722 /* Read geopotential height at the surface
9723 (use lowermost level of 3-D data field)... */
9724 float *help;
9725 ALLOC(help, float,
9726 EX * EY * EP);
9727 memcpy(help, met->pl, sizeof(met->pl));
9728 if (!read_met_nc_3d
9729 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
9730 (float) (1e-3 / G0)))
9731 ERRMSG("Cannot read geopotential height!");
9732 for (int ix = 0; ix < met->nx; ix++)
9733 for (int iy = 0; iy < met->ny; iy++)
9734 met->zs[ix][iy] = met->pl[ix][iy][0];
9735 memcpy(met->pl, help, sizeof(met->pl));
9736 free(help);
9737 }
9738
9739 /* Read temperature at the surface... */
9740 if (!read_met_nc_2d
9741 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, met->ts, 1.0, 1))
9742 WARN("Cannot read surface temperature!");
9743
9744 /* Read zonal wind at the surface... */
9745 if (!read_met_nc_2d
9746 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, met->us,
9747 1.0, 1))
9748 WARN("Cannot read surface zonal wind!");
9749
9750 /* Read meridional wind at the surface... */
9751 if (!read_met_nc_2d
9752 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, met->vs,
9753 1.0, 1))
9754 WARN("Cannot read surface meridional wind!");
9755
9756 /* Read eastward turbulent surface stress... */
9757 if (!read_met_nc_2d
9758 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, met->ess,
9759 1.0, 1))
9760 WARN("Cannot read eastward turbulent surface stress!");
9761
9762 /* Read northward turbulent surface stress... */
9763 if (!read_met_nc_2d
9764 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, met->nss,
9765 1.0, 1))
9766 WARN("Cannot read nothward turbulent surface stress!");
9767
9768 /* Read surface sensible heat flux... */
9769 if (!read_met_nc_2d
9770 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, met->shf,
9771 1.0, 1))
9772 WARN("Cannot read surface sensible heat flux!");
9773
9774 /* Read land-sea mask... */
9775 if (!read_met_nc_2d
9776 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, met->lsm, 1.0,
9777 1))
9778 WARN("Cannot read land-sea mask!");
9779
9780 /* Read sea surface temperature... */
9781 if (!read_met_nc_2d
9782 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, met->sst,
9783 1.0, 1))
9784 WARN("Cannot read sea surface temperature!");
9785
9786 /* Read PBL... */
9787 if (ctl->met_pbl == 0)
9788 if (!read_met_nc_2d
9789 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
9790 0.01f, 1))
9791 WARN("Cannot read planetary boundary layer pressure!");
9792 if (ctl->met_pbl == 1)
9793 if (!read_met_nc_2d
9794 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
9795 0.001f, 1))
9796 WARN("Cannot read planetary boundary layer height!");
9797
9798 /* Read CAPE... */
9799 if (ctl->met_cape == 0)
9800 if (!read_met_nc_2d
9801 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, met->cape,
9802 1.0, 1))
9803 WARN("Cannot read CAPE!");
9804
9805 /* Read CIN... */
9806 if (ctl->met_cape == 0)
9807 if (!read_met_nc_2d
9808 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, met->cin,
9809 1.0, 1))
9810 WARN("Cannot read convective inhibition!");
9811}
9812
9813/*****************************************************************************/
9814
9816 const ctl_t *ctl,
9817 met_t *met) {
9818
9819 /* Set timer... */
9820 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
9821 LOG(2, "Calculate planetary boundary layer...");
9822
9823 /* Convert PBL height from meteo file to pressure... */
9824 if (ctl->met_pbl == 1) {
9825
9826 /* Loop over grid points... */
9827#pragma omp parallel for default(shared) collapse(2)
9828 for (int ix = 0; ix < met->nx; ix++)
9829 for (int iy = 0; iy < met->ny; iy++) {
9830
9831 /* Get pressure at top of PBL... */
9832 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
9833 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
9834 met->pbl[ix][iy] =
9835 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
9836 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
9837 }
9838 }
9839
9840 /* Determine PBL based on Richardson number... */
9841 else if (ctl->met_pbl == 2) {
9842
9843 /* Parameters used to estimate the height of the PBL
9844 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
9845 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
9846
9847 /* Loop over grid points... */
9848#pragma omp parallel for default(shared) collapse(2)
9849 for (int ix = 0; ix < met->nx; ix++)
9850 for (int iy = 0; iy < met->ny; iy++) {
9851
9852 /* Set bottom level of PBL... */
9853 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
9854
9855 /* Find lowest level near the bottom... */
9856 int ip;
9857 for (ip = 1; ip < met->np; ip++)
9858 if (met->p[ip] < pbl_bot)
9859 break;
9860
9861 /* Get near surface data... */
9862 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
9863 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
9864 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
9865
9866 /* Init... */
9867 double rib_old = 0;
9868
9869 /* Loop over levels... */
9870 for (; ip < met->np; ip++) {
9871
9872 /* Get squared horizontal wind speed... */
9873 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
9874 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
9875 vh2 = MAX(vh2, SQR(umin));
9876
9877 /* Calculate bulk Richardson number... */
9878 const double rib =
9879 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
9880 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
9881 met->h2o[ix][iy][ip]) - tvs) / vh2;
9882
9883 /* Check for critical value... */
9884 if (rib >= rib_crit) {
9885 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
9886 rib, met->p[ip], rib_crit));
9887 if (met->pbl[ix][iy] > pbl_bot)
9888 met->pbl[ix][iy] = (float) pbl_bot;
9889 break;
9890 }
9891
9892 /* Save Richardson number... */
9893 rib_old = rib;
9894 }
9895 }
9896 }
9897
9898 /* Determine PBL based on potential temperature... */
9899 if (ctl->met_pbl == 3) {
9900
9901 /* Parameters used to estimate the height of the PBL
9902 (following HYSPLIT model)... */
9903 const double dtheta = 2.0, zmin = 0.1;
9904
9905 /* Loop over grid points... */
9906#pragma omp parallel for default(shared) collapse(2)
9907 for (int ix = 0; ix < met->nx; ix++)
9908 for (int iy = 0; iy < met->ny; iy++) {
9909
9910 /* Potential temperature at the surface... */
9911 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
9912
9913 /* Find topmost level where theta exceeds surface value by 2 K... */
9914 int ip;
9915 for (ip = met->np - 2; ip > 0; ip--)
9916 if (met->p[ip] >= 300.)
9917 if (met->p[ip] > met->ps[ix][iy]
9918 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
9919 break;
9920
9921 /* Interpolate... */
9922 met->pbl[ix][iy]
9923 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
9924 met->p[ip + 1],
9925 THETA(met->p[ip], met->t[ix][iy][ip]),
9926 met->p[ip], theta0 + dtheta));
9927
9928 /* Check minimum value... */
9929 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
9930 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
9931 met->pbl[ix][iy] = (float) pbl_min;
9932 }
9933 }
9934
9935 /* Loop over grid points... */
9936#pragma omp parallel for default(shared) collapse(2)
9937 for (int ix = 0; ix < met->nx; ix++)
9938 for (int iy = 0; iy < met->ny; iy++) {
9939
9940 /* Check minimum value... */
9941 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
9942 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
9943
9944 /* Check maximum value... */
9945 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
9946 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
9947 }
9948}
9949
9950/*****************************************************************************/
9951
9953 met_t *met) {
9954
9955 /* Set timer... */
9956 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
9957 LOG(2, "Apply periodic boundary conditions...");
9958
9959 /* Check longitudes... */
9960 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
9961 + met->lon[1] - met->lon[0] - 360) < 0.01))
9962 return;
9963
9964 /* Increase longitude counter... */
9965 if ((++met->nx) >= EX)
9966 ERRMSG("Cannot create periodic boundary conditions!");
9967
9968 /* Set longitude... */
9969 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
9970
9971 /* Loop over latitudes and pressure levels... */
9972#pragma omp parallel for default(shared)
9973 for (int iy = 0; iy < met->ny; iy++) {
9974 met->ps[met->nx - 1][iy] = met->ps[0][iy];
9975 met->zs[met->nx - 1][iy] = met->zs[0][iy];
9976 met->ts[met->nx - 1][iy] = met->ts[0][iy];
9977 met->us[met->nx - 1][iy] = met->us[0][iy];
9978 met->vs[met->nx - 1][iy] = met->vs[0][iy];
9979 met->ess[met->nx - 1][iy] = met->ess[0][iy];
9980 met->nss[met->nx - 1][iy] = met->nss[0][iy];
9981 met->shf[met->nx - 1][iy] = met->shf[0][iy];
9982 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
9983 met->sst[met->nx - 1][iy] = met->sst[0][iy];
9984 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
9985 met->cape[met->nx - 1][iy] = met->cape[0][iy];
9986 met->cin[met->nx - 1][iy] = met->cin[0][iy];
9987 for (int ip = 0; ip < met->np; ip++) {
9988 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
9989 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
9990 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
9991 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
9992 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
9993 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
9994 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
9995 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
9996 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
9997 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
9998 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
9999 }
10000 for (int ip = 0; ip < met->npl; ip++) {
10001 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
10002 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
10003 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
10004 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
10005 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
10006 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
10007 }
10008 }
10009}
10010
10011/*****************************************************************************/
10012
10014 met_t *met) {
10015
10016 /* Set timer... */
10017 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
10018 LOG(2, "Apply fix for polar winds...");
10019
10020 /* Check latitudes... */
10021 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
10022 return;
10023
10024 /* Loop over hemispheres... */
10025 for (int ihem = 0; ihem < 2; ihem++) {
10026
10027 /* Set latitude indices... */
10028 int i89 = 1, i90 = 0, sign = 1;
10029 if (ihem == 1) {
10030 i89 = met->ny - 2;
10031 i90 = met->ny - 1;
10032 }
10033 if (met->lat[i90] < 0)
10034 sign = -1;
10035
10036 /* Look-up table of cosinus and sinus... */
10037 double clon[EX], slon[EX];
10038#pragma omp parallel for default(shared)
10039 for (int ix = 0; ix < met->nx; ix++) {
10040 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
10041 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
10042 }
10043
10044 /* Loop over levels... */
10045#pragma omp parallel for default(shared)
10046 for (int ip = 0; ip < met->np; ip++) {
10047
10048 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
10049 double vel89x = 0, vel89y = 0;
10050 for (int ix = 0; ix < met->nx; ix++) {
10051 vel89x +=
10052 (met->u[ix][i89][ip] * clon[ix] -
10053 met->v[ix][i89][ip] * slon[ix]) / met->nx;
10054 vel89y +=
10055 (met->u[ix][i89][ip] * slon[ix] +
10056 met->v[ix][i89][ip] * clon[ix]) / met->nx;
10057 }
10058
10059 /* Replace 90 degree winds by 89 degree mean... */
10060 for (int ix = 0; ix < met->nx; ix++) {
10061 met->u[ix][i90][ip]
10062 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
10063 met->v[ix][i90][ip]
10064 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
10065 }
10066 }
10067 }
10068}
10069
10070/*****************************************************************************/
10071
10073 met_t *met) {
10074
10075 double pows[EP];
10076
10077 /* Set timer... */
10078 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
10079 LOG(2, "Calculate potential vorticity...");
10080
10081 /* Set powers... */
10082#pragma omp parallel for default(shared)
10083 for (int ip = 0; ip < met->np; ip++)
10084 pows[ip] = pow(1000. / met->p[ip], 0.286);
10085
10086 /* Loop over grid points... */
10087#pragma omp parallel for default(shared)
10088 for (int ix = 0; ix < met->nx; ix++) {
10089
10090 /* Set indices... */
10091 const int ix0 = MAX(ix - 1, 0);
10092 const int ix1 = MIN(ix + 1, met->nx - 1);
10093
10094 /* Loop over grid points... */
10095 for (int iy = 0; iy < met->ny; iy++) {
10096
10097 /* Set indices... */
10098 const int iy0 = MAX(iy - 1, 0);
10099 const int iy1 = MIN(iy + 1, met->ny - 1);
10100
10101 /* Set auxiliary variables... */
10102 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
10103 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
10104 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
10105 const double c0 = cos(DEG2RAD(met->lat[iy0]));
10106 const double c1 = cos(DEG2RAD(met->lat[iy1]));
10107 const double cr = cos(DEG2RAD(latr));
10108 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
10109
10110 /* Loop over grid points... */
10111 for (int ip = 0; ip < met->np; ip++) {
10112
10113 /* Get gradients in longitude... */
10114 const double dtdx
10115 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
10116 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
10117
10118 /* Get gradients in latitude... */
10119 const double dtdy
10120 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
10121 const double dudy
10122 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
10123
10124 /* Set indices... */
10125 const int ip0 = MAX(ip - 1, 0);
10126 const int ip1 = MIN(ip + 1, met->np - 1);
10127
10128 /* Get gradients in pressure... */
10129 double dtdp, dudp, dvdp;
10130 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
10131 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
10132 if (ip != ip0 && ip != ip1) {
10133 double denom = dp0 * dp1 * (dp0 + dp1);
10134 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
10135 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
10136 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
10137 / denom;
10138 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
10139 - dp1 * dp1 * met->u[ix][iy][ip0]
10140 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
10141 / denom;
10142 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
10143 - dp1 * dp1 * met->v[ix][iy][ip0]
10144 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
10145 / denom;
10146 } else {
10147 const double denom = dp0 + dp1;
10148 dtdp =
10149 (met->t[ix][iy][ip1] * pows[ip1] -
10150 met->t[ix][iy][ip0] * pows[ip0]) / denom;
10151 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
10152 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
10153 }
10154
10155 /* Calculate PV... */
10156 met->pv[ix][iy][ip] = (float)
10157 (1e6 * G0 *
10158 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
10159 }
10160 }
10161 }
10162
10163 /* Fix for polar regions... */
10164#pragma omp parallel for default(shared)
10165 for (int ix = 0; ix < met->nx; ix++)
10166 for (int ip = 0; ip < met->np; ip++) {
10167 met->pv[ix][0][ip]
10168 = met->pv[ix][1][ip]
10169 = met->pv[ix][2][ip];
10170 met->pv[ix][met->ny - 1][ip]
10171 = met->pv[ix][met->ny - 2][ip]
10172 = met->pv[ix][met->ny - 3][ip];
10173 }
10174}
10175
10176/*****************************************************************************/
10177
10179 met_t *met) {
10180
10181 /* Set timer... */
10182 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
10183 LOG(2, "Calculate total column ozone...");
10184
10185 /* Loop over columns... */
10186#pragma omp parallel for default(shared) collapse(2)
10187 for (int ix = 0; ix < met->nx; ix++)
10188 for (int iy = 0; iy < met->ny; iy++) {
10189
10190 /* Integrate... */
10191 double cd = 0;
10192 for (int ip = 1; ip < met->np; ip++)
10193 if (met->p[ip - 1] <= met->ps[ix][iy]) {
10194 const double vmr =
10195 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
10196 const double dp = met->p[ip - 1] - met->p[ip];
10197 cd += vmr * MO3 / MA * dp * 1e2 / G0;
10198 }
10199
10200 /* Convert to Dobson units... */
10201 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
10202 }
10203}
10204
10205/*****************************************************************************/
10206
10208 const ctl_t *ctl,
10209 met_t *met) {
10210
10211 met_t *help;
10212
10213 /* Check parameters... */
10214 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
10215 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
10216 return;
10217
10218 /* Set timer... */
10219 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
10220 LOG(2, "Downsampling of meteo data...");
10221
10222 /* Allocate... */
10223 ALLOC(help, met_t, 1);
10224
10225 /* Copy data... */
10226 help->nx = met->nx;
10227 help->ny = met->ny;
10228 help->np = met->np;
10229 memcpy(help->lon, met->lon, sizeof(met->lon));
10230 memcpy(help->lat, met->lat, sizeof(met->lat));
10231 memcpy(help->p, met->p, sizeof(met->p));
10232
10233 /* Smoothing... */
10234 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
10235 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
10236 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
10237 help->ps[ix][iy] = 0;
10238 help->zs[ix][iy] = 0;
10239 help->ts[ix][iy] = 0;
10240 help->us[ix][iy] = 0;
10241 help->vs[ix][iy] = 0;
10242 help->ess[ix][iy] = 0;
10243 help->nss[ix][iy] = 0;
10244 help->shf[ix][iy] = 0;
10245 help->lsm[ix][iy] = 0;
10246 help->sst[ix][iy] = 0;
10247 help->pbl[ix][iy] = 0;
10248 help->cape[ix][iy] = 0;
10249 help->cin[ix][iy] = 0;
10250 help->t[ix][iy][ip] = 0;
10251 help->u[ix][iy][ip] = 0;
10252 help->v[ix][iy][ip] = 0;
10253 help->w[ix][iy][ip] = 0;
10254 help->h2o[ix][iy][ip] = 0;
10255 help->o3[ix][iy][ip] = 0;
10256 help->lwc[ix][iy][ip] = 0;
10257 help->rwc[ix][iy][ip] = 0;
10258 help->iwc[ix][iy][ip] = 0;
10259 help->swc[ix][iy][ip] = 0;
10260 help->cc[ix][iy][ip] = 0;
10261 float wsum = 0;
10262 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
10263 ix2++) {
10264 int ix3 = ix2;
10265 if (ix3 < 0)
10266 ix3 += met->nx;
10267 else if (ix3 >= met->nx)
10268 ix3 -= met->nx;
10269
10270 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
10271 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
10272 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
10273 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
10274 const float w =
10275 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
10276 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
10277 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
10278 help->ps[ix][iy] += w * met->ps[ix3][iy2];
10279 help->zs[ix][iy] += w * met->zs[ix3][iy2];
10280 help->ts[ix][iy] += w * met->ts[ix3][iy2];
10281 help->us[ix][iy] += w * met->us[ix3][iy2];
10282 help->vs[ix][iy] += w * met->vs[ix3][iy2];
10283 help->ess[ix][iy] += w * met->ess[ix3][iy2];
10284 help->nss[ix][iy] += w * met->nss[ix3][iy2];
10285 help->shf[ix][iy] += w * met->shf[ix3][iy2];
10286 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
10287 help->sst[ix][iy] += w * met->sst[ix3][iy2];
10288 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
10289 help->cape[ix][iy] += w * met->cape[ix3][iy2];
10290 help->cin[ix][iy] += w * met->cin[ix3][iy2];
10291 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
10292 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
10293 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
10294 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
10295 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
10296 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
10297 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
10298 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
10299 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
10300 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
10301 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
10302 wsum += w;
10303 }
10304 }
10305 help->ps[ix][iy] /= wsum;
10306 help->zs[ix][iy] /= wsum;
10307 help->ts[ix][iy] /= wsum;
10308 help->us[ix][iy] /= wsum;
10309 help->vs[ix][iy] /= wsum;
10310 help->ess[ix][iy] /= wsum;
10311 help->nss[ix][iy] /= wsum;
10312 help->shf[ix][iy] /= wsum;
10313 help->lsm[ix][iy] /= wsum;
10314 help->sst[ix][iy] /= wsum;
10315 help->pbl[ix][iy] /= wsum;
10316 help->cape[ix][iy] /= wsum;
10317 help->cin[ix][iy] /= wsum;
10318 help->t[ix][iy][ip] /= wsum;
10319 help->u[ix][iy][ip] /= wsum;
10320 help->v[ix][iy][ip] /= wsum;
10321 help->w[ix][iy][ip] /= wsum;
10322 help->h2o[ix][iy][ip] /= wsum;
10323 help->o3[ix][iy][ip] /= wsum;
10324 help->lwc[ix][iy][ip] /= wsum;
10325 help->rwc[ix][iy][ip] /= wsum;
10326 help->iwc[ix][iy][ip] /= wsum;
10327 help->swc[ix][iy][ip] /= wsum;
10328 help->cc[ix][iy][ip] /= wsum;
10329 }
10330 }
10331 }
10332
10333 /* Downsampling... */
10334 met->nx = 0;
10335 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
10336 met->lon[met->nx] = help->lon[ix];
10337 met->ny = 0;
10338 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
10339 met->lat[met->ny] = help->lat[iy];
10340 met->ps[met->nx][met->ny] = help->ps[ix][iy];
10341 met->zs[met->nx][met->ny] = help->zs[ix][iy];
10342 met->ts[met->nx][met->ny] = help->ts[ix][iy];
10343 met->us[met->nx][met->ny] = help->us[ix][iy];
10344 met->vs[met->nx][met->ny] = help->vs[ix][iy];
10345 met->ess[met->nx][met->ny] = help->ess[ix][iy];
10346 met->nss[met->nx][met->ny] = help->nss[ix][iy];
10347 met->shf[met->nx][met->ny] = help->shf[ix][iy];
10348 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
10349 met->sst[met->nx][met->ny] = help->sst[ix][iy];
10350 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
10351 met->cape[met->nx][met->ny] = help->cape[ix][iy];
10352 met->cin[met->nx][met->ny] = help->cin[ix][iy];
10353 met->np = 0;
10354 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
10355 met->p[met->np] = help->p[ip];
10356 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
10357 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
10358 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
10359 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
10360 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
10361 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
10362 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
10363 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
10364 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
10365 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
10366 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
10367 met->np++;
10368 }
10369 met->ny++;
10370 }
10371 met->nx++;
10372 }
10373
10374 /* Free... */
10375 free(help);
10376}
10377
10378/*****************************************************************************/
10379
10381 const ctl_t *ctl,
10382 const clim_t *clim,
10383 met_t *met) {
10384
10385 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
10386 th2[200], z[EP], z2[200];
10387
10388 /* Set timer... */
10389 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
10390 LOG(2, "Calculate tropopause...");
10391
10392 /* Get altitude and pressure profiles... */
10393#pragma omp parallel for default(shared)
10394 for (int iz = 0; iz < met->np; iz++)
10395 z[iz] = Z(met->p[iz]);
10396#pragma omp parallel for default(shared)
10397 for (int iz = 0; iz <= 190; iz++) {
10398 z2[iz] = 4.5 + 0.1 * iz;
10399 p2[iz] = P(z2[iz]);
10400 }
10401
10402 /* Do not calculate tropopause... */
10403 if (ctl->met_tropo == 0)
10404#pragma omp parallel for default(shared) collapse(2)
10405 for (int ix = 0; ix < met->nx; ix++)
10406 for (int iy = 0; iy < met->ny; iy++)
10407 met->pt[ix][iy] = NAN;
10408
10409 /* Use tropopause climatology... */
10410 else if (ctl->met_tropo == 1) {
10411#pragma omp parallel for default(shared) collapse(2)
10412 for (int ix = 0; ix < met->nx; ix++)
10413 for (int iy = 0; iy < met->ny; iy++)
10414 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
10415 }
10416
10417 /* Use cold point... */
10418 else if (ctl->met_tropo == 2) {
10419
10420 /* Loop over grid points... */
10421#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10422 for (int ix = 0; ix < met->nx; ix++)
10423 for (int iy = 0; iy < met->ny; iy++) {
10424
10425 /* Interpolate temperature profile... */
10426 for (int iz = 0; iz < met->np; iz++)
10427 t[iz] = met->t[ix][iy][iz];
10428 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
10429
10430 /* Find minimum... */
10431 int iz = (int) gsl_stats_min_index(t2, 1, 171);
10432 if (iz > 0 && iz < 170)
10433 met->pt[ix][iy] = (float) p2[iz];
10434 else
10435 met->pt[ix][iy] = NAN;
10436 }
10437 }
10438
10439 /* Use WMO definition... */
10440 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
10441
10442 /* Loop over grid points... */
10443#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10444 for (int ix = 0; ix < met->nx; ix++)
10445 for (int iy = 0; iy < met->ny; iy++) {
10446
10447 /* Interpolate temperature profile... */
10448 int iz;
10449 for (iz = 0; iz < met->np; iz++)
10450 t[iz] = met->t[ix][iy][iz];
10451 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
10452
10453 /* Find 1st tropopause... */
10454 met->pt[ix][iy] = NAN;
10455 for (iz = 0; iz <= 170; iz++) {
10456 int found = 1;
10457 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10458 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10459 found = 0;
10460 break;
10461 }
10462 if (found) {
10463 if (iz > 0 && iz < 170)
10464 met->pt[ix][iy] = (float) p2[iz];
10465 break;
10466 }
10467 }
10468
10469 /* Find 2nd tropopause... */
10470 if (ctl->met_tropo == 4) {
10471 met->pt[ix][iy] = NAN;
10472 for (; iz <= 170; iz++) {
10473 int found = 1;
10474 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
10475 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
10476 found = 0;
10477 break;
10478 }
10479 if (found)
10480 break;
10481 }
10482 for (; iz <= 170; iz++) {
10483 int found = 1;
10484 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10485 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10486 found = 0;
10487 break;
10488 }
10489 if (found) {
10490 if (iz > 0 && iz < 170)
10491 met->pt[ix][iy] = (float) p2[iz];
10492 break;
10493 }
10494 }
10495 }
10496 }
10497 }
10498
10499 /* Use dynamical tropopause... */
10500 else if (ctl->met_tropo == 5) {
10501
10502 /* Loop over grid points... */
10503#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
10504 for (int ix = 0; ix < met->nx; ix++)
10505 for (int iy = 0; iy < met->ny; iy++) {
10506
10507 /* Interpolate potential vorticity profile... */
10508 for (int iz = 0; iz < met->np; iz++)
10509 pv[iz] = met->pv[ix][iy][iz];
10510 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
10511
10512 /* Interpolate potential temperature profile... */
10513 for (int iz = 0; iz < met->np; iz++)
10514 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
10515 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
10516
10517 /* Find dynamical tropopause... */
10518 met->pt[ix][iy] = NAN;
10519 for (int iz = 0; iz <= 170; iz++)
10520 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
10521 || th2[iz] >= ctl->met_tropo_theta) {
10522 if (iz > 0 && iz < 170)
10523 met->pt[ix][iy] = (float) p2[iz];
10524 break;
10525 }
10526 }
10527 }
10528
10529 else
10530 ERRMSG("Cannot calculate tropopause!");
10531
10532 /* Interpolate temperature, geopotential height, and water vapor... */
10533#pragma omp parallel for default(shared) collapse(2)
10534 for (int ix = 0; ix < met->nx; ix++)
10535 for (int iy = 0; iy < met->ny; iy++) {
10536 double h2ot, tt, zt;
10538 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
10539 met->lat[iy], &tt, ci, cw, 1);
10540 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
10541 met->lat[iy], &zt, ci, cw, 0);
10542 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
10543 met->lat[iy], &h2ot, ci, cw, 0);
10544 met->tt[ix][iy] = (float) tt;
10545 met->zt[ix][iy] = (float) zt;
10546 met->h2ot[ix][iy] = (float) h2ot;
10547 }
10548}
10549
10550/*****************************************************************************/
10551
10553 const char *filename,
10554 const ctl_t *ctl,
10555 double *rt,
10556 double *rz,
10557 double *rlon,
10558 double *rlat,
10559 double *robs,
10560 int *nobs) {
10561
10562 /* Write info... */
10563 LOG(1, "Read observation data: %s", filename);
10564
10565 /* Read data... */
10566 if (ctl->obs_type == 0)
10567 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
10568 else if (ctl->obs_type == 1)
10569 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
10570 else
10571 ERRMSG("Set OBS_TYPE to 0 or 1!");
10572
10573 /* Check time... */
10574 for (int i = 1; i < *nobs; i++)
10575 if (rt[i] < rt[i - 1])
10576 ERRMSG("Time must be ascending!");
10577
10578 /* Write info... */
10579 int n = *nobs;
10580 double mini, maxi;
10581 LOG(2, "Number of observations: %d", *nobs);
10582 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
10583 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
10584 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
10585 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
10586 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
10587 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
10588 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
10589 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
10590 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
10591 LOG(2, "Observation range: %g ... %g", mini, maxi);
10592}
10593
10594/*****************************************************************************/
10595
10597 const char *filename,
10598 double *rt,
10599 double *rz,
10600 double *rlon,
10601 double *rlat,
10602 double *robs,
10603 int *nobs) {
10604
10605 /* Open observation data file... */
10606 FILE *in;
10607 if (!(in = fopen(filename, "r")))
10608 ERRMSG("Cannot open file!");
10609
10610 /* Read observations... */
10611 char line[LEN];
10612 while (fgets(line, LEN, in))
10613 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
10614 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
10615 if ((++(*nobs)) >= NOBS)
10616 ERRMSG("Too many observations!");
10617
10618 /* Close observation data file... */
10619 fclose(in);
10620}
10621
10622/*****************************************************************************/
10623
10625 const char *filename,
10626 double *rt,
10627 double *rz,
10628 double *rlon,
10629 double *rlat,
10630 double *robs,
10631 int *nobs) {
10632
10633 int ncid, varid;
10634
10635 /* Open netCDF file... */
10636 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
10637 ERRMSG("Cannot open file!");
10638
10639 /* Read the observations from the NetCDF file... */
10640 NC_INQ_DIM("nobs", nobs, 1, NOBS);
10641 NC_GET_DOUBLE("time", rt, 1);
10642 NC_GET_DOUBLE("alt", rz, 1);
10643 NC_GET_DOUBLE("lon", rlon, 1);
10644 NC_GET_DOUBLE("lat", rlat, 1);
10645 NC_GET_DOUBLE("obs", robs, 1);
10646
10647 /* Close file... */
10648 NC(nc_close(ncid));
10649}
10650
10651/*****************************************************************************/
10652
10654 const char *filename,
10655 int argc,
10656 char *argv[],
10657 const char *varname,
10658 const int arridx,
10659 const char *defvalue,
10660 char *value) {
10661
10662 FILE *in = NULL;
10663
10664 char fullname1[LEN], fullname2[LEN], rval[LEN];
10665
10666 int contain = 0, i;
10667
10668 /* Open file... */
10669 if (filename[strlen(filename) - 1] != '-')
10670 if (!(in = fopen(filename, "r")))
10671 ERRMSG("Cannot open file!");
10672
10673 /* Set full variable name... */
10674 if (arridx >= 0) {
10675 sprintf(fullname1, "%s[%d]", varname, arridx);
10676 sprintf(fullname2, "%s[*]", varname);
10677 } else {
10678 sprintf(fullname1, "%s", varname);
10679 sprintf(fullname2, "%s", varname);
10680 }
10681
10682 /* Read data... */
10683 if (in != NULL) {
10684 char dummy[LEN], line[LEN], rvarname[LEN];
10685 while (fgets(line, LEN, in)) {
10686 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
10687 if (strcasecmp(rvarname, fullname1) == 0 ||
10688 strcasecmp(rvarname, fullname2) == 0) {
10689 contain = 1;
10690 break;
10691 }
10692 }
10693 }
10694 for (i = 1; i < argc - 1; i++)
10695 if (strcasecmp(argv[i], fullname1) == 0 ||
10696 strcasecmp(argv[i], fullname2) == 0) {
10697 sprintf(rval, "%s", argv[i + 1]);
10698 contain = 1;
10699 break;
10700 }
10701
10702 /* Close file... */
10703 if (in != NULL)
10704 fclose(in);
10705
10706 /* Check for missing variables... */
10707 if (!contain) {
10708 if (strlen(defvalue) > 0)
10709 sprintf(rval, "%s", defvalue);
10710 else
10711 ERRMSG("Missing variable %s!\n", fullname1);
10712 }
10713
10714 /* Write info... */
10715 LOG(1, "%s = %s", fullname1, rval);
10716
10717 /* Return values... */
10718 if (value != NULL)
10719 sprintf(value, "%s", rval);
10720 return atof(rval);
10721}
10722
10723/*****************************************************************************/
10724
10725double sedi(
10726 const double p,
10727 const double T,
10728 const double rp,
10729 const double rhop) {
10730
10731 /* Convert particle radius from microns to m... */
10732 const double rp_help = rp * 1e-6;
10733
10734 /* Density of dry air [kg / m^3]... */
10735 const double rho = RHO(p, T);
10736
10737 /* Dynamic viscosity of air [kg / (m s)]... */
10738 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
10739
10740 /* Thermal velocity of an air molecule [m / s]... */
10741 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
10742
10743 /* Mean free path of an air molecule [m]... */
10744 const double lambda = 2. * eta / (rho * v);
10745
10746 /* Knudsen number for air (dimensionless)... */
10747 const double K = lambda / rp_help;
10748
10749 /* Cunningham slip-flow correction (dimensionless)... */
10750 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
10751
10752 /* Sedimentation velocity [m / s]... */
10753 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
10754}
10755
10756/*****************************************************************************/
10757
10759 const double *x,
10760 const double *y,
10761 const int n,
10762 const double *x2,
10763 double *y2,
10764 const int n2,
10765 const int method) {
10766
10767 /* Cubic spline interpolation... */
10768 if (method == 1) {
10769
10770 /* Allocate... */
10771 gsl_interp_accel *acc = gsl_interp_accel_alloc();
10772 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
10773
10774 /* Interpolate profile... */
10775 gsl_spline_init(s, x, y, (size_t) n);
10776 for (int i = 0; i < n2; i++)
10777 if (x2[i] <= x[0])
10778 y2[i] = y[0];
10779 else if (x2[i] >= x[n - 1])
10780 y2[i] = y[n - 1];
10781 else
10782 y2[i] = gsl_spline_eval(s, x2[i], acc);
10783
10784 /* Free... */
10785 gsl_spline_free(s);
10786 gsl_interp_accel_free(acc);
10787 }
10788
10789 /* Linear interpolation... */
10790 else {
10791 for (int i = 0; i < n2; i++)
10792 if (x2[i] <= x[0])
10793 y2[i] = y[0];
10794 else if (x2[i] >= x[n - 1])
10795 y2[i] = y[n - 1];
10796 else {
10797 const int idx = locate_irr(x, n, x2[i]);
10798 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
10799 }
10800 }
10801}
10802
10803/*****************************************************************************/
10804
10806 const float *data,
10807 const int n) {
10808
10809 if (n <= 0)
10810 return 0;
10811
10812 float mean = 0, var = 0;
10813
10814 for (int i = 0; i < n; ++i) {
10815 mean += data[i];
10816 var += SQR(data[i]);
10817 }
10818
10819 var = var / (float) n - SQR(mean / (float) n);
10820
10821 return (var > 0 ? sqrtf(var) : 0);
10822}
10823
10824/*****************************************************************************/
10825
10827 const double sec,
10828 const double lon,
10829 const double lat) {
10830
10831 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
10832 const double D = sec / 86400 - 0.5;
10833
10834 /* Geocentric apparent ecliptic longitude [rad]... */
10835 const double g = DEG2RAD(357.529 + 0.98560028 * D);
10836 const double q = 280.459 + 0.98564736 * D;
10837 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
10838
10839 /* Mean obliquity of the ecliptic [rad]... */
10840 const double e = DEG2RAD(23.439 - 0.00000036 * D);
10841
10842 /* Declination [rad]... */
10843 const double sindec = sin(e) * sin(L);
10844
10845 /* Right ascension [rad]... */
10846 const double ra = atan2(cos(e) * sin(L), cos(L));
10847
10848 /* Greenwich Mean Sidereal Time [h]... */
10849 const double GMST = 18.697374558 + 24.06570982441908 * D;
10850
10851 /* Local Sidereal Time [h]... */
10852 const double LST = GMST + lon / 15;
10853
10854 /* Hour angle [rad]... */
10855 const double h = LST / 12 * M_PI - ra;
10856
10857 /* Convert latitude... */
10858 const double lat_help = DEG2RAD(lat);
10859
10860 /* Return solar zenith angle [rad]... */
10861 return acos(sin(lat_help) * sindec +
10862 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
10863}
10864
10865/*****************************************************************************/
10866
10868 const int year,
10869 const int mon,
10870 const int day,
10871 const int hour,
10872 const int min,
10873 const int sec,
10874 const double remain,
10875 double *jsec) {
10876
10877 struct tm t0, t1;
10878
10879 t0.tm_year = 100;
10880 t0.tm_mon = 0;
10881 t0.tm_mday = 1;
10882 t0.tm_hour = 0;
10883 t0.tm_min = 0;
10884 t0.tm_sec = 0;
10885
10886 t1.tm_year = year - 1900;
10887 t1.tm_mon = mon - 1;
10888 t1.tm_mday = day;
10889 t1.tm_hour = hour;
10890 t1.tm_min = min;
10891 t1.tm_sec = sec;
10892
10893 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
10894}
10895
10896/*****************************************************************************/
10897
10899 const char *name,
10900 const char *group,
10901 const int output) {
10902
10903 static char names[NTIMER][100], groups[NTIMER][100];
10904
10905 static double rt_name[NTIMER], rt_group[NTIMER],
10906 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
10907
10908 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
10909
10910 /* Get time... */
10911 t1 = omp_get_wtime();
10912 dt = t1 - t0;
10913
10914 /* Add elapsed time to current timers... */
10915 if (iname >= 0) {
10916 rt_name[iname] += dt;
10917 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
10918 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
10919 ct_name[iname]++;
10920 }
10921 if (igroup >= 0)
10922 rt_group[igroup] += t1 - t0;
10923
10924 /* Report timers... */
10925 if (output) {
10926 for (int i = 0; i < nname; i++)
10927 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
10928 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
10929 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
10930 for (int i = 0; i < ngroup; i++)
10931 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
10932 double total = 0.0;
10933 for (int i = 0; i < nname; i++)
10934 total += rt_name[i];
10935 LOG(1, "TIMER_TOTAL = %.3f s", total);
10936 }
10937
10938 /* Identify IDs of next timer... */
10939 for (iname = 0; iname < nname; iname++)
10940 if (strcasecmp(name, names[iname]) == 0)
10941 break;
10942 for (igroup = 0; igroup < ngroup; igroup++)
10943 if (strcasecmp(group, groups[igroup]) == 0)
10944 break;
10945
10946 /* Check whether this is a new timer... */
10947 if (iname >= nname) {
10948 sprintf(names[iname], "%s", name);
10949 if ((++nname) >= NTIMER)
10950 ERRMSG("Too many timers!");
10951 }
10952
10953 /* Check whether this is a new group... */
10954 if (igroup >= ngroup) {
10955 sprintf(groups[igroup], "%s", group);
10956 if ((++ngroup) >= NTIMER)
10957 ERRMSG("Too many groups!");
10958 }
10959
10960 /* Save starting time... */
10961 t0 = t1;
10962}
10963
10964/*****************************************************************************/
10965
10967 const char *filename,
10968 const int offset) {
10969
10970 char tstr[10];
10971
10972 double t;
10973
10974 /* Get time from filename... */
10975 int len = (int) strlen(filename);
10976 sprintf(tstr, "%.4s", &filename[len - offset]);
10977 int year = atoi(tstr);
10978 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
10979 int mon = atoi(tstr);
10980 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
10981 int day = atoi(tstr);
10982 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
10983 int hour = atoi(tstr);
10984 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
10985 int min = atoi(tstr);
10986
10987 /* Check time... */
10988 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
10989 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
10990 ERRMSG("Cannot read time from filename!");
10991
10992 /* Convert time to Julian seconds... */
10993 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
10994
10995 /* Return time... */
10996 return t;
10997}
10998
10999/*****************************************************************************/
11000
11002 const clim_t *clim,
11003 const atm_t *atm,
11004 const int ip) {
11005
11006 /* Get tropopause pressure... */
11007 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
11008
11009 /* Get pressure range... */
11010 const double p1 = pt * 0.866877899;
11011 const double p0 = pt / 0.866877899;
11012
11013 /* Get weighting factor... */
11014 if (atm->p[ip] > p0)
11015 return 1;
11016 else if (atm->p[ip] < p1)
11017 return 0;
11018 else
11019 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
11020}
11021
11022/*****************************************************************************/
11023
11025 const char *filename,
11026 const ctl_t *ctl,
11027 const atm_t *atm,
11028 const double t) {
11029
11030 FILE *out;
11031
11032 /* Set time interval for output... */
11033 const double t0 = t - 0.5 * ctl->dt_mod;
11034 const double t1 = t + 0.5 * ctl->dt_mod;
11035
11036 /* Check if gnuplot output is requested... */
11037 if (ctl->atm_gpfile[0] != '-') {
11038
11039 /* Create gnuplot pipe... */
11040 if (!(out = popen("gnuplot", "w")))
11041 ERRMSG("Cannot create pipe to gnuplot!");
11042
11043 /* Set plot filename... */
11044 fprintf(out, "set out \"%s.png\"\n", filename);
11045
11046 /* Set time string... */
11047 double r;
11048 int year, mon, day, hour, min, sec;
11049 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11050 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
11051 year, mon, day, hour, min);
11052
11053 /* Dump gnuplot file to pipe... */
11054 FILE *in;
11055 if (!(in = fopen(ctl->atm_gpfile, "r")))
11056 ERRMSG("Cannot open file!");
11057 char line[LEN];
11058 while (fgets(line, LEN, in))
11059 fprintf(out, "%s", line);
11060 fclose(in);
11061 }
11062
11063 else {
11064
11065 /* Create file... */
11066 if (!(out = fopen(filename, "w")))
11067 ERRMSG("Cannot create file!");
11068 }
11069
11070 /* Write header... */
11071 fprintf(out,
11072 "# $1 = time [s]\n"
11073 "# $2 = altitude [km]\n"
11074 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11075 for (int iq = 0; iq < ctl->nq; iq++)
11076 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
11077 ctl->qnt_unit[iq]);
11078 fprintf(out, "\n");
11079
11080 /* Write data... */
11081 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
11082
11083 /* Check time... */
11084 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11085 continue;
11086
11087 /* Write output... */
11088 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
11089 atm->lon[ip], atm->lat[ip]);
11090 for (int iq = 0; iq < ctl->nq; iq++) {
11091 fprintf(out, " ");
11092 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11093 fprintf(out, ctl->qnt_format[iq], NAN);
11094 else
11095 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11096 }
11097 fprintf(out, "\n");
11098 }
11099
11100 /* Close file... */
11101 fclose(out);
11102}
11103
11104/*****************************************************************************/
11105
11107 const char *filename,
11108 const ctl_t *ctl,
11109 const atm_t *atm) {
11110
11111 FILE *out;
11112
11113 /* Create file... */
11114 if (!(out = fopen(filename, "w")))
11115 ERRMSG("Cannot create file!");
11116
11117 /* Write version of binary data... */
11118 int version = 100;
11119 FWRITE(&version, int,
11120 1,
11121 out);
11122
11123 /* Write data... */
11124 FWRITE(&atm->np, int,
11125 1,
11126 out);
11127 FWRITE(atm->time, double,
11128 (size_t) atm->np,
11129 out);
11130 FWRITE(atm->p, double,
11131 (size_t) atm->np,
11132 out);
11133 FWRITE(atm->lon, double,
11134 (size_t) atm->np,
11135 out);
11136 FWRITE(atm->lat, double,
11137 (size_t) atm->np,
11138 out);
11139 for (int iq = 0; iq < ctl->nq; iq++)
11140 FWRITE(atm->q[iq], double,
11141 (size_t) atm->np,
11142 out);
11143
11144 /* Write final flag... */
11145 int final = 999;
11146 FWRITE(&final, int,
11147 1,
11148 out);
11149
11150 /* Close file... */
11151 fclose(out);
11152}
11153
11154/*****************************************************************************/
11155
11157 const char *filename,
11158 const ctl_t *ctl,
11159 const atm_t *atm) {
11160
11161 int tid, pid, ncid, varid;
11162 size_t start[2], count[2];
11163
11164 /* Create file... */
11165 nc_create(filename, NC_NETCDF4, &ncid);
11166
11167 /* Define dimensions... */
11168 NC(nc_def_dim(ncid, "time", 1, &tid));
11169 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11170
11171 /* Define variables and their attributes... */
11172 int dim_ids[2] = { tid, pid };
11173 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11174 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11175 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11176 ctl->atm_nc_level, 0);
11177 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11178 ctl->atm_nc_level, 0);
11179 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11180 ctl->atm_nc_level, 0);
11181 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11182 for (int iq = 0; iq < ctl->nq; iq++)
11183 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11184 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11185 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11186
11187 /* Define global attributes... */
11188 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11189 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11190
11191 /* End definitions... */
11192 NC(nc_enddef(ncid));
11193
11194 /* Write data... */
11195 NC_PUT_DOUBLE("time", atm->time, 0);
11196 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11197 NC_PUT_DOUBLE("LON", atm->lon, 0);
11198 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11199 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11200 for (int iq = 0; iq < ctl->nq; iq++)
11201 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11202
11203 /* Close file... */
11204 NC(nc_close(ncid));
11205}
11206
11207/*****************************************************************************/
11208
11210 const char *dirname,
11211 const ctl_t *ctl,
11212 const atm_t *atm,
11213 const double t) {
11214
11215 /* Global Counter... */
11216 static size_t out_cnt = 0;
11217
11218 double r, r_start, r_stop;
11219 int year, mon, day, hour, min, sec;
11220 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
11221 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
11222 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
11223
11224 int ncid, varid, tid, pid, cid;
11225 int dim_ids[2];
11226
11227 /* time, nparc */
11228 size_t start[2];
11229 size_t count[2];
11230
11231 /* Determine start and stop times of calculation... */
11232 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11233 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
11234 &min_start, &sec_start, &r_start);
11235 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
11236 &min_stop, &sec_stop, &r_stop);
11237
11238 sprintf(filename_out,
11239 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
11240 year_start % 100, mon_start, day_start, hour_start,
11241 year_stop % 100, mon_stop, day_stop, hour_stop);
11242 LOG(1, "Write traj file: %s", filename_out);
11243
11244 /* Define hyperslap for the traj_file... */
11245 start[0] = out_cnt;
11246 start[1] = 0;
11247 count[0] = 1;
11248 count[1] = (size_t) atm->np;
11249
11250 /* Create the file at the first timestep... */
11251 if (out_cnt == 0) {
11252
11253 /* Create file... */
11254 nc_create(filename_out, NC_NETCDF4, &ncid);
11255
11256 /* Define dimensions... */
11257 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
11258 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11259 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
11260 dim_ids[0] = tid;
11261 dim_ids[1] = pid;
11262
11263 /* Define variables and their attributes... */
11264 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11265 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11266 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
11267 ctl->atm_nc_level, 0);
11268 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
11269 ctl->atm_nc_level, 0);
11270 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
11271 ctl->atm_nc_level, 0);
11272 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
11273 ctl->atm_nc_level, 0);
11274 for (int iq = 0; iq < ctl->nq; iq++)
11275 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11276 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11277 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11278
11279 /* Define global attributes... */
11280 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11281 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11282
11283 /* End definitions... */
11284 NC(nc_enddef(ncid));
11285 NC(nc_close(ncid));
11286 }
11287
11288 /* Increment global counter to change hyperslap... */
11289 out_cnt++;
11290
11291 /* Open file... */
11292 NC(nc_open(filename_out, NC_WRITE, &ncid));
11293
11294 /* Write data... */
11295 NC_PUT_DOUBLE("time", atm->time, 1);
11296 NC_PUT_DOUBLE("LAT", atm->lat, 1);
11297 NC_PUT_DOUBLE("LON", atm->lon, 1);
11298 NC_PUT_DOUBLE("PRESS", atm->p, 1);
11299 if (ctl->advect_vert_coord == 1) {
11300 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
11301 } else if (ctl->qnt_zeta >= 0) {
11302 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
11303 }
11304 for (int iq = 0; iq < ctl->nq; iq++)
11305 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
11306
11307 /* Close file... */
11308 NC(nc_close(ncid));
11309
11310 /* At the last time step create the init_fix_YYYYMMDDHH file... */
11311 if ((year == year_stop) && (mon == mon_stop)
11312 && (day == day_stop) && (hour == hour_stop)) {
11313
11314 /* Set filename... */
11315 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
11316 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
11317 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
11318 LOG(1, "Write init file: %s", filename_init);
11319
11320 /* Create file... */
11321 nc_create(filename_init, NC_NETCDF4, &ncid);
11322
11323 /* Define dimensions... */
11324 NC(nc_def_dim(ncid, "time", 1, &tid));
11325 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11326 dim_ids[0] = tid;
11327 dim_ids[1] = pid;
11328
11329 /* Define variables and their attributes... */
11330 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11331 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11332 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11333 ctl->atm_nc_level, 0);
11334 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11335 ctl->atm_nc_level, 0);
11336 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11337 ctl->atm_nc_level, 0);
11338 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11339 for (int iq = 0; iq < ctl->nq; iq++)
11340 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11341 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11342 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11343
11344 /* Define global attributes... */
11345 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11346 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11347
11348 /* End definitions... */
11349 NC(nc_enddef(ncid));
11350
11351 /* Write data... */
11352 NC_PUT_DOUBLE("time", atm->time, 0);
11353 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11354 NC_PUT_DOUBLE("LON", atm->lon, 0);
11355 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11356 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11357 for (int iq = 0; iq < ctl->nq; iq++)
11358 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11359
11360 /* Close file... */
11361 NC(nc_close(ncid));
11362 }
11363}
11364
11365/*****************************************************************************/
11366
11368 const char *filename,
11369 const ctl_t *ctl,
11370 const atm_t *atm) {
11371
11372 int ncid, obsid, varid;
11373
11374 size_t start[2], count[2];
11375
11376 /* Create file... */
11377 NC(nc_create(filename, NC_NETCDF4, &ncid));
11378
11379 /* Define dimensions... */
11380 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
11381
11382 /* Define variables and their attributes... */
11383 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
11384 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11385 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
11386 ctl->atm_nc_level, 0);
11387 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
11388 ctl->atm_nc_level, 0);
11389 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
11390 ctl->atm_nc_level, 0);
11391 for (int iq = 0; iq < ctl->nq; iq++)
11392 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
11393 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
11394 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11395
11396 /* Define global attributes... */
11397 NC_PUT_ATT_GLOBAL("featureType", "point");
11398
11399 /* End definitions... */
11400 NC(nc_enddef(ncid));
11401
11402 /* Write data... */
11403 NC_PUT_DOUBLE("time", atm->time, 0);
11404 NC_PUT_DOUBLE("press", atm->p, 0);
11405 NC_PUT_DOUBLE("lon", atm->lon, 0);
11406 NC_PUT_DOUBLE("lat", atm->lat, 0);
11407 for (int iq = 0; iq < ctl->nq; iq++)
11408 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11409
11410 /* Close file... */
11411 NC(nc_close(ncid));
11412}
11413
11414/*****************************************************************************/
11415
11417 const char *filename,
11418 const ctl_t *ctl,
11419 const atm_t *atm,
11420 const double t) {
11421
11422 static FILE *out;
11423
11424 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
11425 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
11426
11427 static int *obscount, nobs, nk;
11428
11429 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
11430
11431 const int ensemble = (ctl->nens > 0);
11432
11433 /* Set timer */
11434 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
11435
11436 /* Check quantities... */
11437 if (ctl->qnt_m < 0)
11438 ERRMSG("Need quantity mass!");
11439 if (ensemble) {
11440 if (ctl->qnt_ens < 0)
11441 ERRMSG("Missing ensemble IDs!");
11442 if (ctl->nens > NENS)
11443 ERRMSG("Too many ensembles!");
11444 }
11445
11446 /* Init... */
11447 if (t == ctl->t_start) {
11448
11449 /* Allocate.. */
11450 ALLOC(area, double,
11451 ctl->csi_ny);
11452 ALLOC(rt, double,
11453 NOBS);
11454 ALLOC(rz, double,
11455 NOBS);
11456 ALLOC(rlon, double,
11457 NOBS);
11458 ALLOC(rlat, double,
11459 NOBS);
11460 ALLOC(robs, double,
11461 NOBS);
11462
11463 /* Read observation data... */
11464 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11465
11466 /* Read kernel data... */
11467 if (ctl->csi_kernel[0] != '-')
11468 read_kernel(ctl->csi_kernel, kz, kw, &nk);
11469
11470 /* Create new file... */
11471 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
11472 if (!(out = fopen(filename, "w")))
11473 ERRMSG("Cannot create file!");
11474
11475 /* Write header... */
11476 fprintf(out,
11477 "# $1 = time [s]\n"
11478 "# $2 = ensemble ID\n"
11479 "# $3 = number of hits (cx)\n"
11480 "# $4 = number of misses (cy)\n"
11481 "# $5 = number of false alarms (cz)\n"
11482 "# $6 = number of observations (cx + cy)\n"
11483 "# $7 = number of forecasts (cx + cz)\n"
11484 "# $8 = bias (%%)\n"
11485 "# $9 = POD (%%)\n"
11486 "# $10 = FAR (%%)\n"
11487 "# $11 = CSI (%%)\n"
11488 "# $12 = hits by random chance\n"
11489 "# $13 = ETS (%%)\n"
11490 "# $14 = Pearson R\n"
11491 "# $15 = Spearman R\n"
11492 "# $16 = mean error [kg/m²]\n"
11493 "# $17 = RMSE [kg/m²]\n"
11494 "# $18 = MAE [kg/m²]\n"
11495 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
11496
11497 /* Set grid box size... */
11498 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
11499 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
11500 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
11501
11502 /* Set horizontal coordinates... */
11503 for (int iy = 0; iy < ctl->csi_ny; iy++) {
11504 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
11505 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
11506 }
11507 }
11508
11509 /* Set time interval... */
11510 const double t0 = t - 0.5 * ctl->dt_mod;
11511 const double t1 = t + 0.5 * ctl->dt_mod;
11512
11513 /* Allocate... */
11514 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
11515 ALLOC(modmean, double,
11516 (ensemble ? ctl->nens : 1) * grid_size);
11517 ALLOC(obsmean, double,
11518 grid_size);
11519 ALLOC(obscount, int,
11520 grid_size);
11521 ALLOC(obsstd, double,
11522 grid_size);
11523
11524 /* Init... */
11525 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
11526 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
11527
11528 /* Loop over observations... */
11529 for (int i = 0; i < nobs; i++) {
11530 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
11531 continue;
11532
11533 /* Calculate indices... */
11534 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
11535 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
11536 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
11537 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11538 || iz >= ctl->csi_nz)
11539 continue;
11540
11541 /* Get mean observation index... */
11542 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11543 obsmean[idx] += robs[i];
11544 obsstd[idx] += SQR(robs[i]);
11545 obscount[idx]++;
11546 }
11547
11548 /* Analyze model data... */
11549 for (int ip = 0; ip < atm->np; ip++) {
11550
11551 /* Check time... */
11552 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11553 continue;
11554
11555 /* Get ensemble ID... */
11556 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
11557 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
11558 ERRMSG("Ensemble ID out of range!");
11559
11560 /* Get indices... */
11561 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
11562 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
11563 const int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
11564 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11565 || iz >= ctl->csi_nz)
11566 continue;
11567
11568 /* Get total mass in grid cell... */
11569 const int idx =
11570 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11571 modmean[idx] +=
11572 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11573 }
11574
11575 /* Analyze all grid cells... */
11576 for (int ix = 0; ix < ctl->csi_nx; ix++)
11577 for (int iy = 0; iy < ctl->csi_ny; iy++)
11578 for (int iz = 0; iz < ctl->csi_nz; iz++) {
11579
11580 /* Calculate mean observation index... */
11581 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11582 if (obscount[idx]) {
11583 obsmean[idx] /= obscount[idx];
11584 obsstd[idx] = sqrt(obsstd[idx] - SQR(obsmean[idx]));
11585 }
11586
11587 /* Calculate model mean per ensemble... */
11588 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11589 const int midx = e * grid_size + idx;
11590 if (modmean[midx] > 0)
11591 modmean[midx] /= (1e6 * area[iy]);
11592 }
11593
11594 /* Check number of observations... */
11595 if (obscount[idx]) {
11596
11597 /* Calculate CSI... */
11598 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11599 const int midx = e * grid_size + idx;
11600 ct[e]++;
11601 if (obsmean[idx] >= ctl->csi_obsmin
11602 && modmean[midx] >= ctl->csi_modmin)
11603 cx[e]++;
11604 else if (obsmean[idx] >= ctl->csi_obsmin)
11605 cy[e]++;
11606 else if (modmean[midx] >= ctl->csi_modmin)
11607 cz[e]++;
11608
11609 /* Save data for other verification statistics... */
11610 if (obsmean[idx] >= ctl->csi_obsmin
11611 || modmean[midx] >= ctl->csi_modmin) {
11612 x[n[e]] = modmean[midx];
11613 y[n[e]] = obsmean[idx];
11614 if (modmean[midx] >= ctl->csi_modmin)
11615 obsstdn[n[e]] = obsstd[idx];
11616 if ((++n[e]) >= NCSI)
11617 ERRMSG("Too many points for statistics!");
11618 }
11619 }
11620 }
11621 }
11622
11623 /* Write output... */
11624 if (fmod(t, ctl->csi_dt_out) == 0) {
11625 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11626
11627 if (n[e] == 0)
11628 continue;
11629
11630 /* Calculate verification statistics
11631 (https://www.cawcr.gov.au/projects/verification/) ... */
11632 static double work[2 * NCSI], work2[2 * NCSI];
11633 const int n_obs = cx[e] + cy[e];
11634 const int n_for = cx[e] + cz[e];
11635 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
11636 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
11637 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
11638 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
11639 const double csi =
11640 (cx[e] + cy[e] + cz[e] >
11641 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
11642 const double ets =
11643 (cx[e] + cy[e] + cz[e] - cx_rd >
11644 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
11645 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
11646 const double rho_s =
11647 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
11648 for (int i = 0; i < n[e]; i++) {
11649 work[i] = x[i] - y[i];
11650 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
11651 }
11652 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
11653 const double rmse =
11654 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
11655 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
11656 const double loglikelihood =
11657 gsl_stats_tss(work2, 1, (size_t) n[e]) * -0.5;
11658
11659 /* Write... */
11660 fprintf(out,
11661 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
11662 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
11663 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
11664 loglikelihood, n[e]);
11665
11666 /* Set counters to zero... */
11667 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
11668 }
11669 }
11670
11671 /* Free... */
11672 free(modmean);
11673 free(obsmean);
11674 free(obscount);
11675 free(obsstd);
11676
11677 /* Finalize... */
11678 if (t == ctl->t_stop) {
11679
11680 /* Close output file... */
11681 fclose(out);
11682
11683 /* Free... */
11684 free(area);
11685 free(rt);
11686 free(rz);
11687 free(rlon);
11688 free(rlat);
11689 free(robs);
11690 }
11691}
11692
11693/*****************************************************************************/
11694
11696 const char *filename,
11697 const ctl_t *ctl,
11698 const atm_t *atm,
11699 const double t) {
11700
11701 static FILE *out;
11702
11703 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
11704 x[3], zm[NENS];
11705
11706 static int n[NENS];
11707
11708 /* Set timer... */
11709 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
11710
11711 /* Check quantities... */
11712 if (ctl->qnt_ens < 0)
11713 ERRMSG("Missing ensemble IDs!");
11714
11715 /* Set time interval... */
11716 const double t0 = t - 0.5 * ctl->dt_mod;
11717 const double t1 = t + 0.5 * ctl->dt_mod;
11718
11719 /* Init... */
11720 for (int i = 0; i < NENS; i++) {
11721 for (int iq = 0; iq < ctl->nq; iq++)
11722 qm[iq][i] = qs[iq][i] = 0;
11723 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
11724 n[i] = 0;
11725 }
11726
11727 /* Loop over air parcels... */
11728 for (int ip = 0; ip < atm->np; ip++) {
11729
11730 /* Check time... */
11731 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11732 continue;
11733
11734 /* Check ensemble ID... */
11735 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
11736 ERRMSG("Ensemble ID is out of range!");
11737
11738 /* Get means... */
11739 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
11740 for (int iq = 0; iq < ctl->nq; iq++) {
11741 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
11742 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
11743 }
11744 xm[ctl->qnt_ens][0] += x[0];
11745 xm[ctl->qnt_ens][1] += x[1];
11746 xm[ctl->qnt_ens][2] += x[2];
11747 zm[ctl->qnt_ens] += Z(atm->p[ip]);
11748 n[ctl->qnt_ens]++;
11749 }
11750
11751 /* Create file... */
11752 LOG(1, "Write ensemble data: %s", filename);
11753 if (!(out = fopen(filename, "w")))
11754 ERRMSG("Cannot create file!");
11755
11756 /* Write header... */
11757 fprintf(out,
11758 "# $1 = time [s]\n"
11759 "# $2 = altitude [km]\n"
11760 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11761 for (int iq = 0; iq < ctl->nq; iq++)
11762 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
11763 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11764 for (int iq = 0; iq < ctl->nq; iq++)
11765 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
11766 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11767 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
11768
11769 /* Write data... */
11770 for (int i = 0; i < NENS; i++)
11771 if (n[i] > 0) {
11772 cart2geo(xm[i], &dummy, &lon, &lat);
11773 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
11774 for (int iq = 0; iq < ctl->nq; iq++) {
11775 fprintf(out, " ");
11776 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
11777 }
11778 for (int iq = 0; iq < ctl->nq; iq++) {
11779 fprintf(out, " ");
11780 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
11781 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
11782 }
11783 fprintf(out, " %d\n", n[i]);
11784 }
11785
11786 /* Close file... */
11787 fclose(out);
11788}
11789
11790/*****************************************************************************/
11791
11793 const char *filename,
11794 const ctl_t *ctl,
11795 met_t *met0,
11796 met_t *met1,
11797 const atm_t *atm,
11798 const double t) {
11799
11800 static double kz[EP], kw[EP];
11801
11802 static int nk;
11803
11804 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
11805
11806 int *ixs, *iys, *izs, *np;
11807
11808 /* Set timer... */
11809 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
11810
11811 /* Write info... */
11812 LOG(1, "Write grid data: %s", filename);
11813
11814 /* Init... */
11815 if (t == ctl->t_start) {
11816
11817 /* Read kernel data... */
11818 if (ctl->grid_kernel[0] != '-')
11819 read_kernel(ctl->grid_kernel, kz, kw, &nk);
11820 }
11821
11822 /* Allocate... */
11823 ALLOC(cd, double,
11824 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11825 for (int iq = 0; iq < ctl->nq; iq++) {
11826 ALLOC(mean[iq], double,
11827 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11828 ALLOC(sigma[iq], double,
11829 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11830 }
11831 ALLOC(vmr_impl, double,
11832 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11833 ALLOC(z, double,
11834 ctl->grid_nz);
11835 ALLOC(lon, double,
11836 ctl->grid_nx);
11837 ALLOC(lat, double,
11838 ctl->grid_ny);
11839 ALLOC(area, double,
11840 ctl->grid_ny);
11841 ALLOC(press, double,
11842 ctl->grid_nz);
11843 ALLOC(np, int,
11844 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11845 ALLOC(ixs, int,
11846 atm->np);
11847 ALLOC(iys, int,
11848 atm->np);
11849 ALLOC(izs, int,
11850 atm->np);
11851
11852 /* Set grid box size... */
11853 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
11854 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
11855 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
11856
11857 /* Set vertical coordinates... */
11858#pragma omp parallel for default(shared)
11859 for (int iz = 0; iz < ctl->grid_nz; iz++) {
11860 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
11861 press[iz] = P(z[iz]);
11862 }
11863
11864 /* Set horizontal coordinates... */
11865 for (int ix = 0; ix < ctl->grid_nx; ix++)
11866 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
11867#pragma omp parallel for default(shared)
11868 for (int iy = 0; iy < ctl->grid_ny; iy++) {
11869 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
11870 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
11871 }
11872
11873 /* Set time interval for output... */
11874 const double t0 = t - 0.5 * ctl->dt_mod;
11875 const double t1 = t + 0.5 * ctl->dt_mod;
11876
11877 /* Get grid box indices... */
11878#pragma omp parallel for default(shared)
11879 for (int ip = 0; ip < atm->np; ip++) {
11880 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
11881 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
11882 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
11883 if (atm->time[ip] < t0 || atm->time[ip] > t1
11884 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
11885 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
11886 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
11887 izs[ip] = -1;
11888 }
11889
11890 /* Average data... */
11891 for (int ip = 0; ip < atm->np; ip++)
11892 if (izs[ip] >= 0) {
11893 const int idx =
11894 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
11895 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
11896 np[idx]++;
11897 for (int iq = 0; iq < ctl->nq; iq++) {
11898 mean[iq][idx] += kernel * atm->q[iq][ip];
11899 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
11900 }
11901 }
11902
11903 /* Calculate column density and volume mixing ratio... */
11904#pragma omp parallel for default(shared)
11905 for (int ix = 0; ix < ctl->grid_nx; ix++)
11906 for (int iy = 0; iy < ctl->grid_ny; iy++)
11907 for (int iz = 0; iz < ctl->grid_nz; iz++) {
11908
11909 /* Get grid index... */
11910 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
11911
11912 /* Calculate column density... */
11913 cd[idx] = NAN;
11914 if (ctl->qnt_m >= 0)
11915 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
11916
11917 /* Calculate volume mixing ratio (implicit)... */
11918 vmr_impl[idx] = NAN;
11919 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
11920 && met1 != NULL) {
11921 vmr_impl[idx] = 0;
11922 if (mean[ctl->qnt_m][idx] > 0) {
11923
11924 /* Get temperature... */
11925 double temp;
11927 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
11928 lon[ix], lat[iy], &temp, ci, cw, 1);
11929
11930 /* Calculate volume mixing ratio... */
11931 vmr_impl[idx] =
11932 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
11933 }
11934 }
11935
11936 /* Calculate mean... */
11937 if (np[idx] > 0)
11938 for (int iq = 0; iq < ctl->nq; iq++) {
11939 mean[iq][idx] /= np[idx];
11940 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
11941 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
11942 } else
11943 for (int iq = 0; iq < ctl->nq; iq++) {
11944 mean[iq][idx] = NAN;
11945 sigma[iq][idx] = NAN;
11946 }
11947 }
11948
11949 /* Write ASCII data... */
11950 if (ctl->grid_type == 0)
11951 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
11952 t, z, lon, lat, area, dz, np);
11953
11954 /* Write netCDF data... */
11955 else if (ctl->grid_type == 1)
11956 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
11957 t, z, lon, lat, area, dz, np);
11958
11959 /* Error message... */
11960 else
11961 ERRMSG("Grid data format GRID_TYPE unknown!");
11962
11963 /* Free... */
11964 free(cd);
11965 for (int iq = 0; iq < ctl->nq; iq++) {
11966 free(mean[iq]);
11967 free(sigma[iq]);
11968 }
11969 free(vmr_impl);
11970 free(z);
11971 free(lon);
11972 free(lat);
11973 free(area);
11974 free(press);
11975 free(np);
11976 free(ixs);
11977 free(iys);
11978 free(izs);
11979}
11980
11981/*****************************************************************************/
11982
11984 const char *filename,
11985 const ctl_t *ctl,
11986 const double *cd,
11987 double *mean[NQ],
11988 double *sigma[NQ],
11989 const double *vmr_impl,
11990 const double t,
11991 const double *z,
11992 const double *lon,
11993 const double *lat,
11994 const double *area,
11995 const double dz,
11996 const int *np) {
11997
11998 FILE *out;
11999
12000 /* Check if gnuplot output is requested... */
12001 if (ctl->grid_gpfile[0] != '-') {
12002
12003 /* Create gnuplot pipe... */
12004 if (!(out = popen("gnuplot", "w")))
12005 ERRMSG("Cannot create pipe to gnuplot!");
12006
12007 /* Set plot filename... */
12008 fprintf(out, "set out \"%s.png\"\n", filename);
12009
12010 /* Set time string... */
12011 double r;
12012 int year, mon, day, hour, min, sec;
12013 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12014 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12015 year, mon, day, hour, min);
12016
12017 /* Dump gnuplot file to pipe... */
12018 FILE *in;
12019 char line[LEN];
12020 if (!(in = fopen(ctl->grid_gpfile, "r")))
12021 ERRMSG("Cannot open file!");
12022 while (fgets(line, LEN, in))
12023 fprintf(out, "%s", line);
12024 fclose(in);
12025 }
12026
12027 else {
12028
12029 /* Create file... */
12030 if (!(out = fopen(filename, "w")))
12031 ERRMSG("Cannot create file!");
12032 }
12033
12034 /* Write header... */
12035 fprintf(out,
12036 "# $1 = time [s]\n"
12037 "# $2 = altitude [km]\n"
12038 "# $3 = longitude [deg]\n"
12039 "# $4 = latitude [deg]\n"
12040 "# $5 = surface area [km^2]\n"
12041 "# $6 = layer depth [km]\n"
12042 "# $7 = column density (implicit) [kg/m^2]\n"
12043 "# $8 = volume mixing ratio (implicit) [ppv]\n"
12044 "# $9 = number of particles [1]\n");
12045 for (int iq = 0; iq < ctl->nq; iq++)
12046 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
12047 ctl->qnt_unit[iq]);
12048 if (ctl->grid_stddev)
12049 for (int iq = 0; iq < ctl->nq; iq++)
12050 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
12051 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12052 fprintf(out, "\n");
12053
12054 /* Write data... */
12055 for (int ix = 0; ix < ctl->grid_nx; ix++) {
12056 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
12057 fprintf(out, "\n");
12058 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12059 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
12060 fprintf(out, "\n");
12061 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12062 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12063 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
12064 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
12065 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
12066 for (int iq = 0; iq < ctl->nq; iq++) {
12067 fprintf(out, " ");
12068 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
12069 }
12070 if (ctl->grid_stddev)
12071 for (int iq = 0; iq < ctl->nq; iq++) {
12072 fprintf(out, " ");
12073 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
12074 }
12075 fprintf(out, "\n");
12076 }
12077 }
12078 }
12079 }
12080
12081 /* Close file... */
12082 fclose(out);
12083}
12084
12085/*****************************************************************************/
12086
12088 const char *filename,
12089 const ctl_t *ctl,
12090 const double *cd,
12091 double *mean[NQ],
12092 double *sigma[NQ],
12093 const double *vmr_impl,
12094 const double t,
12095 const double *z,
12096 const double *lon,
12097 const double *lat,
12098 const double *area,
12099 const double dz,
12100 const int *np) {
12101
12102 char longname[2 * LEN], varname[2 * LEN];
12103
12104 double *help;
12105
12106 int *help2, ncid, dimid[10], varid;
12107
12108 size_t start[2], count[2];
12109
12110 /* Allocate... */
12111 ALLOC(help, double,
12112 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12113 ALLOC(help2, int,
12114 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12115
12116 /* Create file... */
12117 NC(nc_create(filename, NC_NETCDF4, &ncid));
12118
12119 /* Define dimensions... */
12120 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
12121 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
12122 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
12123 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
12124 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
12125
12126 /* Define variables and their attributes... */
12127 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
12128 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12129 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
12130 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
12131 0);
12132 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
12133 0);
12134 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
12135 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
12136
12137 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
12138 ctl->grid_nc_level, 0);
12139 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
12140 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
12141 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
12142 for (int iq = 0; iq < ctl->nq; iq++) {
12143 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12144 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
12145 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12146 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12147 if (ctl->grid_stddev) {
12148 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12149 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
12150 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12151 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12152 }
12153 }
12154 /* End definitions... */
12155 NC(nc_enddef(ncid));
12156
12157 /* Write data... */
12158 NC_PUT_DOUBLE("time", &t, 0);
12159 NC_PUT_DOUBLE("lon", lon, 0);
12160 NC_PUT_DOUBLE("lat", lat, 0);
12161 NC_PUT_DOUBLE("z", z, 0);
12162 NC_PUT_DOUBLE("area", area, 0);
12163 NC_PUT_DOUBLE("dz", &dz, 0);
12164
12165 for (int ix = 0; ix < ctl->grid_nx; ix++)
12166 for (int iy = 0; iy < ctl->grid_ny; iy++)
12167 for (int iz = 0; iz < ctl->grid_nz; iz++)
12168 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12169 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12170 NC_PUT_DOUBLE("cd", help, 0);
12171
12172 for (int ix = 0; ix < ctl->grid_nx; ix++)
12173 for (int iy = 0; iy < ctl->grid_ny; iy++)
12174 for (int iz = 0; iz < ctl->grid_nz; iz++)
12175 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12176 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12177 NC_PUT_DOUBLE("vmr_impl", help, 0);
12178
12179 for (int ix = 0; ix < ctl->grid_nx; ix++)
12180 for (int iy = 0; iy < ctl->grid_ny; iy++)
12181 for (int iz = 0; iz < ctl->grid_nz; iz++)
12182 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12183 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12184 NC_PUT_INT("np", help2, 0);
12185
12186 for (int iq = 0; iq < ctl->nq; iq++) {
12187 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12188 for (int ix = 0; ix < ctl->grid_nx; ix++)
12189 for (int iy = 0; iy < ctl->grid_ny; iy++)
12190 for (int iz = 0; iz < ctl->grid_nz; iz++)
12191 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12192 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12193 NC_PUT_DOUBLE(varname, help, 0);
12194 }
12195
12196 if (ctl->grid_stddev)
12197 for (int iq = 0; iq < ctl->nq; iq++) {
12198 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12199 for (int ix = 0; ix < ctl->grid_nx; ix++)
12200 for (int iy = 0; iy < ctl->grid_ny; iy++)
12201 for (int iz = 0; iz < ctl->grid_nz; iz++)
12202 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12203 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12204 NC_PUT_DOUBLE(varname, help, 0);
12205 }
12206
12207 /* Close file... */
12208 NC(nc_close(ncid));
12209
12210 /* Free... */
12211 free(help);
12212 free(help2);
12213}
12214
12215/*****************************************************************************/
12216
12218 const char *filename,
12219 const ctl_t *ctl,
12220 met_t *met) {
12221
12222 /* Create file... */
12223 FILE *out;
12224 if (!(out = fopen(filename, "w")))
12225 ERRMSG("Cannot create file!");
12226
12227 /* Write type of binary data... */
12228 FWRITE(&ctl->met_type, int,
12229 1,
12230 out);
12231
12232 /* Write version of binary data... */
12233 int version = 103;
12234 FWRITE(&version, int,
12235 1,
12236 out);
12237
12238 /* Write grid data... */
12239 FWRITE(&met->time, double,
12240 1,
12241 out);
12242 FWRITE(&met->nx, int,
12243 1,
12244 out);
12245 FWRITE(&met->ny, int,
12246 1,
12247 out);
12248 FWRITE(&met->np, int,
12249 1,
12250 out);
12251 FWRITE(met->lon, double,
12252 (size_t) met->nx,
12253 out);
12254 FWRITE(met->lat, double,
12255 (size_t) met->ny,
12256 out);
12257 FWRITE(met->p, double,
12258 (size_t) met->np,
12259 out);
12260
12261 /* Write surface data... */
12262 write_met_bin_2d(out, met, met->ps, "PS");
12263 write_met_bin_2d(out, met, met->ts, "TS");
12264 write_met_bin_2d(out, met, met->zs, "ZS");
12265 write_met_bin_2d(out, met, met->us, "US");
12266 write_met_bin_2d(out, met, met->vs, "VS");
12267 write_met_bin_2d(out, met, met->ess, "ESS");
12268 write_met_bin_2d(out, met, met->nss, "NSS");
12269 write_met_bin_2d(out, met, met->shf, "SHF");
12270 write_met_bin_2d(out, met, met->lsm, "LSM");
12271 write_met_bin_2d(out, met, met->sst, "SST");
12272 write_met_bin_2d(out, met, met->pbl, "PBL");
12273 write_met_bin_2d(out, met, met->pt, "PT");
12274 write_met_bin_2d(out, met, met->tt, "TT");
12275 write_met_bin_2d(out, met, met->zt, "ZT");
12276 write_met_bin_2d(out, met, met->h2ot, "H2OT");
12277 write_met_bin_2d(out, met, met->pct, "PCT");
12278 write_met_bin_2d(out, met, met->pcb, "PCB");
12279 write_met_bin_2d(out, met, met->cl, "CL");
12280 write_met_bin_2d(out, met, met->plcl, "PLCL");
12281 write_met_bin_2d(out, met, met->plfc, "PLFC");
12282 write_met_bin_2d(out, met, met->pel, "PEL");
12283 write_met_bin_2d(out, met, met->cape, "CAPE");
12284 write_met_bin_2d(out, met, met->cin, "CIN");
12285 write_met_bin_2d(out, met, met->o3c, "O3C");
12286
12287 /* Write level data... */
12288 write_met_bin_3d(out, ctl, met, met->z, "Z",
12289 ctl->met_comp_prec[0], ctl->met_comp_tol[0]);
12290 write_met_bin_3d(out, ctl, met, met->t, "T",
12291 ctl->met_comp_prec[1], ctl->met_comp_tol[1]);
12292 write_met_bin_3d(out, ctl, met, met->u, "U",
12293 ctl->met_comp_prec[2], ctl->met_comp_tol[2]);
12294 write_met_bin_3d(out, ctl, met, met->v, "V",
12295 ctl->met_comp_prec[3], ctl->met_comp_tol[3]);
12296 write_met_bin_3d(out, ctl, met, met->w, "W",
12297 ctl->met_comp_prec[4], ctl->met_comp_tol[4]);
12298 write_met_bin_3d(out, ctl, met, met->pv, "PV",
12299 ctl->met_comp_prec[5], ctl->met_comp_tol[5]);
12300 write_met_bin_3d(out, ctl, met, met->h2o, "H2O",
12301 ctl->met_comp_prec[6], ctl->met_comp_tol[6]);
12302 write_met_bin_3d(out, ctl, met, met->o3, "O3",
12303 ctl->met_comp_prec[7], ctl->met_comp_tol[7]);
12304 write_met_bin_3d(out, ctl, met, met->lwc, "LWC",
12305 ctl->met_comp_prec[8], ctl->met_comp_tol[8]);
12306 write_met_bin_3d(out, ctl, met, met->rwc, "RWC",
12307 ctl->met_comp_prec[9], ctl->met_comp_tol[9]);
12308 write_met_bin_3d(out, ctl, met, met->iwc, "IWC",
12309 ctl->met_comp_prec[10], ctl->met_comp_tol[10]);
12310 write_met_bin_3d(out, ctl, met, met->swc, "SWC",
12311 ctl->met_comp_prec[11], ctl->met_comp_tol[11]);
12312 write_met_bin_3d(out, ctl, met, met->cc, "CC",
12313 ctl->met_comp_prec[12], ctl->met_comp_tol[12]);
12314 if (METVAR != 13)
12315 ERRMSG("Number of meteo variables doesn't match!");
12316
12317 /* Write final flag... */
12318 int final = 999;
12319 FWRITE(&final, int,
12320 1,
12321 out);
12322
12323 /* Close file... */
12324 fclose(out);
12325}
12326
12327/*****************************************************************************/
12328
12330 FILE *out,
12331 met_t *met,
12332 float var[EX][EY],
12333 const char *varname) {
12334
12335 float *help;
12336
12337 /* Allocate... */
12338 ALLOC(help, float,
12339 EX * EY);
12340
12341 /* Copy data... */
12342 for (int ix = 0; ix < met->nx; ix++)
12343 for (int iy = 0; iy < met->ny; iy++)
12344 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
12345
12346 /* Write uncompressed data... */
12347 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
12348 FWRITE(help, float,
12349 (size_t) (met->nx * met->ny),
12350 out);
12351
12352 /* Free... */
12353 free(help);
12354}
12355
12356/*****************************************************************************/
12357
12359 FILE *out,
12360 const ctl_t *ctl,
12361 met_t *met,
12362 float var[EX][EY][EP],
12363 const char *varname,
12364 const int precision,
12365 const double tolerance) {
12366
12367 float *help;
12368
12369 /* Allocate... */
12370 ALLOC(help, float,
12371 EX * EY * EP);
12372
12373 /* Copy data... */
12374#pragma omp parallel for default(shared) collapse(2)
12375 for (int ix = 0; ix < met->nx; ix++)
12376 for (int iy = 0; iy < met->ny; iy++)
12377 for (int ip = 0; ip < met->np; ip++)
12378 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
12379
12380 /* Write uncompressed data... */
12381 if (ctl->met_type == 1) {
12382 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
12383 FWRITE(help, float,
12384 (size_t) (met->nx * met->ny * met->np),
12385 out);
12386 }
12387
12388 /* Write packed data... */
12389 else if (ctl->met_type == 2)
12390 compress_pck(varname, help, (size_t) (met->ny * met->nx),
12391 (size_t) met->np, 0, out);
12392
12393 /* Write ZFP data... */
12394#ifdef ZFP
12395 else if (ctl->met_type == 3) {
12396 FWRITE(&precision, int,
12397 1,
12398 out);
12399 FWRITE(&tolerance, double,
12400 1,
12401 out);
12402 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
12403 tolerance, 0, out);
12404 }
12405#endif
12406
12407 /* Write zstd data... */
12408#ifdef ZSTD
12409 else if (ctl->met_type == 4)
12410 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
12411 ctl->met_zstd_level, out);
12412#endif
12413
12414 /* Write cmultiscale data... */
12415#ifdef CMS
12416 else if (ctl->met_type == 5) {
12417 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
12418 (size_t) met->np, 0, out);
12419 }
12420#endif
12421
12422 /* Write SZ3 data... */
12423#ifdef SZ3
12424 else if (ctl->met_type == 7) {
12425 FWRITE(&precision, int,
12426 1,
12427 out);
12428 FWRITE(&tolerance, double,
12429 1,
12430 out);
12431 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
12432 tolerance, 0, out);
12433 }
12434#endif
12435
12436 /* Unknown method... */
12437 else {
12438 ERRMSG("MET_TYPE not supported!");
12439 LOG(3, "%d %g", precision, tolerance);
12440 }
12441
12442 /* Free... */
12443 free(help);
12444}
12445
12446/*****************************************************************************/
12447
12449 const char *filename,
12450 const ctl_t *ctl,
12451 met_t *met) {
12452
12453 /* Create file... */
12454 int ncid, varid;
12455 size_t start[4], count[4];
12456 nc_create(filename, NC_NETCDF4, &ncid);
12457
12458 /* Define dimensions... */
12459 int tid, lonid, latid, levid;
12460 NC(nc_def_dim(ncid, "time", 1, &tid));
12461 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
12462 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
12463 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
12464
12465 /* Define grid... */
12466 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
12467 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12468 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
12469 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
12470 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
12471
12472 /* Define surface variables... */
12473 int dimid2[2] = { latid, lonid };
12474 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
12475 ctl->met_nc_level, 0);
12476 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
12477 ctl->met_nc_level, 0);
12478 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
12479 ctl->met_nc_level, 0);
12480 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
12481 "m s**-1", ctl->met_nc_level, 0);
12482 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
12483 "m s**-1", ctl->met_nc_level, 0);
12484 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
12485 "Instantaneous eastward turbulent surface stress", "N m**-2",
12486 ctl->met_nc_level, 0);
12487 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
12488 "Instantaneous northward turbulent surface stress", "N m**-2",
12489 ctl->met_nc_level, 0);
12490 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
12491 "Instantaneous surface sensible heat flux", "W m**-1",
12492 ctl->met_nc_level, 0);
12493 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
12494 ctl->met_nc_level, 0);
12495 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
12496 ctl->met_nc_level, 0);
12497 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
12498 ctl->met_nc_level, 0);
12499 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
12500 ctl->met_nc_level, 0);
12501 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
12502 ctl->met_nc_level, 0);
12503 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
12504 ctl->met_nc_level, 0);
12505 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
12506 ctl->met_nc_level, 0);
12507 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
12508 ctl->met_nc_level, 0);
12509 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
12510 ctl->met_nc_level, 0);
12511 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water",
12512 "kg m**2", ctl->met_nc_level, 0);
12513 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
12514 "Pressure at lifted condensation level (LCL)", "Pa",
12515 ctl->met_nc_level, 0);
12516 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
12517 "Pressure at level of free convection (LFC)", "Pa",
12518 ctl->met_nc_level, 0);
12519 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2,
12520 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
12521 0);
12522 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
12523 "Convective available potential energy", "J kg**-1",
12524 ctl->met_nc_level, 0);
12525 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition",
12526 "J kg**-1", ctl->met_nc_level, 0);
12527 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
12528 ctl->met_nc_level, 0);
12529
12530 /* Define level data... */
12531 int dimid3[3] = { levid, latid, lonid };
12532 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
12533 ctl->met_nc_level, ctl->met_nc_quant);
12534 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
12535 ctl->met_nc_level, ctl->met_nc_quant);
12536 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
12537 ctl->met_nc_level, ctl->met_nc_quant);
12538 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
12539 ctl->met_nc_level, ctl->met_nc_quant);
12540 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
12541 ctl->met_nc_level, ctl->met_nc_quant);
12542 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
12543 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12544 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
12545 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12546 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
12547 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12548 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
12549 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12550 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
12551 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12552 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
12553 ctl->met_nc_level, ctl->met_nc_quant);
12554
12555 /* End definitions... */
12556 NC(nc_enddef(ncid));
12557
12558 /* Write grid data... */
12559 NC_PUT_DOUBLE("time", &met->time, 0);
12560 NC_PUT_DOUBLE("lon", met->lon, 0);
12561 NC_PUT_DOUBLE("lat", met->lat, 0);
12562 double phelp[EP];
12563 for (int ip = 0; ip < met->np; ip++)
12564 phelp[ip] = 100. * met->p[ip];
12565 NC_PUT_DOUBLE("lev", phelp, 0);
12566
12567 /* Write surface data... */
12568 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
12569 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
12570 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
12571 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
12572 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
12573 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
12574 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
12575 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
12576 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
12577 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
12578 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
12579 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
12580 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
12581 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
12582 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
12583 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
12584 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
12585 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
12586 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
12587 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
12588 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
12589 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
12590 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
12591 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
12592
12593 /* Write level data... */
12594 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
12595 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
12596 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
12597 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
12598 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
12599 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
12600 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
12601 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
12602 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
12603 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
12604 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
12605
12606 /* Close file... */
12607 NC(nc_close(ncid));
12608}
12609
12610/*****************************************************************************/
12611
12613 const int ncid,
12614 const char *varname,
12615 met_t *met,
12616 float var[EX][EY],
12617 const float scl) {
12618
12619 int varid;
12620 size_t start[4], count[4];
12621
12622 /* Allocate... */
12623 float *help;
12624 ALLOC(help, float,
12625 EX * EY);
12626
12627 /* Copy data... */
12628 for (int ix = 0; ix < met->nx; ix++)
12629 for (int iy = 0; iy < met->ny; iy++)
12630 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
12631
12632 /* Write data... */
12633 NC_PUT_FLOAT(varname, help, 0);
12634
12635 /* Free... */
12636 free(help);
12637}
12638
12639/*****************************************************************************/
12640
12642 const int ncid,
12643 const char *varname,
12644 met_t *met,
12645 float var[EX][EY][EP],
12646 const float scl) {
12647
12648 int varid;
12649 size_t start[4], count[4];
12650
12651 /* Allocate... */
12652 float *help;
12653 ALLOC(help, float,
12654 EX * EY * EP);
12655
12656 /* Copy data... */
12657 for (int ix = 0; ix < met->nx; ix++)
12658 for (int iy = 0; iy < met->ny; iy++)
12659 for (int ip = 0; ip < met->np; ip++)
12660 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
12661
12662 /* Write data... */
12663 NC_PUT_FLOAT(varname, help, 0);
12664
12665 /* Free... */
12666 free(help);
12667}
12668
12669/*****************************************************************************/
12670
12672 const char *filename,
12673 const ctl_t *ctl,
12674 met_t *met0,
12675 met_t *met1,
12676 const atm_t *atm,
12677 const double t) {
12678
12679 static FILE *out;
12680
12681 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
12682 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
12683
12684 static int nobs, *obscount, ip, okay;
12685
12686 /* Set timer... */
12687 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
12688
12689 /* Init... */
12690 if (t == ctl->t_start) {
12691
12692 /* Check quantity index for mass... */
12693 if (ctl->qnt_m < 0)
12694 ERRMSG("Need quantity mass!");
12695
12696 /* Check molar mass... */
12697 if (ctl->molmass <= 0)
12698 ERRMSG("Specify molar mass!");
12699
12700 /* Allocate... */
12701 ALLOC(lon, double,
12702 ctl->prof_nx);
12703 ALLOC(lat, double,
12704 ctl->prof_ny);
12705 ALLOC(area, double,
12706 ctl->prof_ny);
12707 ALLOC(z, double,
12708 ctl->prof_nz);
12709 ALLOC(press, double,
12710 ctl->prof_nz);
12711 ALLOC(rt, double,
12712 NOBS);
12713 ALLOC(rz, double,
12714 NOBS);
12715 ALLOC(rlon, double,
12716 NOBS);
12717 ALLOC(rlat, double,
12718 NOBS);
12719 ALLOC(robs, double,
12720 NOBS);
12721
12722 /* Read observation data... */
12723 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12724
12725 /* Create new output file... */
12726 LOG(1, "Write profile data: %s", filename);
12727 if (!(out = fopen(filename, "w")))
12728 ERRMSG("Cannot create file!");
12729
12730 /* Write header... */
12731 fprintf(out,
12732 "# $1 = time [s]\n"
12733 "# $2 = altitude [km]\n"
12734 "# $3 = longitude [deg]\n"
12735 "# $4 = latitude [deg]\n"
12736 "# $5 = pressure [hPa]\n"
12737 "# $6 = temperature [K]\n"
12738 "# $7 = volume mixing ratio [ppv]\n"
12739 "# $8 = H2O volume mixing ratio [ppv]\n"
12740 "# $9 = O3 volume mixing ratio [ppv]\n"
12741 "# $10 = observed BT index [K]\n"
12742 "# $11 = number of observations\n");
12743
12744 /* Set grid box size... */
12745 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
12746 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
12747 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
12748
12749 /* Set vertical coordinates... */
12750 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12751 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
12752 press[iz] = P(z[iz]);
12753 }
12754
12755 /* Set horizontal coordinates... */
12756 for (int ix = 0; ix < ctl->prof_nx; ix++)
12757 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
12758 for (int iy = 0; iy < ctl->prof_ny; iy++) {
12759 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
12760 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
12761 }
12762 }
12763
12764 /* Set time interval... */
12765 const double t0 = t - 0.5 * ctl->dt_mod;
12766 const double t1 = t + 0.5 * ctl->dt_mod;
12767
12768 /* Allocate... */
12769 ALLOC(mass, double,
12770 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
12771 ALLOC(obsmean, double,
12772 ctl->prof_nx * ctl->prof_ny);
12773 ALLOC(obscount, int,
12774 ctl->prof_nx * ctl->prof_ny);
12775
12776 /* Loop over observations... */
12777 for (int i = 0; i < nobs; i++) {
12778
12779 /* Check time... */
12780 if (rt[i] < t0)
12781 continue;
12782 else if (rt[i] >= t1)
12783 break;
12784
12785 /* Check observation data... */
12786 if (!isfinite(robs[i]))
12787 continue;
12788
12789 /* Calculate indices... */
12790 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
12791 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
12792
12793 /* Check indices... */
12794 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
12795 continue;
12796
12797 /* Get mean observation index... */
12798 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
12799 obsmean[idx] += robs[i];
12800 obscount[idx]++;
12801 }
12802
12803 /* Analyze model data... */
12804 for (ip = 0; ip < atm->np; ip++) {
12805
12806 /* Check time... */
12807 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12808 continue;
12809
12810 /* Get indices... */
12811 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
12812 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
12813 const int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
12814
12815 /* Check indices... */
12816 if (ix < 0 || ix >= ctl->prof_nx ||
12817 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
12818 continue;
12819
12820 /* Get total mass in grid cell... */
12821 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12822 mass[idx] += atm->q[ctl->qnt_m][ip];
12823 }
12824
12825 /* Extract profiles... */
12826 for (int ix = 0; ix < ctl->prof_nx; ix++)
12827 for (int iy = 0; iy < ctl->prof_ny; iy++) {
12828 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
12829 if (obscount[idx2] > 0) {
12830
12831 /* Check profile... */
12832 okay = 0;
12833 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12834 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12835 if (mass[idx3] > 0) {
12836 okay = 1;
12837 break;
12838 }
12839 }
12840 if (!okay)
12841 continue;
12842
12843 /* Write output... */
12844 fprintf(out, "\n");
12845
12846 /* Loop over altitudes... */
12847 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12848
12849 /* Get temperature, water vapor, and ozone... */
12851 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
12852 lon[ix], lat[iy], &temp, ci, cw, 1);
12853 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
12854 lon[ix], lat[iy], &h2o, ci, cw, 0);
12855 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
12856 lon[ix], lat[iy], &o3, ci, cw, 0);
12857
12858 /* Calculate volume mixing ratio... */
12859 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12860 vmr = MA / ctl->molmass * mass[idx3]
12861 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
12862
12863 /* Write output... */
12864 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
12865 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
12866 obsmean[idx2] / obscount[idx2], obscount[idx2]);
12867 }
12868 }
12869 }
12870
12871 /* Free... */
12872 free(mass);
12873 free(obsmean);
12874 free(obscount);
12875
12876 /* Finalize... */
12877 if (t == ctl->t_stop) {
12878
12879 /* Close output file... */
12880 fclose(out);
12881
12882 /* Free... */
12883 free(lon);
12884 free(lat);
12885 free(area);
12886 free(z);
12887 free(press);
12888 free(rt);
12889 free(rz);
12890 free(rlon);
12891 free(rlat);
12892 free(robs);
12893 }
12894}
12895
12896/*****************************************************************************/
12897
12899 const char *filename,
12900 const ctl_t *ctl,
12901 met_t *met0,
12902 met_t *met1,
12903 const atm_t *atm,
12904 const double t) {
12905
12906 static FILE *out;
12907
12908 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
12909 kw[EP];
12910
12911 static int nobs, nk;
12912
12913 /* Set timer... */
12914 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
12915
12916 /* Init... */
12917 if (t == ctl->t_start) {
12918
12919 /* Allocate... */
12920 ALLOC(rt, double,
12921 NOBS);
12922 ALLOC(rz, double,
12923 NOBS);
12924 ALLOC(rlon, double,
12925 NOBS);
12926 ALLOC(rlat, double,
12927 NOBS);
12928 ALLOC(robs, double,
12929 NOBS);
12930
12931 /* Read observation data... */
12932 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12933
12934 /* Read kernel data... */
12935 if (ctl->sample_kernel[0] != '-')
12936 read_kernel(ctl->sample_kernel, kz, kw, &nk);
12937
12938 /* Create output file... */
12939 LOG(1, "Write sample data: %s", filename);
12940 if (!(out = fopen(filename, "w")))
12941 ERRMSG("Cannot create file!");
12942
12943 /* Write header... */
12944 fprintf(out,
12945 "# $1 = time [s]\n"
12946 "# $2 = altitude [km]\n"
12947 "# $3 = longitude [deg]\n"
12948 "# $4 = latitude [deg]\n"
12949 "# $5 = surface area [km^2]\n"
12950 "# $6 = layer depth [km]\n"
12951 "# $7 = number of particles [1]\n"
12952 "# $8 = column density [kg/m^2]\n"
12953 "# $9 = volume mixing ratio [ppv]\n"
12954 "# $10 = observed BT index [K]\n\n");
12955
12956 /* Set latitude range, squared radius, and area... */
12957 dlat = DY2DEG(ctl->sample_dx);
12958 rmax2 = SQR(ctl->sample_dx);
12959 area = M_PI * rmax2;
12960 }
12961
12962 /* Set time interval for output... */
12963 const double t0 = t - 0.5 * ctl->dt_mod;
12964 const double t1 = t + 0.5 * ctl->dt_mod;
12965
12966 /* Loop over observations... */
12967 for (int i = 0; i < nobs; i++) {
12968
12969 /* Check time... */
12970 if (rt[i] < t0)
12971 continue;
12972 else if (rt[i] >= t1)
12973 break;
12974
12975 /* Calculate Cartesian coordinates... */
12976 double x0[3];
12977 geo2cart(0, rlon[i], rlat[i], x0);
12978
12979 /* Set pressure range... */
12980 const double rp = P(rz[i]);
12981 const double ptop = P(rz[i] + ctl->sample_dz);
12982 const double pbot = P(rz[i] - ctl->sample_dz);
12983
12984 /* Init... */
12985 double mass = 0;
12986 int np = 0;
12987
12988 /* Loop over air parcels... */
12989 //#pragma omp parallel for default(shared) reduction(+:mass,np)
12990 for (int ip = 0; ip < atm->np; ip++) {
12991
12992 /* Check time... */
12993 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12994 continue;
12995
12996 /* Check latitude... */
12997 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
12998 continue;
12999
13000 /* Check horizontal distance... */
13001 double x1[3];
13002 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13003 if (DIST2(x0, x1) > rmax2)
13004 continue;
13005
13006 /* Check pressure... */
13007 if (ctl->sample_dz > 0)
13008 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
13009 continue;
13010
13011 /* Add mass... */
13012 if (ctl->qnt_m >= 0)
13013 mass +=
13014 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13015 np++;
13016 }
13017
13018 /* Calculate column density... */
13019 const double cd = mass / (1e6 * area);
13020
13021 /* Calculate volume mixing ratio... */
13022 double vmr = 0;
13023 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
13024 if (mass > 0) {
13025
13026 /* Get temperature... */
13027 double temp;
13029 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
13030 rlon[i], rlat[i], &temp, ci, cw, 1);
13031
13032 /* Calculate volume mixing ratio... */
13033 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
13034 }
13035 } else
13036 vmr = NAN;
13037
13038 /* Write output... */
13039 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
13040 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
13041 }
13042
13043 /* Finalize...... */
13044 if (t == ctl->t_stop) {
13045
13046 /* Close output file... */
13047 fclose(out);
13048
13049 /* Free... */
13050 free(rt);
13051 free(rz);
13052 free(rlon);
13053 free(rlat);
13054 free(robs);
13055 }
13056}
13057
13058/*****************************************************************************/
13059
13061 const char *filename,
13062 const ctl_t *ctl,
13063 atm_t *atm,
13064 const double t) {
13065
13066 static FILE *out;
13067
13068 static double rmax2, x0[3], x1[3];
13069
13070 /* Set timer... */
13071 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
13072
13073 /* Init... */
13074 if (t == ctl->t_start) {
13075
13076 /* Write info... */
13077 LOG(1, "Write station data: %s", filename);
13078
13079 /* Create new file... */
13080 if (!(out = fopen(filename, "w")))
13081 ERRMSG("Cannot create file!");
13082
13083 /* Write header... */
13084 fprintf(out,
13085 "# $1 = time [s]\n"
13086 "# $2 = altitude [km]\n"
13087 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13088 for (int iq = 0; iq < ctl->nq; iq++)
13089 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
13090 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13091 fprintf(out, "\n");
13092
13093 /* Set geolocation and search radius... */
13094 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
13095 rmax2 = SQR(ctl->stat_r);
13096 }
13097
13098 /* Set time interval for output... */
13099 const double t0 = t - 0.5 * ctl->dt_mod;
13100 const double t1 = t + 0.5 * ctl->dt_mod;
13101
13102 /* Loop over air parcels... */
13103 for (int ip = 0; ip < atm->np; ip++) {
13104
13105 /* Check time... */
13106 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13107 continue;
13108
13109 /* Check time range for station output... */
13110 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
13111 continue;
13112
13113 /* Check station flag... */
13114 if (ctl->qnt_stat >= 0)
13115 if ((int) atm->q[ctl->qnt_stat][ip])
13116 continue;
13117
13118 /* Get Cartesian coordinates... */
13119 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13120
13121 /* Check horizontal distance... */
13122 if (DIST2(x0, x1) > rmax2)
13123 continue;
13124
13125 /* Set station flag... */
13126 if (ctl->qnt_stat >= 0)
13127 atm->q[ctl->qnt_stat][ip] = 1;
13128
13129 /* Write data... */
13130 fprintf(out, "%.2f %g %g %g",
13131 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
13132 for (int iq = 0; iq < ctl->nq; iq++) {
13133 fprintf(out, " ");
13134 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
13135 }
13136 fprintf(out, "\n");
13137 }
13138
13139 /* Close file... */
13140 if (t == ctl->t_stop)
13141 fclose(out);
13142}
13143
13144/*****************************************************************************/
13145
13147 const char *filename,
13148 const ctl_t *ctl,
13149 const atm_t *atm,
13150 const double t) {
13151
13152 FILE *out;
13153
13154 /* Set timer... */
13155 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
13156
13157 /* Write info... */
13158 LOG(1, "Write VTK data: %s", filename);
13159
13160 /* Set time interval for output... */
13161 const double t0 = t - 0.5 * ctl->dt_mod;
13162 const double t1 = t + 0.5 * ctl->dt_mod;
13163
13164 /* Create file... */
13165 if (!(out = fopen(filename, "w")))
13166 ERRMSG("Cannot create file!");
13167
13168 /* Count data points... */
13169 int np = 0;
13170 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13171 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13172 continue;
13173 np++;
13174 }
13175
13176 /* Write header... */
13177 fprintf(out,
13178 "# vtk DataFile Version 3.0\n"
13179 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
13180
13181 /* Write point coordinates... */
13182 fprintf(out, "POINTS %d float\n", np);
13183 if (ctl->vtk_sphere) {
13184 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13185 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13186 continue;
13187 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
13188 + ctl->vtk_offset) / RE;
13189 const double coslat = cos(DEG2RAD(atm->lat[ip]));
13190 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
13191 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
13192 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
13193 fprintf(out, "%g %g %g\n", x, y, z);
13194 }
13195 } else
13196 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13197 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13198 continue;
13199 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
13200 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
13201 }
13202
13203 /* Write point data... */
13204 fprintf(out, "POINT_DATA %d\n", np);
13205 for (int iq = 0; iq < ctl->nq; iq++) {
13206 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
13207 ctl->qnt_name[iq]);
13208 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13209 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13210 continue;
13211 fprintf(out, "%g\n", atm->q[iq][ip]);
13212 }
13213 }
13214
13215 /* Close file... */
13216 fclose(out);
13217}
13218
13219/*****************************************************************************/
13220
13221#ifdef DD
13222void dd_atm2particles(
13223 atm_t *atm,
13224 particle_t *particles,
13225 ctl_t *ctl,
13226 int *nparticles,
13227 cache_t *cache,
13228 int rank) {
13229
13230 SELECT_TIMER("DD_ATM2PARTICLES", "DD", NVTX_READ);
13231
13232 /* Select the particles that will be send... */
13233#ifdef _OPENACC
13234 int npart = *nparticles;
13235#pragma acc enter data create( nparticles, particles[:DD_NPART])
13236#pragma acc update device( nparticles)
13237#pragma acc parallel loop present( atm, ctl, particles, cache, nparticles)
13238#endif
13239 for (int ip = atm->np; ip < atm->np + *nparticles; ip++)
13240 if (((int) (atm->q[ctl->qnt_destination][ip]) != rank)
13241 && ((int) (atm->q[ctl->qnt_destination][ip]) >= 0)
13242 && ((int) atm->q[ctl->qnt_subdomain][ip] >= 0)) {
13243
13244 particles[ip - atm->np].time = atm->time[ip];
13245 particles[ip - atm->np].lon = atm->lon[ip];
13246 particles[ip - atm->np].lat = atm->lat[ip];
13247 particles[ip - atm->np].p = atm->p[ip];
13248
13249 for (int iq = 0; iq < ctl->nq; iq++)
13250 particles[ip - atm->np].q[iq] = atm->q[iq][ip];
13251
13252 atm->q[ctl->qnt_subdomain][ip] = -1;
13253 cache->dt[ip] = 0;
13254 }
13255#ifdef _OPENACC
13256#pragma acc update host( particles[:npart])
13257#pragma acc exit data delete( nparticles, particles)
13258#endif
13259}
13260#endif
13261
13262/*****************************************************************************/
13263
13264#ifdef DD
13265void dd_particles2atm(
13266 atm_t *atm,
13267 particle_t *particles,
13268 ctl_t *ctl,
13269 int *nparticles,
13270 cache_t *cache) {
13271
13272 SELECT_TIMER("DD_PARTICLES2ATM", "DD", NVTX_CPU);
13273
13274#ifdef _OPENACC
13275 int npart = *nparticles;
13276#pragma acc enter data create(nparticles, particles[:DD_NPART])
13277#pragma acc update device(particles[:npart], nparticles)
13278#pragma acc data present(atm, ctl, cache, particles, nparticles)
13279#pragma acc parallel loop
13280#endif
13281 for (int ip = atm->np; ip < atm->np + *nparticles; ip++) {
13282
13283 atm->time[ip] = particles[ip - atm->np].time;
13284 atm->lon[ip] = particles[ip - atm->np].lon;
13285 atm->lat[ip] = particles[ip - atm->np].lat;
13286 atm->p[ip] = particles[ip - atm->np].p;
13287
13288 for (int iq = 0; iq < ctl->nq; iq++)
13289 atm->q[iq][ip] = particles[ip - atm->np].q[iq];
13290
13291 cache->dt[ip] = ctl->dt_mod;
13292
13293 }
13294#ifdef _OPENACC
13295#pragma acc exit data delete(nparticles, particles)
13296#endif
13297
13298 /* Reset size... */
13299 atm->np += *nparticles;
13300#ifdef _OPENACC
13301#pragma acc update device(atm->np)
13302#endif
13303 if (atm->np > NP)
13304 ERRMSG("Number of particles to high. Increase NP!");
13305}
13306#endif
13307
13308/*****************************************************************************/
13309
13310#ifdef DD
13311void dd_register_MPI_type_particle(
13312 MPI_Datatype *MPI_Particle) {
13313 MPI_Datatype types[5] = { MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE,
13314 MPI_DOUBLE, MPI_DOUBLE
13315 };
13316 int blocklengths[5] = { 1, 1, 1, 1, NQ };
13317 MPI_Aint displacements[5] = { offsetof(particle_t, time),
13318 offsetof(particle_t, p),
13319 offsetof(particle_t, lon),
13320 offsetof(particle_t, lat),
13321 offsetof(particle_t, q)
13322 };
13323 MPI_Type_create_struct(5, blocklengths, displacements, types, MPI_Particle);
13324 MPI_Type_commit(MPI_Particle);
13325}
13326#endif
13327
13328/*****************************************************************************/
13329
13330#ifdef DD
13331void dd_get_rect_neighbour(
13332 const ctl_t ctl,
13333 mpi_info_t *mpi_info) {
13334
13335 SELECT_TIMER("DD_GET_RECT_NEIGHBOUR", "DD", NVTX_GPU);
13336
13337 if (mpi_info->rank + 1 == mpi_info->size) {
13338
13339 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional;
13340 mpi_info->neighbours[1] = DD_SPOLE;
13341 mpi_info->neighbours[2] =
13342 mpi_info->rank - ctl.dd_subdomains_meridional - 1;
13343
13344 mpi_info->neighbours[3] =
13345 (mpi_info->rank + 1 + ctl.dd_subdomains_meridional) % mpi_info->size -
13346 1;
13347 mpi_info->neighbours[4] = DD_SPOLE;
13348 mpi_info->neighbours[5] =
13349 (mpi_info->rank + ctl.dd_subdomains_meridional) % mpi_info->size - 1;
13350
13351 mpi_info->neighbours[6] = mpi_info->rank - 1;
13352 mpi_info->neighbours[7] = DD_SPOLE;
13353
13354 } else if (mpi_info->rank ==
13356
13357 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional;
13358 mpi_info->neighbours[1] =
13359 mpi_info->rank - ctl.dd_subdomains_meridional + 1;
13360 mpi_info->neighbours[2] = DD_NPOLE;
13361
13362 mpi_info->neighbours[3] =
13363 (mpi_info->rank + 1 + ctl.dd_subdomains_meridional) % mpi_info->size -
13364 1;
13365 mpi_info->neighbours[4] =
13366 (mpi_info->rank + 2 + ctl.dd_subdomains_meridional) % mpi_info->size -
13367 1;
13368 mpi_info->neighbours[5] = DD_NPOLE;
13369
13370 mpi_info->neighbours[6] = DD_NPOLE;
13371 mpi_info->neighbours[7] = mpi_info->rank + 1;
13372
13373 } else if (mpi_info->rank == 0) {
13374
13375 mpi_info->neighbours[0] =
13376 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank;
13377 mpi_info->neighbours[1] =
13378 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank + 1;
13379 mpi_info->neighbours[2] = DD_NPOLE;
13380
13381 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional;
13382 mpi_info->neighbours[4] =
13383 mpi_info->rank + 1 + ctl.dd_subdomains_meridional;
13384 mpi_info->neighbours[5] = DD_NPOLE;
13385
13386 mpi_info->neighbours[6] = DD_NPOLE;
13387 mpi_info->neighbours[7] = mpi_info->rank + 1;
13388
13389 } else if (mpi_info->rank + 1 == ctl.dd_subdomains_meridional) {
13390
13391 mpi_info->neighbours[0] =
13392 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank;
13393 mpi_info->neighbours[1] = DD_SPOLE;
13394 mpi_info->neighbours[2] =
13395 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank - 1;
13396
13397 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional;
13398 mpi_info->neighbours[4] = DD_SPOLE;
13399 mpi_info->neighbours[5] =
13400 mpi_info->rank + ctl.dd_subdomains_meridional - 1;
13401
13402 mpi_info->neighbours[6] = mpi_info->rank - 1;
13403 mpi_info->neighbours[7] = DD_SPOLE;
13404
13405 } else if ((mpi_info->rank + 1) % ctl.dd_subdomains_meridional == 1) {
13406
13407 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional;
13408 mpi_info->neighbours[1] =
13409 mpi_info->rank + 1 - ctl.dd_subdomains_meridional;
13410 mpi_info->neighbours[2] = DD_NPOLE;
13411
13412 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional;
13413 mpi_info->neighbours[4] =
13414 mpi_info->rank + 1 + ctl.dd_subdomains_meridional;
13415 mpi_info->neighbours[5] = DD_NPOLE;
13416
13417 mpi_info->neighbours[6] = DD_NPOLE;
13418 mpi_info->neighbours[7] = mpi_info->rank + 1;
13419
13420 } else if ((mpi_info->rank + 1) % ctl.dd_subdomains_meridional == 0) {
13421
13422 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional;
13423 mpi_info->neighbours[1] = DD_SPOLE;
13424 mpi_info->neighbours[2] =
13425 mpi_info->rank - ctl.dd_subdomains_meridional - 1;
13426
13427 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional;
13428 mpi_info->neighbours[4] = DD_SPOLE;
13429 mpi_info->neighbours[5] =
13430 mpi_info->rank + ctl.dd_subdomains_meridional - 1;
13431
13432 mpi_info->neighbours[6] = mpi_info->rank - 1;
13433 mpi_info->neighbours[7] = DD_SPOLE;
13434
13435 } else if (mpi_info->rank + 1 <= ctl.dd_subdomains_meridional) {
13436
13437 mpi_info->neighbours[0] =
13438 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank;
13439 mpi_info->neighbours[1] =
13440 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank + 1;
13441 mpi_info->neighbours[2] =
13442 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank - 1;
13443
13444 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional;
13445 mpi_info->neighbours[4] =
13446 mpi_info->rank + ctl.dd_subdomains_meridional + 1;
13447 mpi_info->neighbours[5] =
13448 mpi_info->rank + ctl.dd_subdomains_meridional - 1;
13449
13450 mpi_info->neighbours[6] = mpi_info->rank - 1;
13451 mpi_info->neighbours[7] = mpi_info->rank + 1;
13452
13453 } else if (mpi_info->rank + 1 >
13454 mpi_info->size - ctl.dd_subdomains_meridional) {
13455
13456 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional;
13457 mpi_info->neighbours[1] =
13458 mpi_info->rank - ctl.dd_subdomains_meridional + 1;
13459 mpi_info->neighbours[2] =
13460 mpi_info->rank - ctl.dd_subdomains_meridional - 1;
13461
13462 mpi_info->neighbours[3] =
13463 (mpi_info->rank + 1 + ctl.dd_subdomains_meridional) % mpi_info->size -
13464 1;
13465 mpi_info->neighbours[4] =
13466 (mpi_info->rank + 2 + ctl.dd_subdomains_meridional) % mpi_info->size -
13467 1;
13468 mpi_info->neighbours[5] =
13469 (mpi_info->rank + ctl.dd_subdomains_meridional) % mpi_info->size - 1;
13470
13471 mpi_info->neighbours[6] = mpi_info->rank - 1;
13472 mpi_info->neighbours[7] = mpi_info->rank + 1;
13473
13474 } else {
13475
13476 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional; // left...
13477 mpi_info->neighbours[1] = mpi_info->rank - ctl.dd_subdomains_meridional + 1; // lower left..
13478 mpi_info->neighbours[2] = mpi_info->rank - ctl.dd_subdomains_meridional - 1; // upper left..
13479
13480 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional; // right...
13481 mpi_info->neighbours[4] = mpi_info->rank + ctl.dd_subdomains_meridional + 1; // lower right...
13482 mpi_info->neighbours[5] = mpi_info->rank + ctl.dd_subdomains_meridional - 1; // upper right...
13483
13484 mpi_info->neighbours[6] = mpi_info->rank - 1; // upper
13485 mpi_info->neighbours[7] = mpi_info->rank + 1; // lower
13486
13487 }
13488}
13489#endif
13490
13491/*****************************************************************************/
13492
13493#ifdef DD
13494void dd_communicate_particles(
13495 particle_t *particles,
13496 int *nparticles,
13497 MPI_Datatype MPI_Particle,
13498 int *neighbours,
13499 int nneighbours,
13500 ctl_t ctl) {
13501
13502 /* Initialize the buffers... */
13503 int *nbs;
13504 int *nbr;
13505 ALLOC(nbs, int,
13506 nneighbours);
13507 ALLOC(nbr, int,
13508 nneighbours);
13509 particle_t *send_buffers[DD_NNMAX] = { NULL };
13510 particle_t *recieve_buffers[DD_NNMAX] = { NULL };
13511
13512 /* Get MPI rank... */
13513 int rank;
13514 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
13515
13516 /* Infos for MPI async... */
13517 // TODO: Make this requests variable from number of neighbours...
13518 MPI_Request requests_snd_nbr[8] =
13519 { MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL,
13520 MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL
13521 };
13522 MPI_Request requests_rcv_nbr[8] =
13523 { MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL,
13524 MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL
13525 };
13526 MPI_Request requests_snd_part[8] =
13527 { MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL,
13528 MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL
13529 };
13530 MPI_Request requests_rcv_part[8] =
13531 { MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL,
13532 MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL
13533 };
13534 MPI_Status states[8];
13535
13536 /* Sending... */
13537 for (int idest = 0; idest < nneighbours; idest++) {
13538
13539 /* Ignore poles... */
13540 if (neighbours[idest] < 0)
13541 continue;
13542
13543 SELECT_TIMER("DD_COUNT_NUMBER", "DD", NVTX_CPU);
13544 /* Count number of particles in particle array that will be send... */
13545 int help_sum = 0;
13546 for (int ip = 0; ip < *nparticles; ip++)
13547 if ((int) particles[ip].q[ctl.qnt_destination] == neighbours[idest])
13548 help_sum++;
13549 nbs[idest] = help_sum;
13550
13551 SELECT_TIMER("DD_SEND_NUMBER", "DD", NVTX_CPU);
13552 /* Send buffer sizes... */
13553 MPI_Isend(&nbs[idest], 1, MPI_INT,
13554 neighbours[idest], 0, MPI_COMM_WORLD, &requests_snd_nbr[idest]);
13555
13556 /* Don't send empty signals... */
13557 if (nbs[idest] == 0)
13558 continue;
13559
13560 SELECT_TIMER("DD_PREP_BUFFER", "DD", NVTX_CPU);
13561 /* Allocate buffer for sending... */
13562 ALLOC(send_buffers[idest], particle_t, nbs[idest]);
13563
13564 /* Fill the send buffer in a sorted way... */
13565 int ibs = 0;
13566 for (int ip = 0; ip < *nparticles; ip++) {
13567 if ((int) particles[ip].q[ctl.qnt_destination] == neighbours[idest]) {
13568 memcpy(&send_buffers[idest][ibs], &particles[ip], sizeof(particle_t));
13569 ibs++;
13570 }
13571
13572 if (ibs == nbs[idest])
13573 break;
13574 }
13575
13576 SELECT_TIMER("DD_SEND_PARTICLES", "DD", NVTX_CPU);
13577
13578 /* Send the buffer... */
13579 MPI_Isend(send_buffers[idest], nbs[idest], MPI_Particle,
13580 neighbours[idest], 1, MPI_COMM_WORLD,
13581 &requests_snd_part[idest]);
13582 }
13583
13584 SELECT_TIMER("DD_RECIEVE_NUMBERS", "DD", NVTX_CPU);
13585
13586 /* Recieving... */
13587 for (int isourc = 0; isourc < nneighbours; isourc++) {
13588
13589 /* Ignore poles... */
13590 if (neighbours[isourc] < 0) {
13591 requests_rcv_nbr[isourc] = MPI_REQUEST_NULL;
13592 continue;
13593 }
13594
13595 /* Recieve buffer sizes... */
13596 MPI_Irecv(&nbr[isourc], 1, MPI_INT, neighbours[isourc], 0, MPI_COMM_WORLD,
13597 &requests_rcv_nbr[isourc]);
13598
13599 }
13600
13601 /* Wait for all particle numbers to be recieved... */
13602 MPI_Waitall(nneighbours, requests_rcv_nbr, states);
13603
13604 SELECT_TIMER("DD_RECIEVE_PARTICLES", "DD", NVTX_CPU);
13605 for (int isourc = 0; isourc < nneighbours; isourc++) {
13606
13607 /* Ignore poles, and neighbours without signal... */
13608 if ((neighbours[isourc] < 0) || (nbr[isourc] == 0)) {
13609 requests_rcv_part[isourc] = MPI_REQUEST_NULL;
13610 continue;
13611 }
13612
13613 /* Allocate buffer for recieving... */
13614 ALLOC(recieve_buffers[isourc], particle_t, nbr[isourc]);
13615
13616 MPI_Irecv(recieve_buffers[isourc], nbr[isourc], MPI_Particle,
13617 neighbours[isourc], 1, MPI_COMM_WORLD,
13618 &requests_rcv_part[isourc]);
13619
13620 }
13621
13622 /* Wait for all particles to be recieved... */
13623 MPI_Waitall(nneighbours, requests_rcv_part, states);
13624
13625 SELECT_TIMER("DD_EMPTY_BUFFER", "DD", NVTX_CPU);
13626
13627 /* Start position for different buffer ranges... */
13628 int api = 0;
13629
13630 /* Putting buffer into particle array... */
13631 for (int isourc = 0; isourc < nneighbours; isourc++) {
13632
13633 /* Ignore poles... */
13634 if (neighbours[isourc] < 0)
13635 continue;
13636
13637 /* Getting particles from buffer... */
13638 for (int ip = 0; ip < nbr[isourc]; ip++) {
13639 memcpy(&particles[ip + api], &recieve_buffers[isourc][ip],
13640 sizeof(particle_t));
13641 particles[ip + api].q[ctl.qnt_destination] = rank;
13642 particles[ip + api].q[ctl.qnt_subdomain] = rank;
13643
13644 }
13645 api += nbr[isourc];
13646 }
13647
13648 /* Set number of recieved particles... */
13649 *nparticles = api;
13650
13651 SELECT_TIMER("DD_FREE_BUFFER", "DD", NVTX_CPU);
13652
13653 /* Wait for all communication to be finished... */
13654 MPI_Waitall(nneighbours, requests_snd_part, states);
13655 MPI_Waitall(nneighbours, requests_snd_nbr, states);
13656
13657 /* Free buffers and buffersizes... */
13658 for (int i = 0; i < nneighbours; i++) {
13659
13660 if ((send_buffers[i] != NULL) && (nbs[i] != 0)) {
13661 free(send_buffers[i]);
13662 send_buffers[i] = NULL;
13663 }
13664
13665 if ((recieve_buffers[i] != NULL) && (nbr[i] != 0)) {
13666 free(recieve_buffers[i]);
13667 recieve_buffers[i] = NULL;
13668 }
13669
13670 }
13671
13672 free(nbs);
13673 free(nbr);
13674
13675}
13676#endif
13677
13678/*****************************************************************************/
13679
13680#ifdef DD
13681void dd_assign_rect_subdomains_atm(
13682 atm_t *atm,
13683 met_t *met,
13684 ctl_t *ctl,
13685 mpi_info_t *mpi_info,
13686 int init) {
13687
13688 SELECT_TIMER("DD_ASSIGN_RECT_SUBDOMAINS", "DD", NVTX_GPU);
13689
13690 if (init) {
13691#ifdef _OPENACC
13692#pragma acc enter data create(mpi_info)
13693#pragma acc update device(mpi_info->rank)
13694#pragma acc data present(atm, ctl, mpi_info, met)
13695#pragma acc parallel loop independent gang vector
13696#endif
13697 for (int ip = 0; ip < atm->np; ip++) {
13698
13699 double lont = atm->lon[ip];
13700
13701 if (lont < 0)
13702 lont += 360;
13703
13704 if (lont >= met->subdomain_lon_min && lont < met->subdomain_lon_max
13705 && atm->lat[ip] >= met->subdomain_lat_min
13706 && atm->lat[ip] < met->subdomain_lat_max) {
13707 atm->q[ctl->qnt_subdomain][ip] = mpi_info->rank;
13708 atm->q[ctl->qnt_destination][ip] = mpi_info->rank;
13709 } else {
13710 atm->q[ctl->qnt_subdomain][ip] = -1;
13711 atm->q[ctl->qnt_destination][ip] = -1;
13712 }
13713 }
13714#ifdef _OPENACC
13715#pragma acc exit data delete(mpi_info)
13716#endif
13717 } else {
13718
13719 /* Classify air parcels into subdomain... */
13720#ifdef _OPENACC
13721#pragma acc enter data create(mpi_info)
13722#pragma acc update device(mpi_info->neighbours[:DD_NNMAX], mpi_info->rank, mpi_info->size)
13723#pragma acc data present(atm, met, ctl, mpi_info)
13724#pragma acc parallel loop independent gang vector
13725#endif
13726 for (int ip = 0; ip < atm->np; ip++) {
13727
13728 /* Skip empty places in the particle array... */
13729 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
13730 continue;
13731
13732 double lont = atm->lon[ip];
13733 double latt = atm->lat[ip];
13734
13735 double lon_max = met->subdomain_lon_max;
13736 double lon_min = met->subdomain_lon_min;
13737 double lat_max = met->subdomain_lat_max;
13738 double lat_min = met->subdomain_lat_min;
13739
13740 if (lont < 0)
13741 lont += 360;
13742
13743 bool left = (mpi_info->rank <= ctl->dd_subdomains_meridional - 1);
13744 bool right =
13745 (mpi_info->rank >= mpi_info->size - ctl->dd_subdomains_meridional);
13746
13747 bool bound = 0;
13748 if (left)
13749 bound = (lont - lon_max > 90) ? 1 : 0;
13750 if (right)
13751 bound = (lon_min - lont > 90) ? 1 : 0;
13752
13753 if (!bound) {
13754 if ((lont >= lon_max) && (latt >= lat_max)) {
13755 // Upper right...
13756 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[5];
13757 } else if ((lont >= lon_max) && (latt <= lat_min)) {
13758 // Lower right...
13759 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[4];
13760 } else if ((lont <= lon_min) && (latt >= lat_max)) {
13761 // Upper left...
13762 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[2];
13763 } else if ((lont <= lon_min) && (latt <= lat_min)) {
13764 // Lower left...
13765 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[1];
13766 } else if (lont >= lon_max) {
13767 // Right...
13768 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[3];
13769 } else if (lont <= lon_min) {
13770 // Left...
13771 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[0];
13772 } else if (latt <= lat_min) {
13773 // Down...
13774 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[7];
13775 } else if (latt >= lat_max) {
13776 // Up...
13777 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[6];
13778 } else {
13779 // Within...
13780 atm->q[ctl->qnt_destination][ip] = mpi_info->rank;
13781 }
13782 } else {
13783 if ((lont >= lon_max) && (latt >= lat_max)) {
13784 // Upper right...
13785 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[2];
13786 } else if ((lont >= lon_max) && (latt <= lat_min)) {
13787 // Lower right...
13788 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[1];
13789 } else if ((lont <= lon_min) && (latt >= lat_max)) {
13790 // Upper left...
13791 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[5];
13792 } else if ((lont <= lon_min) && (latt <= lat_min)) {
13793 // Lower left...
13794 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[4];
13795 } else if (lont >= lon_max) {
13796 // Right...
13797 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[0];
13798 } else if (lont <= lon_min) {
13799 // Left...
13800 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[3];
13801 } else if (latt <= lat_min) {
13802 // Down...
13803 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[7];
13804 } else if (latt >= lat_max) {
13805 // Up...
13806 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[6];
13807 } else {
13808 // Within...
13809 atm->q[ctl->qnt_destination][ip] = mpi_info->rank;
13810 }
13811 }
13812 }
13813#ifdef _OPENACC
13814#pragma acc exit data delete(mpi_info)
13815#endif
13816 }
13817}
13818#endif
13819
13820/*****************************************************************************/
13821
13822#ifdef DD
13823void dd_init(
13824 ctl_t *ctl,
13825 mpi_info_t *mpi_info,
13826 atm_t *atm,
13827 met_t **met,
13828 int *dd_init_flg) {
13829
13830 /* Check if enough tasks are requested... */
13831 if (mpi_info->size !=
13833 ERRMSG("The number of tasks and subdomains is not identical.");
13834
13835 /* Register the MPI_Particle data type... */
13836 dd_register_MPI_type_particle(&mpi_info->MPI_Particle);
13837
13838 /* Define grid neighbours ... */
13839 dd_get_rect_neighbour(*ctl, mpi_info);
13840
13841 /* Check if particles are in subdomain... */
13842 dd_assign_rect_subdomains_atm(atm, *met, ctl, mpi_info, 1);
13843
13844 *dd_init_flg = 1;
13845}
13846#endif
13847
13848/*****************************************************************************/
13849
13850#ifdef DD
13851void module_dd(
13852 ctl_t *ctl,
13853 atm_t *atm,
13854 cache_t *cache,
13855 mpi_info_t *mpi_info,
13856 met_t **met) {
13857
13858 /* Initialize particles locally... */
13859 int nparticles = 0;
13860 particle_t *particles;
13861 ALLOC(particles, particle_t, DD_NPART);
13862
13863 /* Assign particles to new subdomains... */
13864 dd_assign_rect_subdomains_atm(atm, *met, ctl, mpi_info, 0);
13865
13866 /* Sorting particles according to location and target rank... */
13867 dd_sort(ctl, *met, atm, &nparticles, &mpi_info->rank);
13868
13869 /* Transform from struct of array to array of struct... */
13870 dd_atm2particles(atm, particles, ctl, &nparticles, cache, mpi_info->rank);
13871
13872 /********************* CPU region start ***********************************/
13873
13874 /* Perform the communication... */
13875 dd_communicate_particles(particles, &nparticles, mpi_info->MPI_Particle,
13876 mpi_info->neighbours, ctl->dd_nbr_neighbours,
13877 *ctl);
13878
13879 /********************* CPU region end *************************************/
13880
13881 /* Transform from array of struct to struct of array... */
13882 dd_particles2atm(atm, particles, ctl, &nparticles, cache);
13883
13884 /* Free local particle array... */
13885 free(particles);
13886
13887}
13888#endif
13889
13890/*****************************************************************************/
13891
13892#ifdef DD
13893void dd_sort(
13894 const ctl_t *ctl,
13895 met_t *met0,
13896 atm_t *atm,
13897 int *nparticles,
13898 int *rank) {
13899
13900 /* Set timer... */
13901 SELECT_TIMER("DD_SORT", "DD", NVTX_GPU);
13902
13903 /* Allocate... */
13904 const int np = atm->np;
13905 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
13906 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
13907 double amax = (met0->nx * met0->ny + met0->ny) * met0->np + met0->np;
13908
13909#ifdef _OPENACC
13910#pragma acc enter data create(a[0:np],p[0:np],amax, rank)
13911#pragma acc update device(rank, amax)
13912#pragma acc data present(ctl,met0,atm,a,p,amax,rank)
13913#endif
13914
13915 /* Get box index... */
13916#ifdef _OPENACC
13917#pragma acc parallel loop independent gang vector
13918#else
13919#pragma omp parallel for default(shared)
13920#endif
13921 for (int ip = 0; ip < np; ip++) {
13922 if ((int) atm->q[ctl->qnt_subdomain][ip] != -1) {
13923 if ((int) atm->q[ctl->qnt_destination][ip] == *rank)
13924 a[ip] =
13925 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) *
13926 met0->ny + locate_irr(met0->lat, met0->ny, atm->lat[ip]))
13927 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
13928 else
13929 a[ip] = amax + 1;
13930 } else {
13931 a[ip] = amax + 2;
13932 }
13933 p[ip] = ip;
13934 }
13935
13936 /* Sorting... */
13937#ifdef THRUST
13938#ifdef _OPENACC
13939#pragma acc host_data use_device(a,p)
13940#endif
13941 thrustSortWrapper(a, np, p);
13942#else
13943#ifdef _OPENACC
13944 ERRMSG("GSL sort fallback not available on GPU, use THRUST!");
13945#endif
13946 gsl_sort_index((size_t *) p, a, 1, (size_t) np);
13947#endif
13948
13949 /* Sort data... */
13950 module_sort_help(atm->time, p, np);
13951 module_sort_help(atm->p, p, np);
13952 module_sort_help(atm->lon, p, np);
13953 module_sort_help(atm->lat, p, np);
13954 for (int iq = 0; iq < ctl->nq; iq++)
13955 module_sort_help(atm->q[iq], p, np);
13956
13957 /* Reset the size... */
13958 int npt = 0;
13959#ifdef _OPENACC
13960#pragma acc parallel loop reduction(+:npt) present(atm, rank, ctl)
13961#endif
13962 for (int ip = 0; ip < np; ip++)
13963 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
13964 && ((int) atm->q[ctl->qnt_destination][ip] == *rank))
13965 npt++;
13966
13967 /* Count number of particles to send... */
13968 int nparticlest = 0;
13969#ifdef _OPENACC
13970#pragma acc parallel loop reduction(+:nparticlest) present(atm, rank, ctl)
13971#endif
13972 for (int ip = npt; ip < np; ip++)
13973 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
13974 && ((int) atm->q[ctl->qnt_destination][ip] != *rank))
13975 nparticlest++;
13976
13977 /* Reset sizes... */
13978 *nparticles = nparticlest;
13979 atm->np = npt;
13980#ifdef _OPENACC
13981#pragma acc update device(atm->np)
13982#endif
13983
13984 if (*nparticles > DD_NPART)
13985 ERRMSG
13986 ("Number of particles to send and recieve to small. Increase DD_NPART!");
13987
13988 /* Free... */
13989#ifdef _OPENACC
13990#pragma acc exit data delete(a,p,amax, rank)
13991#endif
13992 free(a);
13993 free(p);
13994
13995}
13996#endif
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:7283
void read_met_nc_surface(const int ncid, const ctl_t *ctl, met_t *met)
Reads surface meteorological data from a netCDF file and stores it in the meteorological data structu...
Definition: mptrac.c:9679
void mptrac_write_atm(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes air parcel data to a file in various formats.
Definition: mptrac.c:5939
void day2doy(const int year, const int mon, const int day, int *doy)
Get day of year from date.
Definition: mptrac.c:1004
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:7243
void write_atm_clams_traj(const char *dirname, const ctl_t *ctl, const atm_t *atm, const double t)
Writes CLaMS trajectory data to a NetCDF file.
Definition: mptrac.c:11209
void write_met_nc_2d(const int ncid, const char *varname, met_t *met, float var[EX][EY], const float scl)
Writes a 2D meteorological variable to a NetCDF file.
Definition: mptrac.c:12612
void mptrac_alloc(ctl_t **ctl, cache_t **cache, clim_t **clim, met_t **met0, met_t **met1, atm_t **atm)
Allocates and initializes memory resources for MPTRAC.
Definition: mptrac.c:4325
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:10207
void write_met_bin_3d(FILE *out, const ctl_t *ctl, met_t *met, float var[EX][EY][EP], const char *varname, const int precision, const double tolerance)
Writes a 3-dimensional meteorological variable to a binary file.
Definition: mptrac.c:12358
void read_obs(const char *filename, const ctl_t *ctl, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
Reads observation data from a file and stores it in arrays.
Definition: mptrac.c:10552
void module_advect(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Advances particle positions using different advection schemes.
Definition: mptrac.c:2194
void module_timesteps(const ctl_t *ctl, cache_t *cache, met_t *met0, atm_t *atm, const double t)
Calculate time steps for air parcels based on specified conditions.
Definition: mptrac.c:4042
int mptrac_read_met(const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met)
Reads meteorological data from a file, supporting multiple formats and MPI broadcasting.
Definition: mptrac.c:5558
void module_meteo(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Update atmospheric properties using meteorological data.
Definition: mptrac.c:3361
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:6371
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:7082
void module_decay(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, atm_t *atm)
Simulate exponential decay processes for atmospheric particles.
Definition: mptrac.c:2747
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:10725
void intpol_met_space_2d(const met_t *met, float array[EX][EY], const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological variables in 2D space.
Definition: mptrac.c:1568
int read_atm_nc(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a generic netCDF file and populates the given atmospheric structure.
Definition: mptrac.c:6338
void read_met_pbl(const ctl_t *ctl, met_t *met)
Computes the planetary boundary layer (PBL) pressure based on meteorological data.
Definition: mptrac.c:9815
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:7139
int read_met_nc_2d(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const char *varname5, const char *varname6, const ctl_t *ctl, const met_t *met, float dest[EX][EY], const float scl, const int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:9015
void read_met_tropo(const ctl_t *ctl, const clim_t *clim, met_t *met)
Calculates the tropopause and related meteorological variables based on various methods and stores th...
Definition: mptrac.c:10380
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:10596
void module_chem_init(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Initializes the chemistry modules by setting atmospheric composition.
Definition: mptrac.c:2632
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:2155
void get_tropo(const int met_tropo, ctl_t *ctl, clim_t *clim, met_t *met, const double *lons, const int nx, const double *lats, const int ny, double *pt, double *zt, double *tt, double *qt, double *o3t, double *ps, double *zs)
Calculate tropopause data.
Definition: mptrac.c:1201
void mptrac_get_met(ctl_t *ctl, clim_t *clim, const double t, met_t **met0, met_t **met1)
Retrieves meteorological data for the specified time.
Definition: mptrac.c:4414
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:8899
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:6490
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:9952
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:4089
void write_ens(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes ensemble data to a file.
Definition: mptrac.c:11695
void module_mixing(const ctl_t *ctl, const clim_t *clim, atm_t *atm, const double t)
Update atmospheric properties through interparcel mixing.
Definition: mptrac.c:3466
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:406
void module_mixing_help(const ctl_t *ctl, const clim_t *clim, atm_t *atm, const int *ixs, const int *iys, const int *izs, const int qnt_idx, const int use_ensemble)
Perform subgrid-scale interparcel mixing of a given quantity.
Definition: mptrac.c:3537
void read_clim_photo_help(const int ncid, const char *varname, const clim_photo_t *photo, double var[CP][CSZA][CO3])
Reads a 3D climatological photochemistry variable from a NetCDF file.
Definition: mptrac.c:6462
void read_met_ml2pl(const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname)
Reads global meteorological information from a grib file.
Definition: mptrac.c:8857
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:205
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:10624
void read_met_bin_2d(FILE *in, const met_t *met, float var[EX][EY], const char *varname)
Reads a 2-dimensional meteorological variable from a binary file and stores it in the provided array.
Definition: mptrac.c:6832
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:2091
void module_isosurf_init(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Initialize the isosurface module based on atmospheric data.
Definition: mptrac.c:3185
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:1881
void intpol_met_4d_coord(const met_t *met0, float heights0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float heights1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double height, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological variables to a given position and time.
Definition: mptrac.c:1271
void write_grid_asc(const char *filename, const ctl_t *ctl, const double *cd, double *mean[NQ], double *sigma[NQ], const double *vmr_impl, const double t, const double *z, const double *lon, const double *lat, const double *area, const double dz, const int *np)
Writes grid data to an ASCII file.
Definition: mptrac.c:11983
void mptrac_update_device(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
Updates device memory for specified data structures.
Definition: mptrac.c:5827
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:10867
void mptrac_init(ctl_t *ctl, cache_t *cache, clim_t *clim, atm_t *atm, const int ntask)
Initializes the MPTRAC model and its associated components.
Definition: mptrac.c:4535
void intpol_met_time_3d(const met_t *met0, float array0[EX][EY][EP], const met_t *met1, float array1[EX][EY][EP], const double ts, const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological data in 3D space and time.
Definition: mptrac.c:1626
void intpol_met_space_3d_ml(const met_t *met, float zs[EX][EY][EP], float array[EX][EY][EP], const double z, const double lon, const double lat, double *var)
Interpolates meteorological data in 3D space.
Definition: mptrac.c:1501
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:1053
void module_wet_depo(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Perform wet deposition calculations for air parcels.
Definition: mptrac.c:4190
void compress_pck(const char *varname, float *array, const size_t nxy, const size_t nz, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats.
Definition: mptrac.c:673
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:6134
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:10758
void module_chem_grid(const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double tt)
Computes gridded chemical tracer concentrations (volume mixing ratio) from individual air parcel mass...
Definition: mptrac.c:2470
double clim_photo(const double rate[CP][CSZA][CO3], const clim_photo_t *photo, const double p, const double sza, const double o3c)
Calculates the photolysis rate for a given set of atmospheric conditions.
Definition: mptrac.c:148
void read_clim_zm(const char *filename, const char *varname, clim_zm_t *zm)
Reads zonally averaged climatological data from a netCDF file and populates the given structure.
Definition: mptrac.c:6544
void read_met_nc_grid(const char *filename, const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological grid information from a NetCDF file.
Definition: mptrac.c:9331
void module_sedi(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Simulate sedimentation of particles in the atmosphere.
Definition: mptrac.c:3910
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:10898
void write_atm_asc(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes air parcel data to an ASCII file or gnuplot.
Definition: mptrac.c:11024
void intpol_met_space_3d(const met_t *met, float array[EX][EY][EP], const double p, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological variables in 3D space.
Definition: mptrac.c:1443
void intpol_met_time_3d_ml(const met_t *met0, float zs0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float zs1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double p, const double lon, const double lat, double *var)
Interpolates meteorological data in both space and time.
Definition: mptrac.c:1655
void module_convection(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Performs convective mixing of atmospheric particles.
Definition: mptrac.c:2674
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:6643
void module_bound_cond(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Apply boundary conditions to particles based on meteorological and climatological data.
Definition: mptrac.c:2374
double scan_ctl(const char *filename, int argc, char *argv[], const char *varname, const int arridx, const char *defvalue, char *value)
Scans a control file or command-line arguments for a specified variable.
Definition: mptrac.c:10653
void module_advect_init(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Initializes the advection module by setting up pressure fields.
Definition: mptrac.c:2347
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:4004
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:10805
void intpol_tropo_3d(const double time0, float array0[EX][EY], const double time1, float array1[EX][EY], const double lons[EX], const double lats[EY], const int nlon, const int nlat, const double time, const double lon, const double lat, const int method, double *var, double *sigma)
Interpolates tropopause data in 3D (latitude, longitude, and time).
Definition: mptrac.c:1713
int read_met_nc_3d(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const ctl_t *ctl, const met_t *met, float dest[EX][EY][EP], const float scl)
Reads a 3-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:9179
void read_met_bin_3d(FILE *in, const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname, const float bound_min, const float bound_max)
Reads 3D meteorological data from a binary file, potentially using different compression methods.
Definition: mptrac.c:6861
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:2121
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:10966
void write_prof(const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
Writes profile data to a specified file.
Definition: mptrac.c:12671
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:4625
double tropo_weight(const clim_t *clim, const atm_t *atm, const int ip)
Computes a weighting factor based on tropopause pressure.
Definition: mptrac.c:11001
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:12448
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:3774
int mptrac_read_atm(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a specified file into the given atmospheric structure.
Definition: mptrac.c:4554
void mptrac_update_host(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
Updates host memory for specified data structures.
Definition: mptrac.c:5883
void mptrac_write_output(const char *dirname, const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double t)
Writes various types of output data to files in a specified directory.
Definition: mptrac.c:6043
double clim_oh(const ctl_t *ctl, const clim_t *clim, const double t, const double lon, const double lat, const double p)
Calculates the hydroxyl radical (OH) concentration from climatology data, with an optional diurnal co...
Definition: mptrac.c:89
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:10178
void mptrac_free(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Frees memory resources allocated for MPTRAC.
Definition: mptrac.c:4382
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:233
void module_rng(const ctl_t *ctl, double *rs, const size_t n, const int method)
Generate random numbers using various methods and distributions.
Definition: mptrac.c:3805
void get_met_help(const ctl_t *ctl, const double t, const int direct, const char *metbase, const double dt_met, char *filename)
Generates a formatted filename for meteorological data files based on the input parameters.
Definition: mptrac.c:1110
void write_station(const char *filename, const ctl_t *ctl, atm_t *atm, const double t)
Writes station data to a specified file.
Definition: mptrac.c:13060
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:10826
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:1023
void intpol_met_time_2d(const met_t *met0, float array0[EX][EY], const met_t *met1, float array1[EX][EY], const double ts, const double lon, const double lat, double *var, int *ci, double *cw, const int init)
Interpolates meteorological data in 2D space and time.
Definition: mptrac.c:1680
void module_position(const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Update the positions and pressure levels of atmospheric particles.
Definition: mptrac.c:3723
void clim_oh_diurnal_correction(const ctl_t *ctl, clim_t *clim)
Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data.
Definition: mptrac.c:115
void locate_vert(float profiles[EX][EY][EP], const int np, const int lon_ap_ind, const int lat_ap_ind, const double height_ap, int *ind)
Locate the four vertical indizes of a box for a given height value.
Definition: mptrac.c:2174
void write_met_bin_2d(FILE *out, met_t *met, float var[EX][EY], const char *varname)
Writes a 2-dimensional meteorological variable to a binary file.
Definition: mptrac.c:12329
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:10072
int read_atm_bin(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a binary file and populates the given atmospheric structure.
Definition: mptrac.c:6222
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:1177
void module_diff_meso(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Simulate mesoscale diffusion for atmospheric particles.
Definition: mptrac.c:2786
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:3939
int read_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a NetCDF file and processes it.
Definition: mptrac.c:8984
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:388
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:1804
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:6684
void mptrac_run_timestep(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t **met0, met_t **met1, atm_t *atm, double t)
Executes a single timestep of the MPTRAC model simulation.
Definition: mptrac.c:5682
void write_atm_clams(const char *filename, const ctl_t *ctl, const atm_t *atm)
Writes air parcel data to a NetCDF file in the CLaMS format.
Definition: mptrac.c:11156
void module_diff_turb(const ctl_t *ctl, cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Applies turbulent diffusion processes to atmospheric particles.
Definition: mptrac.c:2988
int read_atm_clams(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads atmospheric data from a CLAMS NetCDF file.
Definition: mptrac.c:6278
void write_vtk(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes VTK (Visualization Toolkit) data to a specified file.
Definition: mptrac.c:13146
void module_tracer_chem(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Simulate chemical reactions involving long-lived atmospheric tracers.
Definition: mptrac.c:4120
void mptrac_read_ctl(const char *filename, int argc, char *argv[], ctl_t *ctl)
Reads control parameters from a configuration file and populates the given structure.
Definition: mptrac.c:4685
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:10013
void module_h2o2_chem(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Perform chemical reactions involving H2O2 within cloud particles.
Definition: mptrac.c:3103
void write_grid_nc(const char *filename, const ctl_t *ctl, const double *cd, double *mean[NQ], double *sigma[NQ], const double *vmr_impl, const double t, const double *z, const double *lon, const double *lat, const double *area, const double dz, const int *np)
Writes grid data to a NetCDF file.
Definition: mptrac.c:12087
double pbl_weight(const ctl_t *ctl, const atm_t *atm, const int ip, const double pbl, const double ps)
Computes a weighting factor based on planetary boundary layer pressure.
Definition: mptrac.c:6158
void module_diff_pbl(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Computes particle diffusion within the planetary boundary layer (PBL).
Definition: mptrac.c:2863
void write_met_nc_3d(const int ncid, const char *varname, met_t *met, float var[EX][EY][EP], const float scl)
Writes a 3D meteorological variable to a NetCDF file.
Definition: mptrac.c:12641
void module_isosurf(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Apply the isosurface module to adjust atmospheric properties.
Definition: mptrac.c:3255
void module_oh_chem(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Perform hydroxyl chemistry calculations for atmospheric particles.
Definition: mptrac.c:3639
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:1092
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:1837
void read_met_nc_levels(const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological variables at different vertical levels from a NetCDF file.
Definition: mptrac.c:9465
int read_atm_asc(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from an ASCII file and populates the given atmospheric structure.
Definition: mptrac.c:6180
void intpol_check_lon_lat(const double *lons, const int nlon, const double *lats, const int nlat, const double lon, const double lat, double *lon2, double *lat2)
Adjusts longitude and latitude to ensure they fall within valid bounds.
Definition: mptrac.c:1244
void write_sample(const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
Writes sample data to a specified file.
Definition: mptrac.c:12898
void write_grid(const char *filename, const ctl_t *ctl, met_t *met0, met_t *met1, const atm_t *atm, const double t)
Writes grid data to a file in ASCII or netCDF format.
Definition: mptrac.c:11792
void module_dry_depo(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Simulate dry deposition of atmospheric particles.
Definition: mptrac.c:3040
void write_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data in binary format to a specified file.
Definition: mptrac.c:12217
void write_atm_bin(const char *filename, const ctl_t *ctl, const atm_t *atm)
Writes air parcel data to a binary file.
Definition: mptrac.c:11106
void read_met_cape(const ctl_t *ctl, const clim_t *clim, met_t *met)
Calculates Convective Available Potential Energy (CAPE) for each grid point.
Definition: mptrac.c:6967
void mptrac_write_met(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a file, supporting multiple formats and compression options.
Definition: mptrac.c:5999
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:1863
void write_csi(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes Critical Success Index (CSI) data to a file.
Definition: mptrac.c:11416
void write_atm_nc(const char *filename, const ctl_t *ctl, const atm_t *atm)
Writes air parcel data to a NetCDF file.
Definition: mptrac.c:11367
MPTRAC library declarations.
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1371
void compress_zstd(const char *varname, float *array, const size_t n, const int decompress, const int level, FILE *inout)
Compresses or decompresses a float array using Zstandard (ZSTD).
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:318
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:258
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1843
#define DD_NPOLE
Constants indicating the North pole [-].
Definition: mptrac.h:273
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:468
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1398
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:233
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:193
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:228
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:238
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:323
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:343
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:806
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1503
#define H0
Scale height [km].
Definition: mptrac.h:213
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1351
int read_met_nc_dd(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a NetCDF file and processes it.
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1141
int read_met_nc_3d_dd(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const ctl_t *ctl, const met_t *met, float dest[EX][EY][EP], const float scl)
Reads a 3-dimensional meteorological variable from a NetCDF file.
#define DD_SPOLE
Constants indicating the South pole [-].
Definition: mptrac.h:279
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:979
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1155
#define ECC_READ_3D(variable, level, target, scaling_factor, found_flag)
Writes 3D data from a grib message into the meteo struct.
Definition: mptrac.h:743
#define DOTP(a, b)
Calculate the dot product of two vectors.
Definition: mptrac.h:687
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:253
#define EP_GLOB
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:303
#define KARMAN
Karman's constant.
Definition: mptrac.h:223
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:821
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:1126
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2028
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1312
void compress_cms(const ctl_t *ctl, const char *varname, float *array, const size_t nx, const size_t ny, const size_t np, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using a custom multiscale compression algorithm.
void compress_zfp(const char *varname, float *array, const int nx, const int ny, const int nz, const int precision, const double tolerance, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using the ZFP library.
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:298
void dd_particles2atm(atm_t *atm, particle_t *particles, ctl_t *ctl, int *nparticles, cache_t *cache)
Converts particle data to atmospheric data.
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1668
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:852
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:348
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:353
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:449
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:1865
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1428
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:218
#define EY_GLOB
Maximum number of global latitudes for meteo data.
Definition: mptrac.h:313
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:208
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:368
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:333
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:786
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:602
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:538
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:293
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:203
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1476
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1768
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:263
int read_met_grib(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a grib file and processes it.
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1647
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1744
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1818
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1896
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1797
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:639
void dd_atm2particles(atm_t *atm, particle_t *particles, ctl_t *ctl, int *nparticles, cache_t *cache, int rank)
Converts atmospheric data to particle data.
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:1995
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:1915
void read_met_nc_grid_dd(const char *filename, const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological grid data from NetCDF files with domain decomposition.
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1580
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:925
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:426
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1624
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:383
void read_met_nc_surface_dd(const int ncid, const ctl_t *ctl, met_t *met)
Reads and processes surface meteorological data from NetCDF files with domain decomposition.
#define ECC_READ_2D(variable, target, scaling_factor, found_flag)
Writes 2-D data from a grib message into the meteo struct.
Definition: mptrac.h:720
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:555
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:243
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1681
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1520
#define NC_INQ_DIM(dimname, ptr, min, max)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1242
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:328
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2072
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:2108
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:835
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1550
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1289
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:358
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:1958
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1184
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1719
int read_met_nc_2d_dd(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const char *varname5, const char *varname6, const ctl_t *ctl, const met_t *met, float dest[EX][EY], const float scl, const int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
void read_met_nc_levels_dd(const int ncid, const ctl_t *ctl, met_t *met)
Reads and processes meteorological level data from NetCDF files with domain decomposition.
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:493
#define EX_GLOB
Maximum number of global longitudes for meteo data.
Definition: mptrac.h:308
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:338
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1214
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:288
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1452
#define DD_NPART
Maximum number of particles to send and recieve.
Definition: mptrac.h:388
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1605
void module_kpp_chem(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
KPP chemistry module.
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:363
void compress_sz3(const char *varname, float *array, const int nx, const int ny, const int nz, const int precision, const double tolerance, const int decompress, FILE *inout)
Compresses or decompresses a 3-D float array using the SZ3 library.
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1265
#define ECC(cmd)
Execute an ECCODES command and check for errors.
Definition: mptrac.h:701
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:998
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:671
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:517
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:198
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:373
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:620
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1025
#define DD_NNMAX
Maximum number of neighbours to communicate with.
Definition: mptrac.h:393
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:768
Air parcel data.
Definition: mptrac.h:3264
double time[NP]
Time [s].
Definition: mptrac.h:3270
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3279
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3276
int np
Number of air parcels.
Definition: mptrac.h:3267
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3282
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3273
Cache data structure.
Definition: mptrac.h:3343
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3364
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3352
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3355
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3349
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3361
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3358
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3346
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3375
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3381
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3390
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3411
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3387
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3405
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3408
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3402
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3396
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3417
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3420
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3399
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3414
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3393
int np
Number of pressure levels.
Definition: mptrac.h:3378
int no3c
Number of total ozone columns.
Definition: mptrac.h:3384
Climatological data.
Definition: mptrac.h:3483
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3525
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3501
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3513
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3504
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3486
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3531
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3519
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3522
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3516
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3495
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3510
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3489
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3507
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3498
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3492
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3528
Climatological data in the form of time series.
Definition: mptrac.h:3431
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3440
double time[CTS]
Time [s].
Definition: mptrac.h:3437
int ntime
Number of timesteps.
Definition: mptrac.h:3434
Climatological data in the form of zonal means.
Definition: mptrac.h:3451
double time[CT]
Time [s].
Definition: mptrac.h:3463
int np
Number of pressure levels.
Definition: mptrac.h:3460
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3469
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3472
int ntime
Number of timesteps.
Definition: mptrac.h:3454
int nlat
Number of latitudes.
Definition: mptrac.h:3457
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3466
Control parameters.
Definition: mptrac.h:2249
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3132
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2361
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3093
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3060
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2511
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2981
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2589
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2394
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3069
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2843
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2340
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2535
int dd_halos_size
Size of halos given in grid-points.
Definition: mptrac.h:3252
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:3021
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2906
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2930
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2268
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2280
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2544
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2289
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2373
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3063
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2382
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2882
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2831
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3084
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2349
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3210
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2891
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2742
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2903
double stat_r
Search radius around station [km].
Definition: mptrac.h:3216
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2975
int met_zstd_level
ZSTD compression level (from -5 to 22).
Definition: mptrac.h:2598
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3087
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3240
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2927
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2710
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2370
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2945
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2795
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2523
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2632
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2448
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3159
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3135
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2553
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2749
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2529
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2662
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2729
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2412
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2478
char species[LEN]
Species.
Definition: mptrac.h:2840
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3078
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3090
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2777
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2707
double met_comp_tol[METVAR]
Compression tolerance for SZ3 or ZFP.
Definition: mptrac.h:2604
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2364
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2786
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3120
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3138
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3034
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2804
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3150
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2295
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2439
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2635
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2391
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3141
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2418
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2726
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3195
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2472
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2572
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2864
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2948
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2698
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3111
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2623
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2771
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2283
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2316
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2460
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2819
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3222
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3054
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2768
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3156
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3081
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2322
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2954
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3126
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2445
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2936
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2837
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2430
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2695
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2668
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2292
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2759
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3162
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2746
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2825
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2298
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3165
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3057
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2704
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3066
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2665
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2939
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2783
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2647
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2650
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3108
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2626
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3168
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2355
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2810
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2720
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3174
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2277
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2717
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2286
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2735
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2894
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2481
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2415
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3075
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3219
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2957
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2867
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2852
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:2993
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2900
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2436
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3039
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2686
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2966
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3051
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:3002
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2313
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2304
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2508
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3228
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2559
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2801
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3198
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2406
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3105
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2586
int met_comp_prec[METVAR]
Compression precision for SZ3 or ZFP.
Definition: mptrac.h:2601
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2334
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2454
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2653
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2816
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2713
int met_dx
Stride for longitudes.
Definition: mptrac.h:2656
int qnt_destination
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2550
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2915
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2575
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2466
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2861
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2969
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2562
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2762
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2496
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2490
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2337
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3237
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2352
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2433
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2813
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2732
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2409
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2265
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2514
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2683
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2951
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2358
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3183
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2457
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2346
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3204
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2849
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3048
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3123
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2641
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2301
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2617
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3144
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2538
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2532
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2259
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:3018
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2918
int nens
Number of ensembles.
Definition: mptrac.h:3096
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2325
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2385
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2752
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3171
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2689
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2343
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3027
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2963
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2463
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2792
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3099
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2972
int met_vert_coord
Vertical coordinate of input meteo data (0=plev, 1=mlev_p_file, 2=mlev_ab_file, 3=mlev_ab_full,...
Definition: mptrac.h:2579
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3072
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2475
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3213
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2517
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2990
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3147
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2541
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2502
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2674
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2789
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2569
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2828
int dd_nbr_neighbours
Number of neighbours to communicate with.
Definition: mptrac.h:3249
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2620
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2924
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2397
int qnt_zeta_dot
Quantity array index forvelocity of zeta vertical coordinate.
Definition: mptrac.h:2469
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2807
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2897
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2403
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2822
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2909
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2873
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2505
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2493
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3129
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2858
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2310
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3102
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3192
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3030
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2701
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2921
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:3024
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2885
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3189
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2607
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:3008
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2671
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3177
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2933
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2379
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2427
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2442
int qnt_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2547
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2692
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3186
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2400
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:3011
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3180
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2644
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2595
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2960
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2526
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3045
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2999
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2942
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2876
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2638
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2610
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3117
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3225
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:3005
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2328
int met_np
Number of target pressure levels.
Definition: mptrac.h:2677
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2274
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2592
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2888
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2424
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3234
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2879
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2629
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2987
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2765
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2798
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2484
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev).
Definition: mptrac.h:2756
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2421
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2520
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2319
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2912
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3042
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2855
int met_cms_heur
cmultiscale coarsening heuristics (0=default, 1=mean diff, 2=median diff, 3=max diff).
Definition: mptrac.h:2614
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2996
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2451
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2307
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2984
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2978
int met_dy
Stride for latitudes.
Definition: mptrac.h:2659
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2499
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2780
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2834
int dd_subdomains_zonal
Zonal subdomain number.
Definition: mptrac.h:3243
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2271
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2723
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2367
double t_start
Start time of simulation [s].
Definition: mptrac.h:2556
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2262
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2680
int nq
Number of quantities.
Definition: mptrac.h:2256
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2846
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3201
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3231
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3207
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2774
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3153
int dd_subdomains_meridional
Meridional subdomain number.
Definition: mptrac.h:3246
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2331
int met_type
Type of meteo data files (0=netCDF, 1=binary, 2=pck, 3=ZFP, 4=ZSTD, 5=cms, 6=grib,...
Definition: mptrac.h:2583
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2376
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2388
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3114
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2487
Meteo data structure.
Definition: mptrac.h:3542
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3627
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3615
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3687
size_t halo_bnd_count[4]
Definition: mptrac.h:3740
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3657
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3714
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3678
double subdomain_lon_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3719
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3651
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3672
double subdomain_lat_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3728
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3633
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3585
int nx
Number of longitudes.
Definition: mptrac.h:3548
double subdomain_lon_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3722
int ny_glob
Global sizes of meteo data.
Definition: mptrac.h:3752
int ny
Number of latitudes.
Definition: mptrac.h:3551
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3609
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3588
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3684
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3597
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3708
size_t subdomain_start[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3731
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3705
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3594
int halo_offset_start
Definition: mptrac.h:3743
size_t halo_bnd_start[4]
Definition: mptrac.h:3737
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3681
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3696
int np
Number of pressure levels.
Definition: mptrac.h:3554
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3663
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3591
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3666
int halo_offset_end
Definition: mptrac.h:3746
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3603
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3702
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3636
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3648
int nx_glob
Global sizes of meteo data.
Definition: mptrac.h:3749
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3654
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3642
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3567
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3621
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3624
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3618
size_t subdomain_count[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3734
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3600
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3660
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3669
int npl
Number of model levels.
Definition: mptrac.h:3557
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3612
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3690
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3630
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3675
double time
Time [s].
Definition: mptrac.h:3545
double subdomain_lat_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3725
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3639
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3606
int np_glob
Global sizes of meteo data.
Definition: mptrac.h:3755
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3699
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3645
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3574
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3693
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3711
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3581
MPI information data.
Definition: mptrac.h:3319
int rank
Rank of node.
Definition: mptrac.h:3322
int size
Size of node.
Definition: mptrac.h:3325
Particle data.
Definition: mptrac.h:3293
double p
Pressure [hPa].
Definition: mptrac.h:3299
double lat
Latitude [deg].
Definition: mptrac.h:3305
double time
Time [s].
Definition: mptrac.h:3296
double lon
Longitude [deg].
Definition: mptrac.h:3302
double q[NQ]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3308