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
1023#ifdef DD
1025 atm_t *atm,
1026 ctl_t *ctl,
1027 dd_t *dd,
1028 int init) {
1029
1030 SELECT_TIMER("DD_ASSIGN_RECT_SUBDOMAINS", "DD", NVTX_GPU);
1031
1032 if (init) {
1033#ifdef _OPENACC
1034#pragma acc enter data create(dd)
1035#pragma acc update device(dd->rank, dd->subdomain_lon_min, dd->subdomain_lon_max, dd->subdomain_lat_min, dd->subdomain_lat_max)
1036#pragma acc data present(atm, ctl, dd)
1037#pragma acc parallel loop independent gang vector
1038#endif
1039 for (int ip = 0; ip < atm->np; ip++) {
1040
1041 double lont = atm->lon[ip];
1042
1043 if (lont < 0)
1044 lont += 360;
1045
1046 if (lont >= dd->subdomain_lon_min && lont < dd->subdomain_lon_max
1047 && atm->lat[ip] >= dd->subdomain_lat_min
1048 && atm->lat[ip] < dd->subdomain_lat_max) {
1049 atm->q[ctl->qnt_subdomain][ip] = dd->rank;
1050 atm->q[ctl->qnt_destination][ip] = dd->rank;
1051 } else {
1052 WARN
1053 ("DD: Particle is outside the domain (lon: %f, lat: %f, subdomain: %d, subdomain bounds: [%f, %f], [%f, %f])",
1054 atm->lon[ip], atm->lat[ip], dd->rank, dd->subdomain_lon_min,
1056 dd->subdomain_lat_max);
1057 atm->q[ctl->qnt_subdomain][ip] = -1;
1058 atm->q[ctl->qnt_destination][ip] = -1;
1059 }
1060 }
1061#ifdef _OPENACC
1062#pragma acc exit data delete(dd)
1063#endif
1064 } else {
1065
1066 /* Classify air parcels into subdomain... */
1067#ifdef _OPENACC
1068#pragma acc enter data create(dd)
1069#pragma acc update device(dd->neighbours[:DD_NNMAX], dd->rank, dd->size, dd->subdomain_lon_min, dd->subdomain_lon_max, dd->subdomain_lat_min, dd->subdomain_lat_max)
1070#pragma acc data present(atm, ctl, dd)
1071#pragma acc parallel loop independent gang vector
1072#endif
1073 for (int ip = 0; ip < atm->np; ip++) {
1074
1075 /* Skip empty places in the particle array... */
1076 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
1077 continue;
1078
1079 double lont = atm->lon[ip];
1080 double latt = atm->lat[ip];
1081
1082 double lon_max = dd->subdomain_lon_max;
1083 double lon_min = dd->subdomain_lon_min;
1084 double lat_max = dd->subdomain_lat_max;
1085 double lat_min = dd->subdomain_lat_min;
1086
1087 if (lont < 0)
1088 lont += 360;
1089
1090 int left = (dd->rank <= ctl->dd_subdomains_meridional - 1);
1091 int right = (dd->rank >= dd->size - ctl->dd_subdomains_meridional);
1092
1093 int bound = 0;
1094 if (left)
1095 bound = (lont - lon_max > 90) ? 1 : 0;
1096 if (right)
1097 bound = (lon_min - lont > 90) ? 1 : 0;
1098
1099 if (!bound) {
1100 if ((lont >= lon_max) && (latt >= lat_max)) {
1101 // Upper right...
1102 atm->q[ctl->qnt_destination][ip] = dd->neighbours[5];
1103 LOG(4,
1104 "DD: Particle crossing to upper right: from rank %d to rank %d (lon: %f, lat: %f)",
1105 dd->rank, dd->neighbours[5], atm->lon[ip], atm->lat[ip]);
1106 } else if ((lont >= lon_max) && (latt <= lat_min)) {
1107 // Lower right...
1108 atm->q[ctl->qnt_destination][ip] = dd->neighbours[4];
1109 LOG(4,
1110 "DD: Particle crossing to lower right: from rank %d to rank %d (lon: %f, lat: %f)",
1111 dd->rank, dd->neighbours[4], atm->lon[ip], atm->lat[ip]);
1112 } else if ((lont <= lon_min) && (latt >= lat_max)) {
1113 // Upper left...
1114 atm->q[ctl->qnt_destination][ip] = dd->neighbours[2];
1115 LOG(4,
1116 "DD: Particle crossing to upper left: from rank %d to rank %d (lon: %f, lat: %f)",
1117 dd->rank, dd->neighbours[2], atm->lon[ip], atm->lat[ip]);
1118 } else if ((lont <= lon_min) && (latt <= lat_min)) {
1119 // Lower left...
1120 atm->q[ctl->qnt_destination][ip] = dd->neighbours[1];
1121 LOG(4,
1122 "DD: Particle crossing to lower left: from rank %d to rank %d (lon: %f, lat: %f)",
1123 dd->rank, dd->neighbours[1], atm->lon[ip], atm->lat[ip]);
1124 } else if (lont >= lon_max) {
1125 // Right...
1126 atm->q[ctl->qnt_destination][ip] = dd->neighbours[3];
1127 LOG(4,
1128 "DD: Particle crossing to right: from rank %d to rank %d (lon: %f, lat: %f)",
1129 dd->rank, dd->neighbours[3], atm->lon[ip], atm->lat[ip]);
1130 } else if (lont <= lon_min) {
1131 // Left...
1132 atm->q[ctl->qnt_destination][ip] = dd->neighbours[0];
1133 LOG(4,
1134 "DD: Particle crossing to left: from rank %d to rank %d (lon: %f, lat: %f)",
1135 dd->rank, dd->neighbours[0], atm->lon[ip], atm->lat[ip]);
1136 } else if (latt <= lat_min) {
1137 // Down...
1138 atm->q[ctl->qnt_destination][ip] = dd->neighbours[7];
1139 LOG(4,
1140 "DD: Particle crossing downward: from rank %d to rank %d (lon: %f, lat: %f)",
1141 dd->rank, dd->neighbours[7], atm->lon[ip], atm->lat[ip]);
1142 } else if (latt >= lat_max) {
1143 // Up...
1144 atm->q[ctl->qnt_destination][ip] = dd->neighbours[6];
1145 LOG(4,
1146 "DD: Particle crossing upward: from rank %d to rank %d (lon: %f, lat: %f)",
1147 dd->rank, dd->neighbours[6], atm->lon[ip], atm->lat[ip]);
1148 } else {
1149 // Within...
1150 atm->q[ctl->qnt_destination][ip] = dd->rank;
1151 }
1152 } else {
1153 if ((lont >= lon_max) && (latt >= lat_max)) {
1154 // Upper right...
1155 atm->q[ctl->qnt_destination][ip] = dd->neighbours[2];
1156 LOG(4,
1157 "DD: Particle crossing to upper left (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1158 dd->rank, dd->neighbours[2], atm->lon[ip], atm->lat[ip]);
1159 } else if ((lont >= lon_max) && (latt <= lat_min)) {
1160 // Lower right...
1161 atm->q[ctl->qnt_destination][ip] = dd->neighbours[1];
1162 LOG(4,
1163 "DD: Particle crossing to lower left (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1164 dd->rank, dd->neighbours[1], atm->lon[ip], atm->lat[ip]);
1165 } else if ((lont <= lon_min) && (latt >= lat_max)) {
1166 // Upper left...
1167 atm->q[ctl->qnt_destination][ip] = dd->neighbours[5];
1168 LOG(4,
1169 "DD: Particle crossing to upper right (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1170 dd->rank, dd->neighbours[5], atm->lon[ip], atm->lat[ip]);
1171 } else if ((lont <= lon_min) && (latt <= lat_min)) {
1172 // Lower left...
1173 atm->q[ctl->qnt_destination][ip] = dd->neighbours[4];
1174 LOG(4,
1175 "DD: Particle crossing to lower right (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1176 dd->rank, dd->neighbours[4], atm->lon[ip], atm->lat[ip]);
1177 } else if (lont >= lon_max) {
1178 // Right...
1179 atm->q[ctl->qnt_destination][ip] = dd->neighbours[0];
1180 LOG(4,
1181 "DD: Particle crossing to left (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1182 dd->rank, dd->neighbours[0], atm->lon[ip], atm->lat[ip]);
1183 } else if (lont <= lon_min) {
1184 // Left...
1185 atm->q[ctl->qnt_destination][ip] = dd->neighbours[3];
1186 LOG(4,
1187 "DD: Particle crossing to right (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1188 dd->rank, dd->neighbours[3], atm->lon[ip], atm->lat[ip]);
1189 } else if (latt <= lat_min) {
1190 // Down...
1191 atm->q[ctl->qnt_destination][ip] = dd->neighbours[7];
1192 LOG(4,
1193 "DD: Particle crossing downward (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1194 dd->rank, dd->neighbours[7], atm->lon[ip], atm->lat[ip]);
1195 } else if (latt >= lat_max) {
1196 // Up...
1197 atm->q[ctl->qnt_destination][ip] = dd->neighbours[6];
1198 LOG(4,
1199 "DD: Particle crossing upward (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1200 dd->rank, dd->neighbours[6], atm->lon[ip], atm->lat[ip]);
1201 } else {
1202 // Within...
1203 atm->q[ctl->qnt_destination][ip] = dd->rank;
1204 }
1205 }
1206
1207 /* Handle particles assigned to poles by wrapping coordinates and calculating proper subdomain */
1208 /*
1209 if ((int)atm->q[ctl->qnt_destination][ip] < 0) {
1210 int calculated_rank = dd_calc_subdomain_from_coords(atm->lon[ip], atm->lat[ip], met, ctl, dd->size, help_nx_glob, help_ny_glob);
1211
1212 if ((int)atm->q[ctl->qnt_destination][ip] == DD_NPOLE) {
1213 LOG(3, "DD: Particle was assigned to NORTH POLE - redirecting to subdomain %d (lon: %f, lat: %f)",
1214 calculated_rank, atm->lon[ip], atm->lat[ip]);
1215 } else if ((int)atm->q[ctl->qnt_destination][ip] == DD_SPOLE) {
1216 LOG(3, "DD: Particle was assigned to SOUTH POLE - redirecting to subdomain %d (lon: %f, lat: %f)",
1217 calculated_rank, atm->lon[ip], atm->lat[ip]);
1218 } else {
1219 LOG(2, "DD: Particle had invalid destination %d - redirecting to subdomain %d (lon: %f, lat: %f)",
1220 (int)atm->q[ctl->qnt_destination][ip], calculated_rank, atm->lon[ip], atm->lat[ip]);
1221 } */
1222
1223 /* Assign particle to the calculated subdomain */
1224 /*atm->q[ctl->qnt_destination][ip] = calculated_rank;
1225 } */
1226 }
1227#ifdef _OPENACC
1228#pragma acc exit data delete(dd)
1229#endif
1230 }
1231}
1232#endif
1233
1234/*****************************************************************************/
1235
1236#ifdef DD
1237void dd_atm2particles(
1238 atm_t *atm,
1239 particle_t *particles,
1240 ctl_t *ctl,
1241 int *nparticles,
1242 cache_t *cache,
1243 int rank) {
1244
1245 SELECT_TIMER("DD_ATM2PARTICLES", "DD", NVTX_READ);
1246
1247 /* Select the particles that will be send... */
1248#ifdef _OPENACC
1249 int npart = *nparticles;
1250#pragma acc enter data create( nparticles, particles[:DD_NPART])
1251#pragma acc update device( nparticles)
1252#pragma acc parallel loop present( atm, ctl, particles, cache, nparticles)
1253#endif
1254 for (int ip = atm->np; ip < atm->np + *nparticles; ip++)
1255 if (((int) (atm->q[ctl->qnt_destination][ip]) != rank)
1256 && ((int) (atm->q[ctl->qnt_destination][ip]) >= 0)
1257 && ((int) atm->q[ctl->qnt_subdomain][ip] >= 0)) {
1258
1259 particles[ip - atm->np].time = atm->time[ip];
1260 particles[ip - atm->np].lon = atm->lon[ip];
1261 particles[ip - atm->np].lat = atm->lat[ip];
1262 particles[ip - atm->np].p = atm->p[ip];
1263
1264 for (int iq = 0; iq < ctl->nq; iq++)
1265 particles[ip - atm->np].q[iq] = atm->q[iq][ip];
1266
1267 LOG(3,
1268 "DD: Particle being prepared for transfer: subdomain %d -> destination %d (lon: %f, lat: %f)",
1269 (int) atm->q[ctl->qnt_subdomain][ip],
1270 (int) atm->q[ctl->qnt_destination][ip], atm->lon[ip], atm->lat[ip]);
1271 atm->q[ctl->qnt_subdomain][ip] = -1;
1272 cache->dt[ip] = 0;
1273 }
1274#ifdef _OPENACC
1275#pragma acc update host( particles[:npart])
1276#pragma acc exit data delete( nparticles, particles)
1277#endif
1278}
1279#endif
1280
1281/*****************************************************************************/
1282
1283#ifdef DD
1285 double lon,
1286 double lat,
1287 met_t *met,
1288 ctl_t *ctl,
1289 int mpi_size,
1290 int nx_glob,
1291 int ny_glob) {
1292
1293 /* Wrap longitude to [0, 360) */
1294 double wrapped_lon = lon;
1295 while (wrapped_lon < 0)
1296 wrapped_lon += 360;
1297 while (wrapped_lon >= 360)
1298 wrapped_lon -= 360;
1299
1300 /* Handle polar coordinates by wrapping latitude and adjusting longitude */
1301 double wrapped_lat = lat;
1302 if (lat > 90) {
1303 /* North pole overflow: wrap latitude and flip longitude */
1304 wrapped_lat = 180 - lat;
1305 wrapped_lon = fmod(wrapped_lon + 180, 360);
1306 } else if (lat < -90) {
1307 /* South pole overflow: wrap latitude and flip longitude */
1308 wrapped_lat = -180 - lat;
1309 wrapped_lon = fmod(wrapped_lon + 180, 360);
1310 }
1311
1312 /* Get global domain ranges */
1313 /* Handle both periodic (global) and non-periodic (regional) longitude grids */
1314 double lon_range = 360.0;
1315 //if (dd_is_periodic_longitude(met, nx_glob)) {
1316 /* For global grids with periodic boundaries, use full 360 degrees */
1317 //lon_range = 360.0;
1318 //LOG(3, "Detected periodic longitude boundaries, using lon_range = 360.0");
1319 //} else {
1320 /* For regional grids, use the actual data range */
1321 //lon_range = met->lon[nx_glob - 1] - met->lon[0];
1322 //LOG(3, "Detected non-periodic longitude boundaries, using lon_range = %g", lon_range);
1323 //}
1324
1325 LOG(2, "nx_glob: %d", nx_glob);
1326
1327 double lat_range = met->lat[ny_glob - 1] - met->lat[0];
1328 double global_lon_min = met->lon[0];
1329 double global_lat_min = met->lat[0];
1330
1331 /* Calculate subdomain indices */
1332 int lon_idx =
1333 (int) ((wrapped_lon -
1334 global_lon_min) * ctl->dd_subdomains_zonal / lon_range);
1335 int lat_idx =
1336 (int) ((wrapped_lat -
1337 global_lat_min) * ctl->dd_subdomains_meridional / lat_range);
1338
1339 // print wrapped coords, ranges, mins and idxs for debugging
1340 printf
1341 ("DD: Input Lon: %f, Lat: %f | Wrapped Lon: %f, Lat: %f | Lon Range: %f, Lat Range: %f | Lon Min: %f, Lat Min: %f | Lon Idx: %d, Lat Idx: %d\n",
1342 lon, lat, wrapped_lon, wrapped_lat, lon_range, lat_range, global_lon_min,
1343 global_lat_min, lon_idx, lat_idx);
1344
1345 /* Clamp to valid ranges */
1346 lon_idx =
1347 (lon_idx <
1348 0) ? 0 : ((lon_idx >=
1350 1 : lon_idx);
1351 lat_idx =
1352 (lat_idx <
1353 0) ? 0 : ((lat_idx >=
1354 ctl->
1355 dd_subdomains_meridional) ? ctl->dd_subdomains_meridional -
1356 1 : lat_idx);
1357
1358 /* Calculate rank from indices */
1359 int target_rank = lon_idx * ctl->dd_subdomains_meridional + lat_idx;
1360
1361 /* Ensure rank is within valid range */
1362 if (target_rank >= mpi_size)
1363 target_rank = mpi_size - 1;
1364 if (target_rank < 0)
1365 target_rank = 0;
1366
1367 return target_rank;
1368}
1369#endif
1370
1371/*****************************************************************************/
1372
1373#ifdef DD
1375 particle_t *particles,
1376 int *nparticles,
1377 MPI_Datatype MPI_Particle,
1378 int *neighbours,
1379 int nneighbours,
1380 ctl_t ctl) {
1381
1382 /* Initialize the buffers... */
1383 int *nbs;
1384 int *nbr;
1385 ALLOC(nbs, int,
1386 nneighbours);
1387 ALLOC(nbr, int,
1388 nneighbours);
1389 particle_t *send_buffers[DD_NNMAX] = { NULL };
1390 particle_t *recieve_buffers[DD_NNMAX] = { NULL };
1391
1392 /* Get MPI rank... */
1393 int rank;
1394 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
1395
1396 /* Infos for MPI async... */
1397 MPI_Request *requests_snd_nbr =
1398 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1399 MPI_Request *requests_rcv_nbr =
1400 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1401 MPI_Request *requests_snd_part =
1402 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1403 MPI_Request *requests_rcv_part =
1404 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1405 MPI_Status *states =
1406 (MPI_Status *) calloc((size_t) nneighbours, sizeof(MPI_Status));
1407
1408 /* Initialize with MPI_REQUEST_NULL */
1409 for (int i = 0; i < nneighbours; i++) {
1410 requests_snd_nbr[i] = MPI_REQUEST_NULL;
1411 requests_rcv_nbr[i] = MPI_REQUEST_NULL;
1412 requests_snd_part[i] = MPI_REQUEST_NULL;
1413 requests_rcv_part[i] = MPI_REQUEST_NULL;
1414 }
1415
1416 /* Sending... */
1417 for (int idest = 0; idest < nneighbours; idest++) {
1418
1419 /* Ignore poles... */
1420 if (neighbours[idest] < 0)
1421 continue;
1422
1423 SELECT_TIMER("DD_COUNT_NUMBER", "DD", NVTX_CPU);
1424 /* Count number of particles in particle array that will be send... */
1425 int help_sum = 0;
1426 for (int ip = 0; ip < *nparticles; ip++)
1427 if ((int) particles[ip].q[ctl.qnt_destination] == neighbours[idest])
1428 help_sum++;
1429 nbs[idest] = help_sum;
1430
1431 if (help_sum > 0) {
1432 LOG(3, "DD: Rank %d sending %d particles to neighbour %d (rank %d)",
1433 rank, help_sum, idest, neighbours[idest]);
1434 }
1435
1436 SELECT_TIMER("DD_SEND_NUMBER", "DD", NVTX_CPU);
1437 /* Send buffer sizes... */
1438 MPI_Isend(&nbs[idest], 1, MPI_INT,
1439 neighbours[idest], 0, MPI_COMM_WORLD, &requests_snd_nbr[idest]);
1440
1441 /* Don't send empty signals... */
1442 if (nbs[idest] == 0)
1443 continue;
1444
1445 SELECT_TIMER("DD_PREP_BUFFER", "DD", NVTX_CPU);
1446 /* Allocate buffer for sending... */
1447 ALLOC(send_buffers[idest], particle_t, nbs[idest]);
1448
1449 /* Fill the send buffer in a sorted way... */
1450 int ibs = 0;
1451 for (int ip = 0; ip < *nparticles; ip++) {
1452 if ((int) particles[ip].q[ctl.qnt_destination] == neighbours[idest]) {
1453 memcpy(&send_buffers[idest][ibs], &particles[ip], sizeof(particle_t));
1454 ibs++;
1455 }
1456
1457 if (ibs == nbs[idest])
1458 break;
1459 }
1460
1461 SELECT_TIMER("DD_SEND_PARTICLES", "DD", NVTX_CPU);
1462
1463 /* Send the buffer... */
1464 MPI_Isend(send_buffers[idest], nbs[idest], MPI_Particle,
1465 neighbours[idest], 1, MPI_COMM_WORLD,
1466 &requests_snd_part[idest]);
1467 }
1468
1469 SELECT_TIMER("DD_RECIEVE_NUMBERS", "DD", NVTX_CPU);
1470
1471 /* Recieving... */
1472 for (int isourc = 0; isourc < nneighbours; isourc++) {
1473
1474 /* Ignore poles... */
1475 if (neighbours[isourc] < 0) {
1476 requests_rcv_nbr[isourc] = MPI_REQUEST_NULL;
1477 continue;
1478 }
1479
1480 /* Recieve buffer sizes... */
1481 MPI_Irecv(&nbr[isourc], 1, MPI_INT, neighbours[isourc], 0, MPI_COMM_WORLD,
1482 &requests_rcv_nbr[isourc]);
1483 }
1484
1485 /* Wait for all particle numbers to be recieved... */
1486 MPI_Waitall(nneighbours, requests_rcv_nbr, states);
1487
1488 SELECT_TIMER("DD_RECIEVE_PARTICLES", "DD", NVTX_CPU);
1489 for (int isourc = 0; isourc < nneighbours; isourc++) {
1490
1491 /* Ignore poles, and neighbours without signal... */
1492 if ((neighbours[isourc] < 0) || (nbr[isourc] == 0)) {
1493 requests_rcv_part[isourc] = MPI_REQUEST_NULL;
1494 continue;
1495 }
1496
1497 /* Allocate buffer for recieving... */
1498 ALLOC(recieve_buffers[isourc], particle_t, nbr[isourc]);
1499
1500 /* Receive... */
1501 MPI_Irecv(recieve_buffers[isourc], nbr[isourc], MPI_Particle,
1502 neighbours[isourc], 1, MPI_COMM_WORLD,
1503 &requests_rcv_part[isourc]);
1504 }
1505
1506 /* Wait for all particles to be recieved... */
1507 MPI_Waitall(nneighbours, requests_rcv_part, states);
1508
1509 SELECT_TIMER("DD_EMPTY_BUFFER", "DD", NVTX_CPU);
1510
1511 /* Start position for different buffer ranges... */
1512 int api = 0;
1513
1514 /* Putting buffer into particle array... */
1515 for (int isourc = 0; isourc < nneighbours; isourc++) {
1516
1517 /* Ignore poles... */
1518 if (neighbours[isourc] < 0)
1519 continue;
1520
1521 if (nbr[isourc] > 0) {
1522 LOG(3, "DD: Rank %d receiving %d particles from neighbour %d (rank %d)",
1523 rank, nbr[isourc], isourc, neighbours[isourc]);
1524 }
1525
1526 /* Getting particles from buffer... */
1527 for (int ip = 0; ip < nbr[isourc]; ip++) {
1528 memcpy(&particles[ip + api], &recieve_buffers[isourc][ip],
1529 sizeof(particle_t));
1530 particles[ip + api].q[ctl.qnt_destination] = rank;
1531 particles[ip + api].q[ctl.qnt_subdomain] = rank;
1532 }
1533 api += nbr[isourc];
1534 }
1535
1536 /* Set number of recieved particles... */
1537 *nparticles = api;
1538
1539 SELECT_TIMER("DD_FREE_BUFFER", "DD", NVTX_CPU);
1540
1541 /* Wait for all communication to be finished... */
1542 MPI_Waitall(nneighbours, requests_snd_part, states);
1543 MPI_Waitall(nneighbours, requests_snd_nbr, states);
1544
1545 /* Free buffers and buffersizes... */
1546 for (int i = 0; i < nneighbours; i++) {
1547
1548 if ((send_buffers[i] != NULL) && (nbs[i] != 0)) {
1549 free(send_buffers[i]);
1550 send_buffers[i] = NULL;
1551 }
1552
1553 if ((recieve_buffers[i] != NULL) && (nbr[i] != 0)) {
1554 free(recieve_buffers[i]);
1555 recieve_buffers[i] = NULL;
1556 }
1557 }
1558
1559 free(nbs);
1560 free(nbr);
1561}
1562#endif
1563
1564/*****************************************************************************/
1565
1566#ifdef DD
1568 const ctl_t ctl,
1569 dd_t *dd) {
1570 SELECT_TIMER("DD_GET_RECT_NEIGHBOUR", "DD", NVTX_GPU);
1571
1572 const int rank = dd->rank;
1573 const int size = dd->size;
1574 const int m = ctl.dd_subdomains_meridional;
1575 int *nb = dd->neighbours;
1576
1577 nb[0] = (size + rank - m) % size; // left
1578 nb[3] = (rank + m) % size; // right
1579 nb[1] = ((rank + 1) % m == 0) ? DD_SPOLE : (size + rank - m + 1) % size; // lower left
1580 nb[2] = (rank % m == 0) ? DD_NPOLE : (size + rank - m - 1) % size; // upper left
1581 nb[4] = ((rank + 1) % m == 0) ? DD_SPOLE : (rank + m + 1) % size; // lower right
1582 nb[5] = (rank % m == 0) ? DD_NPOLE : (rank + m - 1) % size; // upper right
1583 nb[6] = (rank % m == 0) ? DD_NPOLE : rank - 1; // upper
1584 nb[7] = ((rank + 1) % m == 0) ? DD_SPOLE : rank + 1; // lower
1585}
1586#endif
1587
1588/*****************************************************************************/
1589
1590#ifdef DD
1592 met_t *met,
1593 int nx_glob) {
1594
1595 /* Check if we have at least 2 longitude points... */
1596 if (nx_glob < 2)
1597 return 0;
1598
1599 /* Calculate the longitude spacing */
1600 double lon_spacing = met->lon[1] - met->lon[0];
1601
1602 /* Check if the total range plus one spacing equals 360 degrees
1603 This is the same logic as used in read_met_periodic() */
1604 double total_range = met->lon[nx_glob - 1] - met->lon[0] + lon_spacing;
1605
1606 /* Return 1 if periodic (global), 0 if not periodic (regional) */
1607 return (fabs(total_range - 360.0) < 0.01);
1608}
1609#endif
1610
1611/*****************************************************************************/
1612
1613#ifdef DD
1614int dd_init(
1615 ctl_t *ctl,
1616 dd_t *dd,
1617 atm_t *atm) {
1618
1619 /* Check if enough tasks are requested... */
1620 if (dd->size != ctl->dd_subdomains_meridional * ctl->dd_subdomains_zonal)
1621 ERRMSG("The number of tasks and subdomains is not identical.");
1622
1623#ifdef DD
1624 /* Register the MPI_Particle data type... */
1625 dd_register_MPI_type_particle(&dd->MPI_Particle);
1626#endif
1627
1628 /* Define grid neighbours ... */
1629 dd_get_rect_neighbour(*ctl, dd);
1630
1631 /* Check if particles are in subdomain... */
1632 dd_assign_rect_subdomains_atm(atm, ctl, dd, 1);
1633
1634 /* Set flag of initialization. */
1635 return 1;
1636}
1637#endif
1638
1639/*****************************************************************************/
1640
1641#ifdef DD
1642void dd_particles2atm(
1643 atm_t *atm,
1644 particle_t *particles,
1645 ctl_t *ctl,
1646 int *nparticles,
1647 cache_t *cache) {
1648
1649 SELECT_TIMER("DD_PARTICLES2ATM", "DD", NVTX_CPU);
1650
1651#ifdef _OPENACC
1652 int npart = *nparticles;
1653#pragma acc enter data create(nparticles, particles[:DD_NPART])
1654#pragma acc update device(particles[:npart], nparticles)
1655#pragma acc data present(atm, ctl, cache, particles, nparticles)
1656#pragma acc parallel loop
1657#endif
1658 for (int ip = atm->np; ip < atm->np + *nparticles; ip++) {
1659 atm->time[ip] = particles[ip - atm->np].time;
1660 atm->lon[ip] = particles[ip - atm->np].lon;
1661 atm->lat[ip] = particles[ip - atm->np].lat;
1662 atm->p[ip] = particles[ip - atm->np].p;
1663 for (int iq = 0; iq < ctl->nq; iq++)
1664 atm->q[iq][ip] = particles[ip - atm->np].q[iq];
1665 cache->dt[ip] = ctl->dt_mod;
1666 }
1667#ifdef _OPENACC
1668#pragma acc exit data delete(nparticles, particles)
1669#endif
1670
1671 /* Reset size... */
1672 atm->np += *nparticles;
1673#ifdef _OPENACC
1674#pragma acc update device(atm->np)
1675#endif
1676 if (atm->np > NP)
1677 ERRMSG("Number of particles to high. Increase NP!");
1678}
1679#endif
1680
1681/*****************************************************************************/
1682
1683#ifdef DD
1685 MPI_Datatype *MPI_Particle) {
1686 MPI_Datatype types[5] = { MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE,
1687 MPI_DOUBLE, MPI_DOUBLE
1688 };
1689 int blocklengths[5] = { 1, 1, 1, 1, NQ };
1690 MPI_Aint displacements[5] = { offsetof(particle_t, time),
1691 offsetof(particle_t, p),
1692 offsetof(particle_t, lon),
1693 offsetof(particle_t, lat),
1694 offsetof(particle_t, q)
1695 };
1696 MPI_Type_create_struct(5, blocklengths, displacements, types, MPI_Particle);
1697 MPI_Type_commit(MPI_Particle);
1698}
1699#endif
1700
1701/*****************************************************************************/
1702
1703#ifdef DD
1704void dd_sort(
1705 const ctl_t *ctl,
1706 met_t *met0,
1707 atm_t *atm,
1708 dd_t *dd,
1709 int *nparticles,
1710 int *rank) {
1711
1712 /* Set timer... */
1713 SELECT_TIMER("DD_SORT", "DD", NVTX_GPU);
1714
1715 /* Allocate... */
1716 const int np = atm->np;
1717 double amax = (met0->nx * met0->ny + met0->ny) * met0->np + met0->np;
1718#ifdef _OPENACC
1719#pragma acc enter data create(amax, rank)
1720#pragma acc update device(rank, amax)
1721#pragma acc data present(ctl,met0,atm,dd,amax,rank)
1722#endif
1723
1724 /* Get box index... */
1725#ifdef _OPENACC
1726#pragma acc parallel loop independent gang vector
1727#else
1728#pragma omp parallel for default(shared)
1729#endif
1730 for (int ip = 0; ip < np; ip++) {
1731 if ((int) atm->q[ctl->qnt_subdomain][ip] != -1) {
1732 if ((int) atm->q[ctl->qnt_destination][ip] == *rank)
1733 dd->a[ip] =
1734 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) *
1735 met0->ny + locate_irr(met0->lat, met0->ny, atm->lat[ip]))
1736 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
1737 else
1738 dd->a[ip] = amax + 1;
1739 } else {
1740 dd->a[ip] = amax + 2;
1741 }
1742 dd->p[ip] = ip;
1743 }
1744
1745 /* Sorting... */
1746#ifdef THRUST
1747#ifdef _OPENACC
1748#pragma acc host_data use_device(dd->a,dd->p)
1749#endif
1750 thrustSortWrapper(dd->a, np, dd->p);
1751#else
1752#ifdef _OPENACC
1753 ERRMSG("GSL sort fallback not available on GPU, use THRUST!");
1754#endif
1755 gsl_sort_index((size_t *) (dd->p), (dd->a), 1, (size_t) np);
1756#endif
1757
1758 /* Sort data... */
1759 dd_sort_help(atm->time, dd, np);
1760 dd_sort_help(atm->p, dd, np);
1761 dd_sort_help(atm->lon, dd, np);
1762 dd_sort_help(atm->lat, dd, np);
1763 for (int iq = 0; iq < ctl->nq; iq++)
1764 dd_sort_help(atm->q[iq], dd, np);
1765
1766 /* Reset the size... */
1767 int npt = 0;
1768#ifdef _OPENACC
1769#pragma acc parallel loop reduction(+:npt) present(atm, rank, ctl)
1770#endif
1771 for (int ip = 0; ip < np; ip++)
1772 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
1773 && ((int) atm->q[ctl->qnt_destination][ip] == *rank))
1774 npt++;
1775
1776 /* Count number of particles to send... */
1777 int nparticlest = 0;
1778#ifdef _OPENACC
1779#pragma acc parallel loop reduction(+:nparticlest) present(atm, rank, ctl)
1780#endif
1781 for (int ip = npt; ip < np; ip++)
1782 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
1783 && ((int) atm->q[ctl->qnt_destination][ip] != *rank))
1784 nparticlest++;
1785
1786 /* Reset sizes... */
1787 *nparticles = nparticlest;
1788
1789 /* Count particles with -1 subdomain (these will be effectively lost) */
1790 int nlost = 0;
1791 for (int ip = 0; ip < np; ip++)
1792 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
1793 nlost++;
1794
1795 if (nlost > 0) {
1796 WARN
1797 ("DD: Rank %d: %d particles have subdomain index -1 and will be lost (kept: %d, to_send: %d, total_before: %d)",
1798 *rank, nlost, npt, nparticlest, np);
1799 }
1800
1801 atm->np = npt;
1802#ifdef _OPENACC
1803#pragma acc update device(atm->np)
1804#endif
1805
1806 if (*nparticles > DD_NPART)
1807 ERRMSG
1808 ("Number of particles to send and recieve to small. Increase DD_NPART!");
1809
1810 /* Free... */
1811#ifdef _OPENACC
1812#pragma acc exit data delete(amax, rank)
1813#endif
1814}
1815#endif
1816
1817/*****************************************************************************/
1818
1819#ifdef DD
1820void dd_sort_help(
1821 double *a,
1822 dd_t *dd,
1823 const int np) {
1824
1825 /* Reordering of array... */
1826#ifdef _OPENACC
1827#pragma acc data present(dd,a)
1828#pragma acc parallel loop independent gang vector
1829#else
1830#pragma omp parallel for default(shared)
1831#endif
1832 for (int ip = 0; ip < np; ip++)
1833 dd->help[ip] = a[dd->p[ip]];
1834#ifdef _OPENACC
1835#pragma acc parallel loop independent gang vector
1836#else
1837#pragma omp parallel for default(shared)
1838#endif
1839 for (int ip = 0; ip < np; ip++)
1840 a[ip] = dd->help[ip];
1841}
1842#endif
1843
1844/*****************************************************************************/
1845
1847 const int year,
1848 const int doy,
1849 int *mon,
1850 int *day) {
1851
1852 const int
1853 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1854 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1855
1856 int i;
1857
1858 /* Get month and day... */
1859 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
1860 for (i = 11; i > 0; i--)
1861 if (d0l[i] <= doy)
1862 break;
1863 *mon = i + 1;
1864 *day = doy - d0l[i] + 1;
1865 } else {
1866 for (i = 11; i > 0; i--)
1867 if (d0[i] <= doy)
1868 break;
1869 *mon = i + 1;
1870 *day = doy - d0[i] + 1;
1871 }
1872}
1873
1874/*****************************************************************************/
1875
1877 double *fcReal,
1878 double *fcImag,
1879 const int n) {
1880
1881 double data[2 * EX];
1882
1883 /* Check size... */
1884 if (n > EX)
1885 ERRMSG("Too many data points!");
1886
1887 /* Allocate... */
1888 gsl_fft_complex_wavetable *wavetable =
1889 gsl_fft_complex_wavetable_alloc((size_t) n);
1890 gsl_fft_complex_workspace *workspace =
1891 gsl_fft_complex_workspace_alloc((size_t) n);
1892
1893 /* Set data (real, complex)... */
1894 for (int i = 0; i < n; i++) {
1895 data[2 * i] = fcReal[i];
1896 data[2 * i + 1] = fcImag[i];
1897 }
1898
1899 /* Calculate FFT... */
1900 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
1901
1902 /* Copy data... */
1903 for (int i = 0; i < n; i++) {
1904 fcReal[i] = data[2 * i];
1905 fcImag[i] = data[2 * i + 1];
1906 }
1907
1908 /* Free... */
1909 gsl_fft_complex_wavetable_free(wavetable);
1910 gsl_fft_complex_workspace_free(workspace);
1911}
1912
1913/*****************************************************************************/
1914
1916 const double z,
1917 const double lon,
1918 const double lat,
1919 double *x) {
1920
1921 const double radius = z + RE;
1922 const double latrad = DEG2RAD(lat);
1923 const double lonrad = DEG2RAD(lon);
1924 const double coslat = cos(latrad);
1925
1926 x[0] = radius * coslat * cos(lonrad);
1927 x[1] = radius * coslat * sin(lonrad);
1928 x[2] = radius * sin(latrad);
1929}
1930
1931/*****************************************************************************/
1932
1934 const ctl_t *ctl,
1935 const double t,
1936 const int direct,
1937 const char *metbase,
1938 const double dt_met,
1939 char *filename) {
1940
1941 char repl[LEN];
1942
1943 double t6, r;
1944
1945 int year, mon, day, hour, min, sec;
1946
1947 /* Round time to fixed intervals... */
1948 if (direct == -1)
1949 t6 = floor(t / dt_met) * dt_met;
1950 else
1951 t6 = ceil(t / dt_met) * dt_met;
1952
1953 /* Decode time... */
1954 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1955
1956 /* Set filename of MPTRAC meteo files... */
1957 if (ctl->met_clams == 0) {
1958 if (ctl->met_type == 0)
1959 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1960 else if (ctl->met_type == 1)
1961 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1962 else if (ctl->met_type == 2)
1963 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1964 else if (ctl->met_type == 3)
1965 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1966 else if (ctl->met_type == 4)
1967 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1968 else if (ctl->met_type == 5)
1969 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1970 else if (ctl->met_type == 7)
1971 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
1972 sprintf(repl, "%d", year);
1973 get_met_replace(filename, "YYYY", repl);
1974 sprintf(repl, "%02d", mon);
1975 get_met_replace(filename, "MM", repl);
1976 sprintf(repl, "%02d", day);
1977 get_met_replace(filename, "DD", repl);
1978 sprintf(repl, "%02d", hour);
1979 get_met_replace(filename, "HH", repl);
1980 }
1981
1982 /* Set filename of CLaMS meteo files... */
1983 else {
1984 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1985 sprintf(repl, "%d", year);
1986 get_met_replace(filename, "YYYY", repl);
1987 sprintf(repl, "%02d", year % 100);
1988 get_met_replace(filename, "YY", repl);
1989 sprintf(repl, "%02d", mon);
1990 get_met_replace(filename, "MM", repl);
1991 sprintf(repl, "%02d", day);
1992 get_met_replace(filename, "DD", repl);
1993 sprintf(repl, "%02d", hour);
1994 get_met_replace(filename, "HH", repl);
1995 }
1996}
1997
1998/*****************************************************************************/
1999
2001 char *orig,
2002 char *search,
2003 char *repl) {
2004
2005 char buffer[LEN];
2006
2007 /* Iterate... */
2008 for (int i = 0; i < 3; i++) {
2009
2010 /* Replace sub-string... */
2011 char *ch;
2012 if (!(ch = strstr(orig, search)))
2013 return;
2014 strncpy(buffer, orig, (size_t) (ch - orig));
2015 buffer[ch - orig] = 0;
2016 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
2017 orig[0] = 0;
2018 strcpy(orig, buffer);
2019 }
2020}
2021
2022/*****************************************************************************/
2023
2025 const int met_tropo,
2026 ctl_t *ctl,
2027 clim_t *clim,
2028 met_t *met,
2029 const double *lons,
2030 const int nx,
2031 const double *lats,
2032 const int ny,
2033 double *pt,
2034 double *zt,
2035 double *tt,
2036 double *qt,
2037 double *o3t,
2038 double *ps,
2039 double *zs) {
2040
2042
2043 ctl->met_tropo = met_tropo;
2044 read_met_tropo(ctl, clim, met);
2045#pragma omp parallel for default(shared) private(ci,cw)
2046 for (int ix = 0; ix < nx; ix++)
2047 for (int iy = 0; iy < ny; iy++) {
2048 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
2049 &pt[iy * nx + ix], ci, cw, 1);
2050 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
2051 &ps[iy * nx + ix], ci, cw, 0);
2052 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
2053 &zs[iy * nx + ix], ci, cw, 0);
2054 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
2055 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
2056 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
2057 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
2058 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
2059 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
2060 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
2061 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
2062 }
2063}
2064
2065/*****************************************************************************/
2066
2068 const double *lons,
2069 const int nlon,
2070 const double *lats,
2071 const int nlat,
2072 const double lon,
2073 const double lat,
2074 double *lon2,
2075 double *lat2) {
2076
2077 /* Check longitude... */
2078 *lon2 = FMOD(lon, 360.);
2079 if (*lon2 < lons[0])
2080 *lon2 += 360;
2081 else if (*lon2 > lons[nlon - 1])
2082 *lon2 -= 360;
2083
2084 /* Check latitude... */
2085 *lat2 = lat;
2086 if (lats[0] < lats[nlat - 1])
2087 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
2088 else
2089 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
2090}
2091
2092/*****************************************************************************/
2093
2095 const met_t *met0,
2096 float heights0[EX][EY][EP],
2097 float array0[EX][EY][EP],
2098 const met_t *met1,
2099 float heights1[EX][EY][EP],
2100 float array1[EX][EY][EP],
2101 const double ts,
2102 const double height,
2103 const double lon,
2104 const double lat,
2105 double *var,
2106 int *ci,
2107 double *cw,
2108 const int init) {
2109
2110 if (init) {
2111
2112 /* Check longitude and latitude... */
2113 double lon2, lat2;
2114 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
2115 &lon2, &lat2);
2116
2117 /* Get horizontal indizes... */
2118 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
2119 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
2120
2121 /* Locate the vertical indizes for each edge of the column... */
2122 int ind[2][4];
2123 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
2124 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
2125
2126 /* Find minimum and maximum indizes... */
2127 ci[2] = ind[0][0];
2128 int k_max = ind[0][0];
2129 for (int i = 0; i < 2; i++)
2130 for (int j = 0; j < 4; j++) {
2131 if (ci[2] > ind[i][j])
2132 ci[2] = ind[i][j];
2133 if (k_max < ind[i][j])
2134 k_max = ind[i][j];
2135 }
2136
2137 /* Get weighting factors for time, longitude and latitude... */
2138 cw[3] = (ts - met0->time) / (met1->time - met0->time);
2139 cw[0] = (lon2 - met0->lon[ci[0]]) /
2140 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
2141 cw[1] = (lat2 - met0->lat[ci[1]]) /
2142 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
2143
2144 /* Interpolate in time at the lowest level... */
2145 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
2146 - heights0[ci[0]][ci[1]][ci[2]])
2147 + heights0[ci[0]][ci[1]][ci[2]];
2148 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
2149 - heights0[ci[0]][ci[1] + 1][ci[2]])
2150 + heights0[ci[0]][ci[1] + 1][ci[2]];
2151 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
2152 - heights0[ci[0] + 1][ci[1]][ci[2]])
2153 + heights0[ci[0] + 1][ci[1]][ci[2]];
2154 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
2155 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
2156 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
2157
2158 /* Interpolate in latitude direction... */
2159 double height0 = cw[1] * (height01 - height00) + height00;
2160 double height1 = cw[1] * (height11 - height10) + height10;
2161
2162 /* Interpolate in longitude direction... */
2163 double height_bot = cw[0] * (height1 - height0) + height0;
2164
2165 /* Interpolate in time at the upper level... */
2166 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2167 - heights0[ci[0]][ci[1]][ci[2] + 1])
2168 + heights0[ci[0]][ci[1]][ci[2] + 1];
2169 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2170 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2171 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2172 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2173 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2174 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2175 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2176 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2177 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2178
2179 /* Interpolate in latitude direction... */
2180 height0 = cw[1] * (height01 - height00) + height00;
2181 height1 = cw[1] * (height11 - height10) + height10;
2182
2183 /* Interpolate in longitude direction... */
2184 double height_top = cw[0] * (height1 - height0) + height0;
2185
2186 /* Search at higher levels if height is not in box... */
2187 while (((heights0[0][0][0] > heights0[0][0][1]) &&
2188 ((height_bot <= height) || (height_top > height))
2189 && (height_bot >= height) && (ci[2] < k_max))
2190 ||
2191 ((heights0[0][0][0] < heights0[0][0][1]) &&
2192 ((height_bot >= height) || (height_top < height))
2193 && (height_bot <= height) && (ci[2] < k_max))
2194 ) {
2195
2196 ci[2]++;
2197 height_bot = height_top;
2198
2199 /* Interpolate in time at the next level... */
2200 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2201 - heights0[ci[0]][ci[1]][ci[2] + 1])
2202 + heights0[ci[0]][ci[1]][ci[2] + 1];
2203 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2204 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2205 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2206 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2207 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2208 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2209 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2210 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2211 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2212
2213 /* Interpolate in latitude direction... */
2214 height0 = cw[1] * (height01 - height00) + height00;
2215 height1 = cw[1] * (height11 - height10) + height10;
2216
2217 /* Interpolate in longitude direction... */
2218 height_top = cw[0] * (height1 - height0) + height0;
2219 }
2220
2221 /* Get vertical weighting factors... */
2222 cw[2] = (height - height_bot)
2223 / (height_top - height_bot);
2224 }
2225
2226 /* Calculate the needed array values... */
2227 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
2228 - array0[ci[0]][ci[1]][ci[2]])
2229 + array0[ci[0]][ci[1]][ci[2]];
2230 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
2231 - array0[ci[0] + 1][ci[1]][ci[2]])
2232 + array0[ci[0] + 1][ci[1]][ci[2]];
2233 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
2234 - array0[ci[0]][ci[1] + 1][ci[2]])
2235 + array0[ci[0]][ci[1] + 1][ci[2]];
2236 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
2237 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
2238 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
2239 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
2240 - array0[ci[0]][ci[1]][ci[2] + 1])
2241 + array0[ci[0]][ci[1]][ci[2] + 1];
2242 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2243 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2244 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2245 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2246 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2247 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2248 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2249 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2250 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2251
2252 const double array00 = cw[0] * (array100 - array000) + array000;
2253 const double array10 = cw[0] * (array110 - array010) + array010;
2254 const double array01 = cw[0] * (array101 - array001) + array001;
2255 const double array11 = cw[0] * (array111 - array011) + array011;
2256
2257 const double aux0 = cw[1] * (array10 - array00) + array00;
2258 const double aux1 = cw[1] * (array11 - array01) + array01;
2259
2260 /* Interpolate vertically... */
2261 *var = cw[2] * (aux1 - aux0) + aux0;
2262}
2263
2264/*****************************************************************************/
2265
2267 const met_t *met,
2268 float array[EX][EY][EP],
2269 const double p,
2270 const double lon,
2271 const double lat,
2272 double *var,
2273 int *ci,
2274 double *cw,
2275 const int init) {
2276
2277 /* Initialize interpolation... */
2278 if (init) {
2279
2280 /* Check longitude and latitude... */
2281 double lon2, lat2;
2282 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2283 &lon2, &lat2);
2284
2285 /* Get interpolation indices... */
2286 ci[0] = locate_irr(met->p, met->np, p);
2287 ci[1] = locate_reg(met->lon, met->nx, lon2);
2288 ci[2] = locate_irr(met->lat, met->ny, lat2);
2289
2290 /* Get interpolation weights... */
2291 cw[0] = (met->p[ci[0] + 1] - p)
2292 / (met->p[ci[0] + 1] - met->p[ci[0]]);
2293 cw[1] = (met->lon[ci[1] + 1] - lon2)
2294 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2295 cw[2] = (met->lat[ci[2] + 1] - lat2)
2296 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2297 }
2298
2299 /* Interpolate vertically... */
2300 const double aux00 =
2301 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
2302 + array[ci[1]][ci[2]][ci[0] + 1];
2303 const double aux01 =
2304 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
2305 array[ci[1]][ci[2] + 1][ci[0] + 1])
2306 + array[ci[1]][ci[2] + 1][ci[0] + 1];
2307 const double aux10 =
2308 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
2309 array[ci[1] + 1][ci[2]][ci[0] + 1])
2310 + array[ci[1] + 1][ci[2]][ci[0] + 1];
2311 const double aux11 =
2312 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
2313 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
2314 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
2315
2316 /* Interpolate horizontally... */
2317 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2318 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2319 *var = cw[1] * (aux0 - aux1) + aux1;
2320}
2321
2322/*****************************************************************************/
2323
2325 const met_t *met,
2326 float array[EX][EY],
2327 const double lon,
2328 const double lat,
2329 double *var,
2330 int *ci,
2331 double *cw,
2332 const int init) {
2333
2334 /* Initialize interpolation... */
2335 if (init) {
2336
2337 /* Check longitude and latitude... */
2338 double lon2, lat2;
2339 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2340 &lon2, &lat2);
2341
2342 /* Get interpolation indices... */
2343 ci[1] = locate_reg(met->lon, met->nx, lon2);
2344 ci[2] = locate_irr(met->lat, met->ny, lat2);
2345
2346 /* Get interpolation weights... */
2347 cw[1] = (met->lon[ci[1] + 1] - lon2)
2348 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2349 cw[2] = (met->lat[ci[2] + 1] - lat2)
2350 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2351 }
2352
2353 /* Set variables... */
2354 const double aux00 = array[ci[1]][ci[2]];
2355 const double aux01 = array[ci[1]][ci[2] + 1];
2356 const double aux10 = array[ci[1] + 1][ci[2]];
2357 const double aux11 = array[ci[1] + 1][ci[2] + 1];
2358
2359 /* Interpolate horizontally... */
2360 if (isfinite(aux00) && isfinite(aux01)
2361 && isfinite(aux10) && isfinite(aux11)) {
2362 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2363 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2364 *var = cw[1] * (aux0 - aux1) + aux1;
2365 } else {
2366 if (cw[2] < 0.5) {
2367 if (cw[1] < 0.5)
2368 *var = aux11;
2369 else
2370 *var = aux01;
2371 } else {
2372 if (cw[1] < 0.5)
2373 *var = aux10;
2374 else
2375 *var = aux00;
2376 }
2377 }
2378}
2379
2380/*****************************************************************************/
2381
2383 const met_t *met0,
2384 float array0[EX][EY][EP],
2385 const met_t *met1,
2386 float array1[EX][EY][EP],
2387 const double ts,
2388 const double p,
2389 const double lon,
2390 const double lat,
2391 double *var,
2392 int *ci,
2393 double *cw,
2394 const int init) {
2395
2396 double var0, var1;
2397
2398 /* Spatial interpolation... */
2399 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
2400 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
2401
2402 /* Get weighting factor... */
2403 const double wt = (met1->time - ts) / (met1->time - met0->time);
2404
2405 /* Interpolate... */
2406 *var = wt * (var0 - var1) + var1;
2407}
2408
2409/*****************************************************************************/
2410
2412 const met_t *met0,
2413 float array0[EX][EY],
2414 const met_t *met1,
2415 float array1[EX][EY],
2416 const double ts,
2417 const double lon,
2418 const double lat,
2419 double *var,
2420 int *ci,
2421 double *cw,
2422 const int init) {
2423
2424 double var0, var1;
2425
2426 /* Spatial interpolation... */
2427 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
2428 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
2429
2430 /* Get weighting factor... */
2431 const double wt = (met1->time - ts) / (met1->time - met0->time);
2432
2433 /* Interpolate... */
2434 if (isfinite(var0) && isfinite(var1))
2435 *var = wt * (var0 - var1) + var1;
2436 else if (wt < 0.5)
2437 *var = var1;
2438 else
2439 *var = var0;
2440}
2441
2442/*****************************************************************************/
2443
2445 const double time0,
2446 float array0[EX][EY],
2447 const double time1,
2448 float array1[EX][EY],
2449 const double lons[EX],
2450 const double lats[EY],
2451 const int nlon,
2452 const int nlat,
2453 const double time,
2454 const double lon,
2455 const double lat,
2456 const int method,
2457 double *var,
2458 double *sigma) {
2459
2460 double mean = 0;
2461
2462 int n = 0;
2463
2464 /* Check longitude and latitude... */
2465 double lon2, lat2;
2466 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
2467
2468 /* Get indices... */
2469 const int ix = locate_reg(lons, (int) nlon, lon2);
2470 const int iy = locate_irr(lats, (int) nlat, lat2);
2471
2472 /* Calculate standard deviation... */
2473 *sigma = 0;
2474 for (int dx = 0; dx < 2; dx++)
2475 for (int dy = 0; dy < 2; dy++) {
2476 if (isfinite(array0[ix + dx][iy + dy])) {
2477 mean += array0[ix + dx][iy + dy];
2478 *sigma += SQR(array0[ix + dx][iy + dy]);
2479 n++;
2480 }
2481 if (isfinite(array1[ix + dx][iy + dy])) {
2482 mean += array1[ix + dx][iy + dy];
2483 *sigma += SQR(array1[ix + dx][iy + dy]);
2484 n++;
2485 }
2486 }
2487 if (n > 0)
2488 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
2489
2490 /* Linear interpolation... */
2491 if (method == 1 && isfinite(array0[ix][iy])
2492 && isfinite(array0[ix][iy + 1])
2493 && isfinite(array0[ix + 1][iy])
2494 && isfinite(array0[ix + 1][iy + 1])
2495 && isfinite(array1[ix][iy])
2496 && isfinite(array1[ix][iy + 1])
2497 && isfinite(array1[ix + 1][iy])
2498 && isfinite(array1[ix + 1][iy + 1])) {
2499
2500 const double aux00 = LIN(lons[ix], array0[ix][iy],
2501 lons[ix + 1], array0[ix + 1][iy], lon2);
2502 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
2503 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2504 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2505
2506 const double aux10 = LIN(lons[ix], array1[ix][iy],
2507 lons[ix + 1], array1[ix + 1][iy], lon2);
2508 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
2509 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2510 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2511
2512 *var = LIN(time0, aux0, time1, aux1, time);
2513 }
2514
2515 /* Nearest neighbor interpolation... */
2516 else {
2517 const double aux00 = NN(lons[ix], array0[ix][iy],
2518 lons[ix + 1], array0[ix + 1][iy], lon2);
2519 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
2520 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2521 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2522
2523 const double aux10 = NN(lons[ix], array1[ix][iy],
2524 lons[ix + 1], array1[ix + 1][iy], lon2);
2525 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
2526 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2527 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2528
2529 *var = NN(time0, aux0, time1, aux1, time);
2530 }
2531}
2532
2533/*****************************************************************************/
2534
2536 const double jsec,
2537 int *year,
2538 int *mon,
2539 int *day,
2540 int *hour,
2541 int *min,
2542 int *sec,
2543 double *remain) {
2544
2545 struct tm t0, *t1;
2546
2547 t0.tm_year = 100;
2548 t0.tm_mon = 0;
2549 t0.tm_mday = 1;
2550 t0.tm_hour = 0;
2551 t0.tm_min = 0;
2552 t0.tm_sec = 0;
2553
2554 const time_t jsec0 = (time_t) jsec + timegm(&t0);
2555 t1 = gmtime(&jsec0);
2556
2557 *year = t1->tm_year + 1900;
2558 *mon = t1->tm_mon + 1;
2559 *day = t1->tm_mday;
2560 *hour = t1->tm_hour;
2561 *min = t1->tm_min;
2562 *sec = t1->tm_sec;
2563 *remain = jsec - floor(jsec);
2564}
2565
2566/*****************************************************************************/
2567
2569 const double kz[EP],
2570 const double kw[EP],
2571 const int nk,
2572 const double p) {
2573
2574 /* Check number of data points... */
2575 if (nk < 2)
2576 return 1.0;
2577
2578 /* Get altitude... */
2579 const double z = Z(p);
2580
2581 /* Get weighting factor... */
2582 if (z < kz[0])
2583 return kw[0];
2584 else if (z > kz[nk - 1])
2585 return kw[nk - 1];
2586 else {
2587 const int idx = locate_irr(kz, nk, z);
2588 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
2589 }
2590}
2591
2592/*****************************************************************************/
2593
2595 const double t,
2596 const double h2o) {
2597
2598 /*
2599 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
2600 and water vapor volume mixing ratio [1].
2601
2602 Reference: https://en.wikipedia.org/wiki/Lapse_rate
2603 */
2604
2605 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
2606
2607 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
2608}
2609
2610/*****************************************************************************/
2611
2613 ctl_t *ctl) {
2614
2615 if (0 == ctl->met_press_level_def) {
2616
2617 ctl->met_np = 138;
2618
2619 const double press[138] = {
2620 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
2621 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
2622 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
2623 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
2624 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2625 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
2626 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
2627 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
2628 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
2629 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
2630 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
2631 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
2632 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
2633 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
2634 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
2635 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
2636 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
2637 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
2638 1010.8487, 1013.2500, 1044.45
2639 };
2640
2641 for (int ip = 0; ip < ctl->met_np; ip++)
2642 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2643
2644 } else if (1 == ctl->met_press_level_def) {
2645
2646 ctl->met_np = 92;
2647
2648 const double press[92] = {
2649 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
2650 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
2651 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
2652 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
2653 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
2654 113.6382,
2655 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
2656 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
2657 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2658 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2659 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2660 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2661 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2662 1007.4431, 1010.8487, 1013.2500, 1044.45
2663 };
2664
2665 for (int ip = 0; ip < ctl->met_np; ip++)
2666 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2667
2668 } else if (2 == ctl->met_press_level_def) {
2669
2670 ctl->met_np = 60;
2671
2672 const double press[60] = {
2673 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2674 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2675 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2676 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2677 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2678 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2679 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2680 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1044.45
2681 };
2682
2683 for (int ip = 0; ip < ctl->met_np; ip++)
2684 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2685
2686 } else if (3 == ctl->met_press_level_def) {
2687
2688 ctl->met_np = 147;
2689
2690 const double press[147] = {
2691 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
2692 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
2693 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
2694 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
2695 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2696 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
2697 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
2698 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
2699 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
2700 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
2701 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
2702 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
2703 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
2704 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
2705 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
2706 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
2707 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
2708 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
2709 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
2710 1031.97,
2711 1035.09, 1038.21, 1041.33, 1044.45
2712 };
2713
2714 for (int ip = 0; ip < ctl->met_np; ip++)
2715 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2716
2717 } else if (4 == ctl->met_press_level_def) {
2718
2719 ctl->met_np = 101;
2720
2721 const double press[101] = {
2722 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
2723 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
2724 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
2725 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
2726 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
2727 113.6382,
2728 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
2729 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
2730 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2731 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2732 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2733 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2734 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2735 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
2736 1028.85, 1031.97,
2737 1035.09, 1038.21, 1041.33, 1044.45
2738 };
2739
2740 for (int ip = 0; ip < ctl->met_np; ip++)
2741 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2742
2743 } else if (5 == ctl->met_press_level_def) {
2744
2745 ctl->met_np = 62;
2746
2747 const double press[62] = {
2748 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2749 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2750 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2751 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2752 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2753 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2754 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2755 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
2756 1044.45
2757 };
2758
2759 for (int ip = 0; ip < ctl->met_np; ip++)
2760 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2761
2762 } else if (6 == ctl->met_press_level_def) {
2763
2764 ctl->met_np = 137;
2765
2766 const double press[137] = {
2767 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
2768 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
2769 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
2770 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
2771 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
2772 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2773 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
2774 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
2775 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
2776 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
2777 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
2778 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
2779 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
2780 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
2781 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
2782 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
2783 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
2784 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
2785 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
2786 1030.06, 1037.25, 1044.45
2787 };
2788
2789 for (int ip = 0; ip < ctl->met_np; ip++)
2790 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2791
2792 } else if (7 == ctl->met_press_level_def) {
2793
2794 ctl->met_np = 59;
2795
2796 const double press[59] = {
2797 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2798 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2799 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2800 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2801 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2802 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2803 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2804 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2805 1028.53, 1046.13
2806 };
2807
2808 for (int ip = 0; ip < ctl->met_np; ip++)
2809 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2810
2811 } else {
2812 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.");
2813 }
2814
2815 if (ctl->met_np > EP) {
2816 ERRMSG("Recompile with larger EP to use this pressure level definition.");
2817 }
2818}
2819
2820/*****************************************************************************/
2821
2823 const double *xx,
2824 const int n,
2825 const double x) {
2826
2827 int ilo = 0;
2828 int ihi = n - 1;
2829 int i = (ihi + ilo) >> 1;
2830
2831 if (xx[i] < xx[i + 1])
2832 while (ihi > ilo + 1) {
2833 i = (ihi + ilo) >> 1;
2834 if (xx[i] > x)
2835 ihi = i;
2836 else
2837 ilo = i;
2838 } else
2839 while (ihi > ilo + 1) {
2840 i = (ihi + ilo) >> 1;
2841 if (xx[i] <= x)
2842 ihi = i;
2843 else
2844 ilo = i;
2845 }
2846
2847 return ilo;
2848}
2849
2850/*****************************************************************************/
2851
2853 const float *xx,
2854 const int n,
2855 const double x,
2856 const int ig) {
2857
2858 int ilo = 0;
2859 int ihi = n - 1;
2860 int i = (ihi + ilo) >> 1;
2861
2862 if ((xx[ig] <= x && x < xx[ig + 1]) || (xx[ig] >= x && x > xx[ig + 1]))
2863 return ig;
2864
2865 if (xx[i] < xx[i + 1])
2866 while (ihi > ilo + 1) {
2867 i = (ihi + ilo) >> 1;
2868 if (xx[i] > x)
2869 ihi = i;
2870 else
2871 ilo = i;
2872 } else
2873 while (ihi > ilo + 1) {
2874 i = (ihi + ilo) >> 1;
2875 if (xx[i] <= x)
2876 ihi = i;
2877 else
2878 ilo = i;
2879 }
2880
2881 return ilo;
2882}
2883
2884/*****************************************************************************/
2885
2887 const double *xx,
2888 const int n,
2889 const double x) {
2890
2891 /* Calculate index... */
2892 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2893
2894 /* Check range... */
2895 if (i < 0)
2896 return 0;
2897 else if (i > n - 2)
2898 return n - 2;
2899 else
2900 return i;
2901}
2902
2903/*****************************************************************************/
2904
2906 float profiles[EX][EY][EP],
2907 const int np,
2908 const int lon_ap_ind,
2909 const int lat_ap_ind,
2910 const double height_ap,
2911 int *ind) {
2912
2913 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2914 np, height_ap, 0);
2915 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2916 np, height_ap, ind[0]);
2917 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2918 np, height_ap, ind[1]);
2919 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2920 np, height_ap, ind[2]);
2921}
2922
2923/*****************************************************************************/
2924
2926 const ctl_t *ctl,
2927 const cache_t *cache,
2928 met_t *met0,
2929 met_t *met1,
2930 atm_t *atm) {
2931
2932 /* Set timer... */
2933 SELECT_TIMER("MODULE_ADVECT", "PHYSICS", NVTX_GPU);
2934
2935 /* Use omega vertical velocity... */
2936 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2937
2938 /* Loop over particles... */
2939 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2940
2941 /* Init... */
2943 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2944 x[3] = { 0, 0, 0 };
2945
2946 /* Loop over integration nodes... */
2947 for (int i = 0; i < ctl->advect; i++) {
2948
2949 /* Set position... */
2950 if (i == 0) {
2951 dts = 0.0;
2952 x[0] = atm->lon[ip];
2953 x[1] = atm->lat[ip];
2954 x[2] = atm->p[ip];
2955 } else {
2956 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2957 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2958 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2959 x[2] = atm->p[ip] + dts * w[i - 1];
2960 }
2961 const double tm = atm->time[ip] + dts;
2962
2963 /* Interpolate meteo data on pressure levels... */
2964 if (ctl->advect_vert_coord == 0) {
2965 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2966 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2967 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2968 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2969 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2970 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2971 }
2972
2973 /* Interpolate meteo data on model levels... */
2974 else {
2975 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
2976 met1, met1->pl, met1->ul,
2977 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2978 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
2979 met1, met1->pl, met1->vl,
2980 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2981 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
2982 met1, met1->pl, met1->wl,
2983 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2984 }
2985
2986 /* Get mean wind... */
2987 double k = 1.0;
2988 if (ctl->advect == 2)
2989 k = (i == 0 ? 0.0 : 1.0);
2990 else if (ctl->advect == 4)
2991 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2992 um += k * u[i];
2993 vm += k * v[i];
2994 wm += k * w[i];
2995 }
2996
2997 /* Set new position... */
2998 atm->time[ip] += cache->dt[ip];
2999 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
3000 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3001 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
3002 atm->p[ip] += cache->dt[ip] * wm;
3003 }
3004 }
3005
3006 /* Use zeta or eta vertical velocity... */
3007 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
3008
3009 /* Select quantity index depending on coordinate... */
3010 const int qnt = (ctl->advect_vert_coord == 1
3011 ? ctl->qnt_zeta : ctl->qnt_eta);
3012
3013 /* Loop over particles... */
3014 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3015
3016 /* Convert pressure to vertical coordinate (zeta or eta)... */
3018 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
3019 met1, met1->pl, met1->zetal,
3020 atm->time[ip], atm->p[ip],
3021 atm->lon[ip], atm->lat[ip],
3022 &atm->q[qnt][ip], ci, cw, 1);
3023
3024 /* Init... */
3025 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
3026 wdotm = 0, x[3] = { 0, 0, 0 };
3027
3028 /* Loop over integration nodes (Runge–Kutta steps)... */
3029 for (int i = 0; i < ctl->advect; i++) {
3030
3031 /* Set position... */
3032 if (i == 0) {
3033 dts = 0.0;
3034 x[0] = atm->lon[ip];
3035 x[1] = atm->lat[ip];
3036 x[2] = atm->q[qnt][ip];
3037 } else {
3038 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3039 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
3040 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
3041 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
3042 }
3043
3044 const double tm = atm->time[ip] + dts;
3045
3046 /* Interpolate meteo data... */
3047 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
3048 met1, met1->zetal, met1->ul,
3049 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3050 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
3051 met1, met1->zetal, met1->vl,
3052 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3053 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
3054 met1, met1->zetal, met1->zeta_dotl,
3055 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
3056
3057 /* Compute Runge–Kutta weights... */
3058 double k = 1.0;
3059 if (ctl->advect == 2)
3060 k = (i == 0 ? 0.0 : 1.0);
3061 else if (ctl->advect == 4)
3062 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3063
3064 um += k * u[i];
3065 vm += k * v[i];
3066 wdotm += k * wdot[i];
3067 }
3068
3069 /* Update particle position... */
3070 atm->time[ip] += cache->dt[ip];
3071 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
3072 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3073 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
3074 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
3075
3076 /* Convert vertical coordinate (zeta or eta) back to pressure... */
3077 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
3078 met1, met1->zetal, met1->pl,
3079 atm->time[ip],
3080 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
3081 &atm->p[ip], ci, cw, 1);
3082 }
3083 }
3084}
3085
3086/*****************************************************************************/
3087
3089 const ctl_t *ctl,
3090 const cache_t *cache,
3091 met_t *met0,
3092 met_t *met1,
3093 atm_t *atm) {
3094
3095 /* Check parameters... */
3096 if (ctl->advect_vert_coord != 1)
3097 return;
3098
3099 /* Set timer... */
3100 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS", NVTX_GPU);
3101
3102 /* Loop over particles... */
3103 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
3104
3105 /* Initialize pressure consistent with zeta... */
3107 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
3108 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
3109 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
3110 }
3111}
3112
3113/*****************************************************************************/
3114
3116 const ctl_t *ctl,
3117 const cache_t *cache,
3118 const clim_t *clim,
3119 met_t *met0,
3120 met_t *met1,
3121 atm_t *atm) {
3122
3123 /* Set timer... */
3124 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS", NVTX_GPU);
3125
3126 /* Check quantity flags... */
3127 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
3128 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
3129 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
3130 return;
3131
3132 /* Loop over particles... */
3133 PARTICLE_LOOP(0, atm->np, 1,
3134 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3135
3136 /* Check latitude and pressure range... */
3137 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
3138 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
3139 continue;
3140
3141 /* Check surface layer... */
3142 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
3143 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
3144
3145 /* Get surface pressure... */
3146 double ps;
3148 INTPOL_2D(ps, 1);
3149
3150 /* Check pressure... */
3151 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
3152 continue;
3153
3154 /* Check height... */
3155 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
3156 continue;
3157
3158 /* Check zeta range... */
3159 if (ctl->bound_zetas > 0) {
3160 double t;
3161 INTPOL_3D(t, 1);
3162 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
3163 continue;
3164 }
3165
3166 /* Check planetary boundary layer... */
3167 if (ctl->bound_pbl) {
3168 double pbl;
3169 INTPOL_2D(pbl, 0);
3170 if (atm->p[ip] < pbl)
3171 continue;
3172 }
3173 }
3174
3175 /* Set mass and volume mixing ratio... */
3176 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
3177 atm->q[ctl->qnt_m][ip] =
3178 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
3179 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
3180 atm->q[ctl->qnt_vmr][ip] =
3181 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
3182
3183 /* Set CFC-10 volume mixing ratio... */
3184 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
3185 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
3186
3187 /* Set CFC-11 volume mixing ratio... */
3188 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
3189 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
3190
3191 /* Set CFC-12 volume mixing ratio... */
3192 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
3193 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
3194
3195 /* Set N2O volume mixing ratio... */
3196 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
3197 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
3198
3199 /* Set SF6 volume mixing ratio... */
3200 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
3201 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
3202
3203 /* Set age of air... */
3204 if (ctl->qnt_aoa >= 0)
3205 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
3206 }
3207}
3208
3209/*****************************************************************************/
3210
3212 const ctl_t *ctl,
3213 met_t *met0,
3214 met_t *met1,
3215 atm_t *atm,
3216 const double tt) {
3217
3218 /* Check quantities... */
3219 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
3220 return;
3221 if (ctl->molmass <= 0)
3222 ERRMSG("Molar mass is not defined!");
3223
3224 /* Set timer... */
3225 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS", NVTX_GPU);
3226
3227 /* Allocate... */
3228 const int ensemble_mode = (ctl->nens > 0);
3229 const int np = atm->np;
3230 const int nz = ctl->chemgrid_nz;
3231 const int nx = ctl->chemgrid_nx;
3232 const int ny = ctl->chemgrid_ny;
3233 const int ngrid = nx * ny * nz;
3234 const int nens = ensemble_mode ? ctl->nens : 1;
3235
3236 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
3237 double *restrict const press =
3238 (double *) malloc((size_t) nz * sizeof(double));
3239 double *restrict const mass =
3240 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
3241 double *restrict const area =
3242 (double *) malloc((size_t) ny * sizeof(double));
3243 double *restrict const lon =
3244 (double *) malloc((size_t) nx * sizeof(double));
3245 double *restrict const lat =
3246 (double *) malloc((size_t) ny * sizeof(double));
3247
3248 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3249 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3250 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3251
3252 /* Set grid box size... */
3253 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
3254 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
3255 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
3256
3257 /* Set vertical coordinates... */
3258#ifdef _OPENACC
3259#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])
3260#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
3261#pragma acc parallel loop independent gang vector
3262#else
3263#pragma omp parallel for default(shared)
3264#endif
3265 for (int iz = 0; iz < nz; iz++) {
3266 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
3267 press[iz] = P(z[iz]);
3268 }
3269
3270 /* Set time interval for output... */
3271 const double t0 = tt - 0.5 * ctl->dt_mod;
3272 const double t1 = tt + 0.5 * ctl->dt_mod;
3273
3274 /* Get indices... */
3275#ifdef _OPENACC
3276#pragma acc parallel loop independent gang vector
3277#else
3278#pragma omp parallel for default(shared)
3279#endif
3280 for (int ip = 0; ip < np; ip++) {
3281 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
3282 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
3283 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
3284 if (atm->time[ip] < t0 || atm->time[ip] > t1
3285 || ixs[ip] < 0 || ixs[ip] >= nx
3286 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
3287 izs[ip] = -1;
3288 }
3289
3290 /* Set horizontal coordinates... */
3291#ifdef _OPENACC
3292#pragma acc parallel loop independent gang vector
3293#else
3294#pragma omp parallel for default(shared)
3295#endif
3296 for (int ix = 0; ix < nx; ix++)
3297 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3298
3299#ifdef _OPENACC
3300#pragma acc parallel loop independent gang vector
3301#else
3302#pragma omp parallel for default(shared)
3303#endif
3304 for (int iy = 0; iy < ny; iy++) {
3305 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3306 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3307 }
3308
3309 /* Get mass per grid box... */
3310#ifdef _OPENACC
3311#pragma acc parallel loop independent gang vector
3312#endif
3313 for (int ip = 0; ip < np; ip++) {
3314 if (izs[ip] >= 0) {
3315 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3316 if (ensemble_mode) {
3317 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3318 mass_idx += ens * ngrid;
3319 }
3320#ifdef _OPENACC
3321#pragma acc atomic update
3322#endif
3323 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
3324 }
3325 }
3326
3327 /* Assign grid data to air parcels ... */
3328#ifdef _OPENACC
3329#pragma acc parallel loop independent gang vector
3330#else
3331#pragma omp parallel for default(shared)
3332#endif
3333 for (int ip = 0; ip < np; ip++)
3334 if (izs[ip] >= 0) {
3335
3336 /* Interpolate temperature... */
3337 double temp;
3339 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
3340 press[izs[ip]],
3341 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
3342
3343 /* Set mass... */
3344 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3345 if (ensemble_mode) {
3346 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3347 mass_idx += ens * ngrid;
3348 }
3349
3350 /* Calculate volume mixing ratio... */
3351 const double m = mass[mass_idx];
3352 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
3353 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
3354 }
3355
3356 /* Free... */
3357#ifdef _OPENACC
3358#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
3359#endif
3360 free(mass);
3361 free(lon);
3362 free(lat);
3363 free(area);
3364 free(z);
3365 free(press);
3366 free(ixs);
3367 free(iys);
3368 free(izs);
3369}
3370
3371/*****************************************************************************/
3372
3374 const ctl_t *ctl,
3375 const cache_t *cache,
3376 const clim_t *clim,
3377 met_t *met0,
3378 met_t *met1,
3379 atm_t *atm) {
3380
3381 /* Set timer... */
3382 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS", NVTX_GPU);
3383
3384 /* Loop over particles... */
3385 PARTICLE_LOOP(0, atm->np, 0,
3386 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3387
3388 /* Set H2O and O3 using meteo data... */
3390 if (ctl->qnt_Ch2o >= 0) {
3391 double h2o;
3392 INTPOL_3D(h2o, 1);
3393 SET_ATM(qnt_Ch2o, h2o);
3394 }
3395 if (ctl->qnt_Co3 >= 0) {
3396 double o3;
3397 INTPOL_3D(o3, 1);
3398 SET_ATM(qnt_Co3, o3);
3399 }
3400
3401 /* Set radical species... */
3402 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
3403 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3404 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
3405 atm->lat[ip], atm->p[ip]));
3406 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
3407 atm->lat[ip], atm->p[ip]));
3408 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
3409 atm->lat[ip], atm->p[ip]));
3410 }
3411}
3412
3413/*****************************************************************************/
3414
3416 const ctl_t *ctl,
3417 cache_t *cache,
3418 met_t *met0,
3419 met_t *met1,
3420 atm_t *atm) {
3421
3422 /* Set timer... */
3423 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
3424
3425 /* Create random numbers... */
3426 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
3427
3428 /* Loop over particles... */
3429 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3430
3431 /* Interpolate surface pressure... */
3432 double ps;
3434 INTPOL_2D(ps, 1);
3435
3436 /* Initialize pressure range for vertical mixing... */
3437 double pbot = ps, ptop = ps;
3438
3439 /* Mixing in the PBL... */
3440 if (ctl->conv_mix_pbl) {
3441
3442 /* Interpolate PBL... */
3443 double pbl;
3444 INTPOL_2D(pbl, 0);
3445
3446 /* Set pressure range... */
3447 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
3448 }
3449
3450 /* Convective mixing... */
3451 if (ctl->conv_cape >= 0) {
3452
3453 /* Interpolate CAPE, CIN, and equilibrium level... */
3454 double cape, cin, pel;
3455 INTPOL_2D(cape, 0);
3456 INTPOL_2D(cin, 0);
3457 INTPOL_2D(pel, 0);
3458
3459 /* Set pressure range... */
3460 if (isfinite(cape) && cape >= ctl->conv_cape
3461 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
3462 ptop = GSL_MIN(ptop, pel);
3463 }
3464
3465 /* Apply vertical mixing... */
3466 if (ptop != pbot && atm->p[ip] >= ptop) {
3467
3468 /* Get density range... */
3469 double tbot, ttop;
3470 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
3471 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
3472 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
3473 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
3474 const double rhobot = pbot / tbot;
3475 const double rhotop = ptop / ttop;
3476
3477 /* Get new density... */
3478 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
3479
3480 /* Get pressure... */
3481 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
3482 }
3483 }
3484}
3485
3486/*****************************************************************************/
3487
3488#ifdef DD
3489void module_dd(
3490 ctl_t *ctl,
3491 atm_t *atm,
3492 cache_t *cache,
3493 dd_t *dd,
3494 met_t **met) {
3495
3496 /* Initialize particles locally... */
3497 int nparticles = 0;
3498 particle_t *particles;
3499 ALLOC(particles, particle_t, DD_NPART);
3500
3501 /* Assign particles to new subdomains... */
3502 dd_assign_rect_subdomains_atm(atm, ctl, dd, 0);
3503
3504 /* Sorting particles according to location and target rank... */
3505 dd_sort(ctl, *met, atm, dd, &nparticles, &dd->rank);
3506
3507 /* Transform from struct of array to array of struct... */
3508 dd_atm2particles(atm, particles, ctl, &nparticles, cache, dd->rank);
3509
3510 /********************* CPU region start ***********************************/
3511
3512 /* Perform the communication... */
3513 dd_communicate_particles(particles, &nparticles, dd->MPI_Particle,
3514 dd->neighbours, ctl->dd_nbr_neighbours, *ctl);
3515
3516 /********************* CPU region end *************************************/
3517
3518 /* Transform from array of struct to struct of array... */
3519 dd_particles2atm(atm, particles, ctl, &nparticles, cache);
3520
3521 /* Free local particle array... */
3522 free(particles);
3523}
3524#endif
3525
3526/*****************************************************************************/
3527
3529 const ctl_t *ctl,
3530 const cache_t *cache,
3531 const clim_t *clim,
3532 atm_t *atm) {
3533
3534 /* Set timer... */
3535 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
3536
3537 /* Check quantity flags... */
3538 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3539 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3540
3541 /* Loop over particles... */
3542 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
3543
3544 /* Get weighting factor... */
3545 const double w = tropo_weight(clim, atm, ip);
3546
3547 /* Set lifetime... */
3548 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
3549
3550 /* Calculate exponential decay... */
3551 const double aux = exp(-cache->dt[ip] / tdec);
3552 if (ctl->qnt_m >= 0) {
3553 if (ctl->qnt_mloss_decay >= 0)
3554 atm->q[ctl->qnt_mloss_decay][ip]
3555 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3556 atm->q[ctl->qnt_m][ip] *= aux;
3557 if (ctl->qnt_loss_rate >= 0)
3558 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
3559 }
3560 if (ctl->qnt_vmr >= 0)
3561 atm->q[ctl->qnt_vmr][ip] *= aux;
3562 }
3563}
3564
3565/*****************************************************************************/
3566
3568 const ctl_t *ctl,
3569 cache_t *cache,
3570 met_t *met0,
3571 met_t *met1,
3572 atm_t *atm) {
3573
3574 /* Set timer... */
3575 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS", NVTX_GPU);
3576
3577 /* Create random numbers... */
3578 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3579
3580 /* Loop over particles... */
3581 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3582
3583 /* Get indices... */
3584 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
3585 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
3586 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
3587
3588 /* Get standard deviations of local wind data... */
3589 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
3590 for (int i = 0; i < 2; i++)
3591 for (int j = 0; j < 2; j++)
3592 for (int k = 0; k < 2; k++) {
3593 umean += met0->u[ix + i][iy + j][iz + k];
3594 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
3595 vmean += met0->v[ix + i][iy + j][iz + k];
3596 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
3597 wmean += met0->w[ix + i][iy + j][iz + k];
3598 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
3599
3600 umean += met1->u[ix + i][iy + j][iz + k];
3601 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
3602 vmean += met1->v[ix + i][iy + j][iz + k];
3603 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
3604 wmean += met1->w[ix + i][iy + j][iz + k];
3605 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
3606 }
3607 usig = usig / 16.f - SQR(umean / 16.f);
3608 usig = (usig > 0 ? sqrtf(usig) : 0);
3609 vsig = vsig / 16.f - SQR(vmean / 16.f);
3610 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
3611 wsig = wsig / 16.f - SQR(wmean / 16.f);
3612 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
3613
3614 /* Set temporal correlations for mesoscale fluctuations... */
3615 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
3616 const double r2 = sqrt(1 - r * r);
3617
3618 /* Calculate horizontal mesoscale wind fluctuations... */
3619 if (ctl->turb_mesox > 0) {
3620 cache->uvwp[ip][0] =
3621 (float) (r * cache->uvwp[ip][0] +
3622 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
3623 atm->lon[ip] +=
3624 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3625
3626 cache->uvwp[ip][1] =
3627 (float) (r * cache->uvwp[ip][1] +
3628 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
3629 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3630 }
3631
3632 /* Calculate vertical mesoscale wind fluctuations... */
3633 if (ctl->turb_mesoz > 0) {
3634 cache->uvwp[ip][2] =
3635 (float) (r * cache->uvwp[ip][2] +
3636 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
3637 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
3638 }
3639 }
3640}
3641
3642/*****************************************************************************/
3643
3645 const ctl_t *ctl,
3646 cache_t *cache,
3647 met_t *met0,
3648 met_t *met1,
3649 atm_t *atm) {
3650
3651 /* Set timer... */
3652 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS", NVTX_GPU);
3653
3654 /* Create random numbers... */
3655 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3656
3657 /* Loop over particles... */
3658 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3659
3660 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
3661 tau_u = 300., tau_w = 100.;
3662
3663 /* Get surface and PBL pressure... */
3664 double pbl, ps;
3666 INTPOL_2D(ps, 1);
3667 INTPOL_2D(pbl, 0);
3668
3669 /* Boundary layer... */
3670 if (atm->p[ip] >= pbl) {
3671
3672 /* Calculate heights... */
3673 const double p = MIN(atm->p[ip], ps);
3674 const double zs = Z(ps);
3675 const double z = 1e3 * (Z(p) - zs);
3676 const double zi = 1e3 * (Z(pbl) - zs);
3677 const double zratio = z / zi;
3678
3679 /* Calculate friction velocity... */
3680 double ess, nss, h2o, t;
3681 INTPOL_2D(ess, 0);
3682 INTPOL_2D(nss, 0);
3683 INTPOL_3D(t, 1);
3684 INTPOL_3D(h2o, 0);
3685 const double rho = RHO(p, TVIRT(t, h2o));
3686 const double tau = sqrt(SQR(ess) + SQR(nss));
3687 const double ustar = sqrt(tau / rho);
3688
3689 /* Get surface sensible heat flux... */
3690 double shf;
3691 INTPOL_2D(shf, 1);
3692
3693 /* Stable or neutral conditions... */
3694 if (shf <= 0) {
3695
3696 /* Calcalute turbulent velocity variances... */
3697 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
3698 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
3699
3700 /* Calculate derivative dsig_w/dz... */
3701 dsigw_dz = -1.3 * ustar / zi;
3702
3703 /* Calcalute Lagrangian timescales... */
3704 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
3705 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
3706 }
3707
3708 /* Unstable conditions... */
3709 else {
3710
3711 /* Convective velocity... */
3712 const double wstar =
3713 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
3714
3715 /* Calcalute turbulent velocity variances... */
3716 sig_u = 1e-2
3717 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
3718 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
3719 * pow(zratio, 2.0 / 3.0)
3720 + (1.8 - 1.4 * zratio) * SQR(ustar));
3721
3722 /* Calculate derivative dsig_w/dz... */
3723 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
3724 * (0.8 *
3725 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
3726 - 1.8 * pow(zratio, 2.0 / 3.0)));
3727
3728 /* Calculate Lagrangian timescales... */
3729 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
3730 const double eps =
3731 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
3732 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
3733 tau_u = 2 * SQR(sig_u) / (C0 * eps);
3734 tau_w = 2 * SQR(sig_w) / (C0 * eps);
3735 }
3736 }
3737
3738 /* Set minimum values... */
3739 sig_u = MAX(sig_u, 0.25);
3740 sig_w = MAX(sig_w, 0.1);
3741 tau_u = MAX(tau_u, 300.);
3742 tau_w = MAX(tau_w, 100.);
3743
3744 /* Update perturbations... */
3745 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
3746 const double ru2 = sqrt(1.0 - SQR(ru));
3747 cache->uvwp[ip][0]
3748 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
3749 cache->uvwp[ip][1]
3750 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
3751
3752 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
3753 const double rw2 = sqrt(1.0 - SQR(rw));
3754 cache->uvwp[ip][2]
3755 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
3756 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
3757
3758 /* Calculate new air parcel position... */
3759 atm->lon[ip] +=
3760 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3761 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3762 atm->p[ip] +=
3763 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
3764 }
3765}
3766
3767/*****************************************************************************/
3768
3770 const ctl_t *ctl,
3771 cache_t *cache,
3772 const clim_t *clim,
3773 met_t *met0,
3774 met_t *met1,
3775 atm_t *atm) {
3776
3777 /* Set timer... */
3778 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS", NVTX_GPU);
3779
3780 /* Create random numbers... */
3781 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3782
3783 /* Loop over particles... */
3784 PARTICLE_LOOP(0, atm->np, 1,
3785 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3786
3787 /* Get PBL and surface pressure... */
3788 double pbl, ps;
3790 INTPOL_2D(pbl, 1);
3791 INTPOL_2D(ps, 0);
3792
3793 /* Get weighting factors... */
3794 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
3795 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
3796 const double wstrat = 1.0 - wpbl - wtrop;
3797
3798 /* Set diffusivity... */
3799 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
3800 + wstrat * ctl->turb_dx_strat;
3801 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
3802 + wstrat * ctl->turb_dz_strat;
3803
3804 /* Horizontal turbulent diffusion... */
3805 if (dx > 0) {
3806 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
3807 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
3808 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
3809 }
3810
3811 /* Vertical turbulent diffusion... */
3812 if (dz > 0) {
3813 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
3814 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
3815 }
3816 }
3817}
3818
3819/*****************************************************************************/
3820
3822 const ctl_t *ctl,
3823 const cache_t *cache,
3824 met_t *met0,
3825 met_t *met1,
3826 atm_t *atm) {
3827
3828 /* Set timer... */
3829 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS", NVTX_GPU);
3830
3831 /* Check quantity flags... */
3832 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3833 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3834
3835 /* Loop over particles... */
3836 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3837
3838 /* Get surface pressure... */
3839 double ps;
3841 INTPOL_2D(ps, 1);
3842
3843 /* Check whether particle is above the surface layer... */
3844 if (atm->p[ip] < ps - ctl->dry_depo_dp)
3845 continue;
3846
3847 /* Set depth of surface layer... */
3848 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
3849
3850 /* Calculate sedimentation velocity for particles... */
3851 double v_dep;
3852 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
3853
3854 /* Get temperature... */
3855 double t;
3856 INTPOL_3D(t, 1);
3857
3858 /* Set deposition velocity... */
3859 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3860 atm->q[ctl->qnt_rhop][ip]);
3861 }
3862
3863 /* Use explicit sedimentation velocity for gases... */
3864 else
3865 v_dep = ctl->dry_depo_vdep;
3866
3867 /* Calculate loss of mass based on deposition velocity... */
3868 const double aux = exp(-cache->dt[ip] * v_dep / dz);
3869 if (ctl->qnt_m >= 0) {
3870 if (ctl->qnt_mloss_dry >= 0)
3871 atm->q[ctl->qnt_mloss_dry][ip]
3872 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3873 atm->q[ctl->qnt_m][ip] *= aux;
3874 if (ctl->qnt_loss_rate >= 0)
3875 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
3876 }
3877 if (ctl->qnt_vmr >= 0)
3878 atm->q[ctl->qnt_vmr][ip] *= aux;
3879 }
3880}
3881
3882/*****************************************************************************/
3883
3885 const ctl_t *ctl,
3886 const cache_t *cache,
3887 const clim_t *clim,
3888 met_t *met0,
3889 met_t *met1,
3890 atm_t *atm) {
3891
3892 /* Set timer... */
3893 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS", NVTX_GPU);
3894
3895 /* Check quantity flags... */
3896 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3897 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3898
3899 /* Parameter of SO2 correction... */
3900 const double a = 3.12541941e-06;
3901 const double b = -5.72532259e-01;
3902 const double low = pow(1. / a, 1. / b);
3903
3904 /* Loop over particles... */
3905 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3906
3907 /* Check whether particle is inside cloud... */
3908 double lwc, rwc;
3910 INTPOL_3D(lwc, 1);
3911 INTPOL_3D(rwc, 0);
3912 if (!(lwc > 0 || rwc > 0))
3913 continue;
3914
3915 /* Get temperature... */
3916 double t;
3917 INTPOL_3D(t, 0);
3918
3919 /* Get molecular density... */
3920 const double M = MOLEC_DENS(atm->p[ip], t);
3921
3922 /* Reaction rate (Berglen et al., 2004)... */
3923 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3924
3925 /* Henry constant of SO2... */
3926 const double H_SO2 =
3927 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3928 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3929
3930 /* Henry constant of H2O2... */
3931 const double H_h2o2 =
3932 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3933
3934 /* Correction factor for high SO2 concentration
3935 (if qnt_Cx is defined, the correction is switched on)... */
3936 double cor = 1.0;
3937 if (ctl->qnt_Cx >= 0)
3938 cor = atm->q[ctl->qnt_Cx][ip] >
3939 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3940
3941 const double h2o2 = H_h2o2
3942 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3943 * M * cor * 1000. / AVO; /* unit: mol/L */
3944
3945 /* Volume water content in cloud [m^3 m^(-3)]... */
3946 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3947 const double CWC = (lwc + rwc) * rho_air / 1e3;
3948
3949 /* Calculate exponential decay (Rolph et al., 1992)... */
3950 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3951 const double aux = exp(-cache->dt[ip] * rate_coef);
3952 if (ctl->qnt_m >= 0) {
3953 if (ctl->qnt_mloss_h2o2 >= 0)
3954 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3955 atm->q[ctl->qnt_m][ip] *= aux;
3956 if (ctl->qnt_loss_rate >= 0)
3957 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3958 }
3959 if (ctl->qnt_vmr >= 0)
3960 atm->q[ctl->qnt_vmr][ip] *= aux;
3961 }
3962}
3963
3964/*****************************************************************************/
3965
3967 const ctl_t *ctl,
3968 cache_t *cache,
3969 met_t *met0,
3970 met_t *met1,
3971 atm_t *atm) {
3972
3973 double t;
3974
3975 /* Set timer... */
3976 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS", NVTX_GPU);
3977
3978 /* Save pressure... */
3979 if (ctl->isosurf == 1) {
3980 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
3981 cache->iso_var[ip] = atm->p[ip];
3982 }
3983 }
3984
3985 /* Save density... */
3986 else if (ctl->isosurf == 2) {
3987 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3989 INTPOL_3D(t, 1);
3990 cache->iso_var[ip] = atm->p[ip] / t;
3991 }
3992 }
3993
3994 /* Save potential temperature... */
3995 else if (ctl->isosurf == 3) {
3996 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3998 INTPOL_3D(t, 1);
3999 cache->iso_var[ip] = THETA(atm->p[ip], t);
4000 }
4001 }
4002
4003 /* Read balloon pressure data... */
4004 else if (ctl->isosurf == 4) {
4005
4006 /* Write info... */
4007 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
4008
4009 /* Open file... */
4010 FILE *in;
4011 if (!(in = fopen(ctl->balloon, "r")))
4012 ERRMSG("Cannot open file!");
4013
4014 /* Read pressure time series... */
4015 char line[LEN];
4016 while (fgets(line, LEN, in))
4017 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
4018 &(cache->iso_ps[cache->iso_n])) == 2)
4019 if ((++cache->iso_n) > NP)
4020 ERRMSG("Too many data points!");
4021
4022 /* Check number of points... */
4023 if (cache->iso_n < 1)
4024 ERRMSG("Could not read any data!");
4025
4026 /* Close file... */
4027 fclose(in);
4028
4029 /* Update of cache data on device... */
4030 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
4031 }
4032}
4033
4034/*****************************************************************************/
4035
4037 const ctl_t *ctl,
4038 const cache_t *cache,
4039 met_t *met0,
4040 met_t *met1,
4041 atm_t *atm) {
4042
4043 /* Set timer... */
4044 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
4045
4046 /* Loop over particles... */
4047 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
4048
4049 /* Init... */
4050 double t;
4052
4053 /* Restore pressure... */
4054 if (ctl->isosurf == 1)
4055 atm->p[ip] = cache->iso_var[ip];
4056
4057 /* Restore density... */
4058 else if (ctl->isosurf == 2) {
4059 INTPOL_3D(t, 1);
4060 atm->p[ip] = cache->iso_var[ip] * t;
4061 }
4062
4063 /* Restore potential temperature... */
4064 else if (ctl->isosurf == 3) {
4065 INTPOL_3D(t, 1);
4066 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
4067 }
4068
4069 /* Interpolate pressure... */
4070 else if (ctl->isosurf == 4) {
4071 if (atm->time[ip] <= cache->iso_ts[0])
4072 atm->p[ip] = cache->iso_ps[0];
4073 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
4074 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
4075 else {
4076 const int idx =
4077 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
4078 atm->p[ip] =
4079 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
4080 cache->iso_ps[idx + 1], atm->time[ip]);
4081 }
4082 }
4083 }
4084}
4085
4086/*****************************************************************************/
4087
4088#ifdef KPP
4089void module_kpp_chem(
4090 ctl_t *ctl,
4091 cache_t *cache,
4092 clim_t *clim,
4093 met_t *met0,
4094 met_t *met1,
4095 atm_t *atm) {
4096
4097 /* Set timer... */
4098 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS", NVTX_GPU);
4099
4100 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
4101 double rtol[1] = { 1.0e-3 };
4102 double atol[1] = { 1.0 };
4103
4104 /* Loop over particles... */
4105#ifdef _OPENACC
4106#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
4107#endif
4108 PARTICLE_LOOP(0, atm->np, 1,
4109 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
4110
4111 /* Initialize... */
4112 double var[nvar], fix[nfix], rconst[nreact];
4113 for (int i = 0; i < nvar; i++)
4114 var[i] = 0.0;
4115 for (int i = 0; i < nfix; i++)
4116 fix[i] = 0.0;
4117 for (int i = 0; i < nreact; i++)
4118 rconst[i] = 0.0;
4119 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
4120
4121 /* Integrate... */
4122 double rpar[20];
4123 int ipar[20];
4124 for (int i = 0; i < 20; i++) {
4125 ipar[i] = 0;
4126 rpar[i] = 0.0;
4127 }
4128 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) */
4129 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
4130 ipar[3] = 4; /* choice of the method:Rodas3 */
4131 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
4132 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
4133
4134 /* Save results.. */
4135 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
4136 }
4137}
4138#endif
4139
4140/*****************************************************************************/
4141
4143 const ctl_t *ctl,
4144 const cache_t *cache,
4145 const clim_t *clim,
4146 met_t *met0,
4147 met_t *met1,
4148 atm_t *atm) {
4149
4150 /* Set timer... */
4151 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
4152
4153 /* Check quantity flags... */
4154 if (ctl->qnt_tsts >= 0)
4155 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
4156 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
4157
4158 /* Loop over particles... */
4159 PARTICLE_LOOP(0, atm->np, 0,
4160 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4161
4162 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
4163 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
4164 o3, lwc, rwc, iwc, swc, cc, z, zt;
4165
4166 /* Interpolate meteo data... */
4168 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
4169
4170 /* Set quantities... */
4171 SET_ATM(qnt_ps, ps);
4172 SET_ATM(qnt_ts, ts);
4173 SET_ATM(qnt_zs, zs);
4174 SET_ATM(qnt_us, us);
4175 SET_ATM(qnt_vs, vs);
4176 SET_ATM(qnt_ess, ess);
4177 SET_ATM(qnt_nss, nss);
4178 SET_ATM(qnt_shf, shf);
4179 SET_ATM(qnt_lsm, lsm);
4180 SET_ATM(qnt_sst, sst);
4181 SET_ATM(qnt_pbl, pbl);
4182 SET_ATM(qnt_pt, pt);
4183 SET_ATM(qnt_tt, tt);
4184 SET_ATM(qnt_zt, zt);
4185 SET_ATM(qnt_h2ot, h2ot);
4186 SET_ATM(qnt_zg, z);
4187 SET_ATM(qnt_p, atm->p[ip]);
4188 SET_ATM(qnt_t, t);
4189 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
4190 SET_ATM(qnt_u, u);
4191 SET_ATM(qnt_v, v);
4192 SET_ATM(qnt_w, w);
4193 SET_ATM(qnt_h2o, h2o);
4194 SET_ATM(qnt_o3, o3);
4195 SET_ATM(qnt_lwc, lwc);
4196 SET_ATM(qnt_rwc, rwc);
4197 SET_ATM(qnt_iwc, iwc);
4198 SET_ATM(qnt_swc, swc);
4199 SET_ATM(qnt_cc, cc);
4200 SET_ATM(qnt_pct, pct);
4201 SET_ATM(qnt_pcb, pcb);
4202 SET_ATM(qnt_cl, cl);
4203 SET_ATM(qnt_plcl, plcl);
4204 SET_ATM(qnt_plfc, plfc);
4205 SET_ATM(qnt_pel, pel);
4206 SET_ATM(qnt_cape, cape);
4207 SET_ATM(qnt_cin, cin);
4208 SET_ATM(qnt_o3c, o3c);
4209 SET_ATM(qnt_hno3,
4210 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
4211 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
4212 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4213 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
4214 atm->lat[ip], atm->p[ip]));
4215 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
4216 atm->lat[ip], atm->p[ip]));
4217 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
4218 atm->lat[ip], atm->p[ip]));
4219 SET_ATM(qnt_vh, sqrt(u * u + v * v));
4220 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
4221 SET_ATM(qnt_psat, PSAT(t));
4222 SET_ATM(qnt_psice, PSICE(t));
4223 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
4224 SET_ATM(qnt_sh, SH(h2o));
4225 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
4226 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
4227 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
4228 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
4229 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
4230 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
4231 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
4232 SET_ATM(qnt_eta_dot, atm->q[ctl->qnt_eta_dot][ip]);
4233 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
4234 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
4235 SET_ATM(qnt_pv, pv);
4236 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
4237 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
4238 SET_ATM(qnt_tnat,
4239 nat_temperature(atm->p[ip], h2o,
4240 clim_zm(&clim->hno3, atm->time[ip],
4241 atm->lat[ip], atm->p[ip])));
4242 SET_ATM(qnt_tsts,
4243 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
4244 }
4245}
4246
4247/*****************************************************************************/
4248
4250 const ctl_t *ctl,
4251 const clim_t *clim,
4252 atm_t *atm,
4253 const double t) {
4254
4255 /* Set timer... */
4256 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
4257
4258 /* Allocate... */
4259 const int np = atm->np;
4260 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
4261 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
4262 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
4263
4264 /* Set grid box size... */
4265 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
4266 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
4267 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
4268
4269 /* Set time interval... */
4270 const double t0 = t - 0.5 * ctl->dt_mod;
4271 const double t1 = t + 0.5 * ctl->dt_mod;
4272
4273 /* Get indices... */
4274#ifdef _OPENACC
4275#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
4276#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
4277#pragma acc parallel loop independent gang vector
4278#else
4279#pragma omp parallel for default(shared)
4280#endif
4281 for (int ip = 0; ip < np; ip++) {
4282 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
4283 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
4284 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
4285 if (atm->time[ip] < t0 || atm->time[ip] > t1
4286 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
4287 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
4288 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
4289 izs[ip] = -1;
4290 }
4291
4292 /* Calculate interparcel mixing... */
4293 const int use_ensemble = (ctl->nens > 0);
4294
4295 const int quantities[] = {
4296 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
4297 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
4298 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
4299 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
4300 ctl->qnt_Csf6, ctl->qnt_aoa
4301 };
4302 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
4303
4304 for (int i = 0; i < n_qnt; i++)
4305 if (quantities[i] >= 0)
4306 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
4307 use_ensemble);
4308
4309 /* Free... */
4310#ifdef _OPENACC
4311#pragma acc exit data delete(ixs,iys,izs)
4312#endif
4313 free(ixs);
4314 free(iys);
4315 free(izs);
4316}
4317
4318/*****************************************************************************/
4319
4321 const ctl_t *ctl,
4322 const clim_t *clim,
4323 atm_t *atm,
4324 const int *ixs,
4325 const int *iys,
4326 const int *izs,
4327 const int qnt_idx,
4328 const int use_ensemble) {
4329
4330 const int np = atm->np;
4331 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
4332 const int nens = use_ensemble ? ctl->nens : 1;
4333 const int total_grid = ngrid * nens;
4334
4335 double *restrict const cmean =
4336 (double *) malloc((size_t) total_grid * sizeof(double));
4337 int *restrict const count =
4338 (int *) malloc((size_t) total_grid * sizeof(int));
4339
4340 /* Init... */
4341#ifdef _OPENACC
4342#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
4343#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
4344#pragma acc parallel loop independent gang vector
4345#else
4346#ifdef __NVCOMPILER
4347#pragma novector
4348#endif
4349#pragma omp parallel for
4350#endif
4351 for (int i = 0; i < total_grid; i++) {
4352 count[i] = 0;
4353 cmean[i] = 0.0;
4354 }
4355
4356 /* Loop over particles... */
4357#ifdef _OPENACC
4358#pragma acc parallel loop independent gang vector
4359#endif
4360 for (int ip = 0; ip < np; ip++)
4361 if (izs[ip] >= 0) {
4362 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4363 const int idx =
4364 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4365 ctl->mixing_nz);
4366#ifdef _OPENACC
4367#pragma acc atomic update
4368#endif
4369 cmean[idx] += atm->q[qnt_idx][ip];
4370#ifdef _OPENACC
4371#pragma acc atomic update
4372#endif
4373 count[idx]++;
4374 }
4375
4376 /* Compute means... */
4377#ifdef _OPENACC
4378#pragma acc parallel loop independent gang vector
4379#else
4380#ifdef __NVCOMPILER
4381#pragma novector
4382#endif
4383#pragma omp parallel for
4384#endif
4385 for (int i = 0; i < total_grid; i++)
4386 if (count[i] > 0)
4387 cmean[i] /= count[i];
4388
4389 /* Interparcel mixing... */
4390#ifdef _OPENACC
4391#pragma acc parallel loop independent gang vector
4392#else
4393#pragma omp parallel for
4394#endif
4395 for (int ip = 0; ip < np; ip++) {
4396 if (izs[ip] >= 0) {
4397 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4398
4399 double mixparam = 1.0;
4400 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
4401 const double w = tropo_weight(clim, atm, ip);
4402 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
4403 }
4404
4405 const int idx =
4406 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4407 ctl->mixing_nz);
4408 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
4409 }
4410 }
4411
4412 /* Free... */
4413#ifdef _OPENACC
4414#pragma acc exit data delete(cmean,count)
4415#endif
4416 free(cmean);
4417 free(count);
4418}
4419
4420/*****************************************************************************/
4421
4423 const ctl_t *ctl,
4424 const cache_t *cache,
4425 const clim_t *clim,
4426 met_t *met0,
4427 met_t *met1,
4428 atm_t *atm) {
4429
4430 /* Set timer... */
4431 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS", NVTX_GPU);
4432
4433 /* Check quantity flags... */
4434 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4435 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4436
4437 /* Parameter of SO2 correction... */
4438 const double a = 4.71572206e-08;
4439 const double b = -8.28782867e-01;
4440 const double low = pow(1. / a, 1. / b);
4441
4442 /* Loop over particles... */
4443 PARTICLE_LOOP(0, atm->np, 1,
4444 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4445
4446 /* Get temperature... */
4447 double t;
4449 INTPOL_3D(t, 1);
4450
4451 /* Calculate molecular density... */
4452 const double M = MOLEC_DENS(atm->p[ip], t);
4453
4454 /* Use constant reaction rate... */
4455 double k = NAN;
4456 if (ctl->oh_chem_reaction == 1)
4457 k = ctl->oh_chem[0];
4458
4459 /* Calculate bimolecular reaction rate... */
4460 else if (ctl->oh_chem_reaction == 2)
4461 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
4462
4463 /* Calculate termolecular reaction rate... */
4464 if (ctl->oh_chem_reaction == 3) {
4465
4466 /* Calculate rate coefficient for X + OH + M -> XOH + M
4467 (JPL Publication 19-05) ... */
4468 const double k0 =
4469 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
4470 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
4471 const double ki =
4472 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
4473 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
4474 const double c = log10(k0 * M / ki);
4475 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
4476 }
4477
4478 /* Correction factor for high SO2 concentration
4479 (if qnt_Cx is defined, the correction is switched on)... */
4480 double cor = 1;
4481 if (ctl->qnt_Cx >= 0)
4482 cor =
4483 atm->q[ctl->qnt_Cx][ip] >
4484 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
4485
4486 /* Calculate exponential decay... */
4487 const double rate_coef =
4488 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
4489 atm->lat[ip], atm->p[ip]) * M * cor;
4490 const double aux = exp(-cache->dt[ip] * rate_coef);
4491 if (ctl->qnt_m >= 0) {
4492 if (ctl->qnt_mloss_oh >= 0)
4493 atm->q[ctl->qnt_mloss_oh][ip]
4494 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4495 atm->q[ctl->qnt_m][ip] *= aux;
4496 if (ctl->qnt_loss_rate >= 0)
4497 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4498 }
4499 if (ctl->qnt_vmr >= 0)
4500 atm->q[ctl->qnt_vmr][ip] *= aux;
4501 }
4502}
4503
4504/*****************************************************************************/
4505
4507 const cache_t *cache,
4508 met_t *met0,
4509 met_t *met1,
4510 atm_t *atm) {
4511
4512 /* Set timer... */
4513 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
4514
4515 /* Loop over particles... */
4516 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
4517
4518 /* Init... */
4519 double ps;
4521
4522 /* Calculate modulo... */
4523 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
4524 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
4525
4526 /* Check latitude... */
4527 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
4528 if (atm->lat[ip] > 90) {
4529 atm->lat[ip] = 180 - atm->lat[ip];
4530 atm->lon[ip] += 180;
4531 }
4532 if (atm->lat[ip] < -90) {
4533 atm->lat[ip] = -180 - atm->lat[ip];
4534 atm->lon[ip] += 180;
4535 }
4536 }
4537
4538 /* Check longitude... */
4539 while (atm->lon[ip] < -180)
4540 atm->lon[ip] += 360;
4541 while (atm->lon[ip] >= 180)
4542 atm->lon[ip] -= 360;
4543
4544 /* Check pressure... */
4545 if (atm->p[ip] < met0->p[met0->np - 1]) {
4546 atm->p[ip] = met0->p[met0->np - 1];
4547 } else if (atm->p[ip] > 300.) {
4548 INTPOL_2D(ps, 1);
4549 if (atm->p[ip] > ps)
4550 atm->p[ip] = ps;
4551 }
4552 }
4553}
4554
4555/*****************************************************************************/
4556
4558 const int ntask) {
4559
4560 /* Initialize GSL random number generators... */
4561 gsl_rng_env_setup();
4562 if (omp_get_max_threads() > NTHREADS)
4563 ERRMSG("Too many threads!");
4564 for (int i = 0; i < NTHREADS; i++) {
4565 rng[i] = gsl_rng_alloc(gsl_rng_default);
4566 gsl_rng_set(rng[i], gsl_rng_default_seed
4567 + (long unsigned) (ntask * NTHREADS + i));
4568 }
4569
4570 /* Initialize cuRAND random number generators... */
4571#ifdef CURAND
4572 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
4573 CURAND_STATUS_SUCCESS)
4574 ERRMSG("Cannot create random number generator!");
4575 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
4576 CURAND_STATUS_SUCCESS)
4577 ERRMSG("Cannot set seed for random number generator!");
4578 if (curandSetStream
4579 (rng_curand,
4580 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
4581 CURAND_STATUS_SUCCESS)
4582 ERRMSG("Cannot set stream for random number generator!");
4583#endif
4584}
4585
4586/*****************************************************************************/
4587
4589 const ctl_t *ctl,
4590 double *rs,
4591 const size_t n,
4592 const int method) {
4593
4594 /* Use GSL random number generators... */
4595 if (ctl->rng_type == 0) {
4596
4597 /* Uniform distribution... */
4598 if (method == 0) {
4599#pragma omp parallel for default(shared)
4600 for (size_t i = 0; i < n; ++i)
4601 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
4602 }
4603
4604 /* Normal distribution... */
4605 else if (method == 1) {
4606#pragma omp parallel for default(shared)
4607 for (size_t i = 0; i < n; ++i)
4608 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
4609 }
4610
4611 /* Update of random numbers on device... */
4612#ifdef _OPENACC
4613 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
4614#pragma acc update device(rs[:n])
4615#endif
4616 }
4617
4618 /* Use Squares random number generator (Widynski, 2022)... */
4619 else if (ctl->rng_type == 1) {
4620
4621 /* Set key (don't change this!)... */
4622 const uint64_t key = 0xc8e4fd154ce32f6d;
4623
4624 /* Uniform distribution... */
4625#ifdef _OPENACC
4626#pragma acc data present(rs)
4627#pragma acc parallel loop independent gang vector
4628#else
4629#pragma omp parallel for default(shared)
4630#endif
4631 for (size_t i = 0; i < n + 1; ++i) {
4632 uint64_t r, t, x, y, z;
4633 y = x = (rng_ctr + i) * key;
4634 z = y + key;
4635 x = x * x + y;
4636 x = (x >> 32) | (x << 32);
4637 x = x * x + z;
4638 x = (x >> 32) | (x << 32);
4639 x = x * x + y;
4640 x = (x >> 32) | (x << 32);
4641 t = x = x * x + z;
4642 x = (x >> 32) | (x << 32);
4643 r = t ^ ((x * x + y) >> 32);
4644 rs[i] = (double) r / (double) UINT64_MAX;
4645 }
4646 rng_ctr += n + 1;
4647
4648 /* Normal distribution... */
4649 if (method == 1) {
4650#ifdef _OPENACC
4651#pragma acc parallel loop independent gang vector
4652#else
4653#pragma omp parallel for default(shared)
4654#endif
4655 for (size_t i = 0; i < n; i += 2) {
4656 const double r = sqrt(-2.0 * log(rs[i]));
4657 const double phi = 2.0 * M_PI * rs[i + 1];
4658 rs[i] = r * cosf((float) phi);
4659 rs[i + 1] = r * sinf((float) phi);
4660 }
4661 }
4662 }
4663
4664 /* Use cuRAND random number generators... */
4665 else if (ctl->rng_type == 2) {
4666#ifdef CURAND
4667#pragma acc host_data use_device(rs)
4668 {
4669
4670 /* Uniform distribution... */
4671 if (method == 0) {
4672 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
4673 CURAND_STATUS_SUCCESS)
4674 ERRMSG("Cannot create random numbers!");
4675 }
4676
4677 /* Normal distribution... */
4678 else if (method == 1) {
4679 if (curandGenerateNormalDouble
4680 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
4681 1.0) != CURAND_STATUS_SUCCESS)
4682 ERRMSG("Cannot create random numbers!");
4683 }
4684 }
4685#else
4686 ERRMSG("MPTRAC was compiled without cuRAND!");
4687#endif
4688 }
4689}
4690
4691/*****************************************************************************/
4692
4694 const ctl_t *ctl,
4695 const cache_t *cache,
4696 met_t *met0,
4697 met_t *met1,
4698 atm_t *atm) {
4699
4700 /* Set timer... */
4701 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
4702
4703 /* Loop over particles... */
4704 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4705
4706 /* Get temperature... */
4707 double t;
4709 INTPOL_3D(t, 1);
4710
4711 /* Sedimentation velocity... */
4712 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4713 atm->q[ctl->qnt_rhop][ip]);
4714
4715 /* Calculate pressure change... */
4716 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
4717 }
4718}
4719
4720/*****************************************************************************/
4721
4723 const ctl_t *ctl,
4724 met_t *met0,
4725 atm_t *atm) {
4726
4727 /* Set timer... */
4728 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
4729
4730 /* Allocate... */
4731 const int np = atm->np;
4732 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
4733 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
4734 if (a == NULL || p == NULL)
4735 ERRMSG("Out of memory!");
4736
4737#ifdef _OPENACC
4738#pragma acc enter data create(a[0:np],p[0:np])
4739#pragma acc data present(ctl,met0,atm,a,p)
4740#endif
4741
4742 /* Get box index... */
4743#ifdef _OPENACC
4744#pragma acc parallel loop independent gang vector
4745#else
4746#pragma omp parallel for default(shared)
4747#endif
4748 for (int ip = 0; ip < np; ip++) {
4749 a[ip] =
4750 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
4751 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
4752 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
4753 p[ip] = ip;
4754 }
4755
4756 /* Sorting... */
4757#ifdef THRUST
4758#ifdef _OPENACC
4759#pragma acc host_data use_device(a,p)
4760#endif
4761 thrustSortWrapper(a, np, p);
4762#else
4763#ifdef _OPENACC
4764 ERRMSG("GSL sort fallback not available on GPU, use THRUST!");
4765#endif
4766 gsl_sort_index((size_t *) p, a, 1, (size_t) np);
4767#endif
4768
4769 /* Sort data... */
4770 module_sort_help(atm->time, p, np);
4771 module_sort_help(atm->p, p, np);
4772 module_sort_help(atm->lon, p, np);
4773 module_sort_help(atm->lat, p, np);
4774 for (int iq = 0; iq < ctl->nq; iq++)
4775 module_sort_help(atm->q[iq], p, np);
4776
4777 /* Free... */
4778#ifdef _OPENACC
4779#pragma acc exit data delete(a,p)
4780#endif
4781 free(a);
4782 free(p);
4783}
4784
4785/*****************************************************************************/
4786
4788 double *a,
4789 const int *p,
4790 const int np) {
4791
4792 /* Allocate... */
4793 double *restrict const help =
4794 (double *) malloc((size_t) np * sizeof(double));
4795 if (help == NULL)
4796 ERRMSG("Out of memory!");
4797
4798 /* Reordering of array... */
4799#ifdef _OPENACC
4800#pragma acc enter data create(help[0:np])
4801#pragma acc data present(a,p,help)
4802#pragma acc parallel loop independent gang vector
4803#else
4804#pragma omp parallel for default(shared)
4805#endif
4806 for (int ip = 0; ip < np; ip++)
4807 help[ip] = a[p[ip]];
4808#ifdef _OPENACC
4809#pragma acc parallel loop independent gang vector
4810#else
4811#pragma omp parallel for default(shared)
4812#endif
4813 for (int ip = 0; ip < np; ip++)
4814 a[ip] = help[ip];
4815
4816 /* Free... */
4817#ifdef _OPENACC
4818#pragma acc exit data delete(help)
4819#endif
4820 free(help);
4821}
4822
4823/*****************************************************************************/
4824
4826 const ctl_t *ctl,
4827 cache_t *cache,
4828 met_t *met0,
4829 atm_t *atm,
4830 const double t) {
4831
4832 /* Set timer... */
4833 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
4834
4835 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
4836 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
4837
4838 const int local =
4839 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
4840
4841 /* Loop over particles... */
4842 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
4843
4844 /* Set time step for each air parcel... */
4845 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
4846 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
4847 && ctl->direction * (atm->time[ip] - t) < 0))
4848 cache->dt[ip] = t - atm->time[ip];
4849 else
4850 cache->dt[ip] = 0.0;
4851
4852 /* Check horizontal boundaries of local meteo data... */
4853#ifndef DD
4854 int dd = 1;
4855#else
4856 int dd = 0;
4857#endif
4858 if (dd) {
4859 if (local && (atm->lon[ip] <= met0->lon[0]
4860 || atm->lon[ip] >= met0->lon[met0->nx - 1]
4861 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
4862 cache->dt[ip] = 0.0;
4863 } else {
4864 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
4865 cache->dt[ip] = 0;
4866 }
4867 }
4868}
4869
4870/*****************************************************************************/
4871
4873 ctl_t *ctl,
4874 const atm_t *atm) {
4875
4876 /* Set timer... */
4877 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS", NVTX_GPU);
4878
4879 /* Set start time... */
4880 if (ctl->direction == 1) {
4881 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4882 if (ctl->t_stop > 1e99)
4883 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4884 } else {
4885 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4886 if (ctl->t_stop > 1e99)
4887 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4888 }
4889
4890 /* Check time interval... */
4891 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
4892 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
4893
4894 /* Round start time... */
4895 if (ctl->direction == 1)
4896 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4897 else
4898 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4899}
4900
4901/*****************************************************************************/
4902
4904 const ctl_t *ctl,
4905 const cache_t *cache,
4906 const clim_t *clim,
4907 met_t *met0,
4908 met_t *met1,
4909 atm_t *atm) {
4910
4911 /* Set timer... */
4912 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS", NVTX_GPU);
4913
4914 /* Loop over particles... */
4915 PARTICLE_LOOP(0, atm->np, 1,
4916 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4917
4918 /* Get temperature... */
4919 double t;
4921 INTPOL_3D(t, 1);
4922
4923 /* Get molecular density... */
4924 const double M = MOLEC_DENS(atm->p[ip], t);
4925
4926 /* Get total column ozone... */
4927 double o3c;
4928 INTPOL_2D(o3c, 1);
4929
4930 /* Get solar zenith angle... */
4931 const double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
4932
4933 /* Get O(1D) volume mixing ratio... */
4934 const double o1d =
4935 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4936
4937 /* Reactions for CFC-10... */
4938 if (ctl->qnt_Cccl4 >= 0) {
4939 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4940 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4941 atm->p[ip], sza, o3c);
4942 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4943 }
4944
4945 /* Reactions for CFC-11... */
4946 if (ctl->qnt_Cccl3f >= 0) {
4947 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4948 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4949 atm->p[ip], sza, o3c);
4950 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4951 }
4952
4953 /* Reactions for CFC-12... */
4954 if (ctl->qnt_Cccl2f2 >= 0) {
4955 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4956 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4957 atm->p[ip], sza, o3c);
4958 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4959 }
4960
4961 /* Reactions for N2O... */
4962 if (ctl->qnt_Cn2o >= 0) {
4963 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4964 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4965 atm->p[ip], sza, o3c);
4966 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4967 }
4968 }
4969}
4970
4971/*****************************************************************************/
4972
4974 const ctl_t *ctl,
4975 const cache_t *cache,
4976 met_t *met0,
4977 met_t *met1,
4978 atm_t *atm) {
4979
4980 /* Set timer... */
4981 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS", NVTX_GPU);
4982
4983 /* Check quantity flags... */
4984 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4985 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4986
4987 /* Loop over particles... */
4988 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4989
4990 /* Check whether particle is below cloud top... */
4991 double pct;
4993 INTPOL_2D(pct, 1);
4994 if (!isfinite(pct) || atm->p[ip] <= pct)
4995 continue;
4996
4997 /* Get cloud bottom pressure... */
4998 double pcb;
4999 INTPOL_2D(pcb, 0);
5000
5001 /* Estimate precipitation rate (Pisso et al., 2019)... */
5002 double cl;
5003 INTPOL_2D(cl, 0);
5004 const double Is =
5005 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
5006 if (Is < 0.01)
5007 continue;
5008
5009 /* Check whether particle is inside or below cloud... */
5010 double lwc, rwc, iwc, swc;
5011 INTPOL_3D(lwc, 1);
5012 INTPOL_3D(rwc, 0);
5013 INTPOL_3D(iwc, 0);
5014 INTPOL_3D(swc, 0);
5015 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
5016
5017 /* Get temperature... */
5018 double t;
5019 INTPOL_3D(t, 0);
5020
5021 /* Calculate in-cloud scavenging coefficient... */
5022 double lambda = 0;
5023 if (inside) {
5024
5025 /* Calculate retention factor... */
5026 double eta;
5027 if (t > 273.15)
5028 eta = 1;
5029 else if (t <= 238.15)
5030 eta = ctl->wet_depo_ic_ret_ratio;
5031 else
5032 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
5033
5034 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5035 if (ctl->wet_depo_ic_a > 0)
5036 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
5037
5038 /* Use Henry's law for gases... */
5039 else if (ctl->wet_depo_ic_h[0] > 0) {
5040
5041 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5042 double h = ctl->wet_depo_ic_h[0]
5043 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
5044
5045 /* Use effective Henry's constant for SO2
5046 (Berglen, 2004; Simpson, 2012)... */
5047 if (ctl->wet_depo_so2_ph > 0) {
5048 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
5049 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
5050 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
5051 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
5052 }
5053
5054 /* Estimate depth of cloud layer... */
5055 const double dz = 1e3 * (Z(pct) - Z(pcb));
5056
5057 /* Calculate scavenging coefficient... */
5058 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5059 }
5060 }
5061
5062 /* Calculate below-cloud scavenging coefficient... */
5063 else {
5064
5065 /* Calculate retention factor... */
5066 double eta;
5067 if (t > 270)
5068 eta = 1;
5069 else
5070 eta = ctl->wet_depo_bc_ret_ratio;
5071
5072 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5073 if (ctl->wet_depo_bc_a > 0)
5074 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
5075
5076 /* Use Henry's law for gases... */
5077 else if (ctl->wet_depo_bc_h[0] > 0) {
5078
5079 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5080 const double h = ctl->wet_depo_bc_h[0]
5081 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
5082
5083 /* Estimate depth of cloud layer... */
5084 const double dz = 1e3 * (Z(pct) - Z(pcb));
5085
5086 /* Calculate scavenging coefficient... */
5087 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5088 }
5089 }
5090
5091 /* Calculate exponential decay of mass... */
5092 const double aux = exp(-cache->dt[ip] * lambda);
5093 if (ctl->qnt_m >= 0) {
5094 if (ctl->qnt_mloss_wet >= 0)
5095 atm->q[ctl->qnt_mloss_wet][ip]
5096 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5097 atm->q[ctl->qnt_m][ip] *= aux;
5098 if (ctl->qnt_loss_rate >= 0)
5099 atm->q[ctl->qnt_loss_rate][ip] += lambda;
5100 }
5101 if (ctl->qnt_vmr >= 0)
5102 atm->q[ctl->qnt_vmr][ip] *= aux;
5103 }
5104}
5105
5106/*****************************************************************************/
5107
5109 ctl_t **ctl,
5110 cache_t **cache,
5111 clim_t **clim,
5112 met_t **met0,
5113 met_t **met1,
5114 atm_t **atm,
5115 dd_t **dd) {
5116
5117 /* Initialize GPU... */
5118#ifdef _OPENACC
5119 SELECT_TIMER("ACC_INIT", "INIT", NVTX_GPU);
5120 int rank = 0;
5121#ifdef MPI
5122 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5123#endif
5124 if (acc_get_num_devices(acc_device_nvidia) <= 0)
5125 ERRMSG("Not running on a GPU device!");
5126 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
5127 acc_device_nvidia);
5128 acc_device_t device_type = acc_get_device_type();
5129 acc_init(device_type);
5130#endif
5131
5132 /* Allocate... */
5133 SELECT_TIMER("ALLOC", "MEMORY", NVTX_CPU);
5134 ALLOC(*ctl, ctl_t, 1);
5135 ALLOC(*cache, cache_t, 1);
5136 ALLOC(*clim, clim_t, 1);
5137 ALLOC(*met0, met_t, 1);
5138 ALLOC(*met1, met_t, 1);
5139 ALLOC(*atm, atm_t, 1);
5140 ALLOC(*dd, dd_t, 1);
5141
5142 /* Create data region on GPU... */
5143#ifdef _OPENACC
5144 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY", NVTX_GPU);
5145 ctl_t *ctlup = *ctl;
5146 cache_t *cacheup = *cache;
5147 clim_t *climup = *clim;
5148 met_t *met0up = *met0;
5149 met_t *met1up = *met1;
5150 atm_t *atmup = *atm;
5151#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
5152#ifdef DD
5153 dd_t *ddup = *dd;
5154#pragma acc enter data create(ddup[:1])
5155#endif
5156#endif
5157}
5158
5159/*****************************************************************************/
5160
5162 ctl_t *ctl,
5163 cache_t *cache,
5164 clim_t *clim,
5165 met_t *met0,
5166 met_t *met1,
5167 atm_t *atm,
5168 dd_t *dd) {
5169
5170 /* Delete data region on GPU... */
5171#ifdef _OPENACC
5172 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY", NVTX_GPU);
5173#pragma acc exit data delete (ctl,cache,clim,met0,met1,atm)
5174#endif
5175
5176 /* Free... */
5177 SELECT_TIMER("FREE", "MEMORY", NVTX_CPU);
5178 free(atm);
5179 free(ctl);
5180 free(cache);
5181 free(clim);
5182 free(met0);
5183 free(met1);
5184
5185 /* Free MPI datatype... */
5186#ifdef DD
5187 MPI_Type_free(&dd->MPI_Particle);
5188#endif
5189 free(dd);
5190}
5191
5192/*****************************************************************************/
5193
5195 ctl_t *ctl,
5196 clim_t *clim,
5197 const double t,
5198 met_t **met0,
5199 met_t **met1,
5200 dd_t *dd) {
5201
5202 static int init;
5203
5204 met_t *mets;
5205
5206 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
5207
5208 /* Set timer... */
5209 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5210
5211 /* Init... */
5212 if (t == ctl->t_start || !init) {
5213 init = 1;
5214
5215 /* Read meteo data... */
5216 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
5217 ctl->metbase, ctl->dt_met, filename);
5218 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5219 ERRMSG("Cannot open file!");
5220
5221 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
5222 ctl->metbase, ctl->dt_met, filename);
5223 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5224 ERRMSG("Cannot open file!");
5225
5226 /* Update GPU... */
5227 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
5228 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5229
5230 /* Caching... */
5231 if (ctl->met_cache && t != ctl->t_stop) {
5232 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
5233 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
5234 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5235 LOG(1, "Caching: %s", cachefile);
5236 if (system(cmd) != 0)
5237 WARN("Caching command failed!");
5238 }
5239 }
5240
5241 /* Read new data for forward trajectories... */
5242 if (t > (*met1)->time) {
5243
5244 /* Pointer swap... */
5245 mets = *met1;
5246 *met1 = *met0;
5247 *met0 = mets;
5248
5249 /* Read new meteo data... */
5250 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
5251 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5252 ERRMSG("Cannot open file!");
5253
5254 /* Update GPU... */
5255 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
5256 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5257
5258 /* Caching... */
5259 if (ctl->met_cache && t != ctl->t_stop) {
5260 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
5261 cachefile);
5262 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5263 LOG(1, "Caching: %s", cachefile);
5264 if (system(cmd) != 0)
5265 WARN("Caching command failed!");
5266 }
5267 }
5268
5269 /* Read new data for backward trajectories... */
5270 if (t < (*met0)->time) {
5271
5272 /* Pointer swap... */
5273 mets = *met1;
5274 *met1 = *met0;
5275 *met0 = mets;
5276
5277 /* Read new meteo data... */
5278 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
5279 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5280 ERRMSG("Cannot open file!");
5281
5282 /* Update GPU... */
5283 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
5284 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5285
5286 /* Caching... */
5287 if (ctl->met_cache && t != ctl->t_stop) {
5288 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
5289 cachefile);
5290 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5291 LOG(1, "Caching: %s", cachefile);
5292 if (system(cmd) != 0)
5293 WARN("Caching command failed!");
5294 }
5295 }
5296
5297 /* Check that grids are consistent... */
5298 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
5299 if ((*met0)->nx != (*met1)->nx
5300 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
5301 ERRMSG("Meteo grid dimensions do not match!");
5302 for (int ix = 0; ix < (*met0)->nx; ix++)
5303 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
5304 ERRMSG("Meteo grid longitudes do not match!");
5305 for (int iy = 0; iy < (*met0)->ny; iy++)
5306 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
5307 ERRMSG("Meteo grid latitudes do not match!");
5308 for (int ip = 0; ip < (*met0)->np; ip++)
5309 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
5310 ERRMSG("Meteo grid pressure levels do not match!");
5311 }
5312}
5313
5314/*****************************************************************************/
5315
5317 ctl_t *ctl,
5318 cache_t *cache,
5319 clim_t *clim,
5320 atm_t *atm,
5321 const int ntask) {
5322
5323 /* Initialize timesteps... */
5324 module_timesteps_init(ctl, atm);
5325
5326 /* Initialize random number generator... */
5327 module_rng_init(ntask);
5328
5329 /* Update GPU memory... */
5330 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
5331}
5332
5333/*****************************************************************************/
5334
5336 const char *filename,
5337 const ctl_t *ctl,
5338 atm_t *atm) {
5339
5340 int result;
5341
5342 /* Set timer... */
5343 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
5344
5345 /* Init... */
5346 atm->np = 0;
5347
5348 /* Write info... */
5349 LOG(1, "Read atmospheric data: %s", filename);
5350
5351 /* Read ASCII data... */
5352 if (ctl->atm_type == 0)
5353 result = read_atm_asc(filename, ctl, atm);
5354
5355 /* Read binary data... */
5356 else if (ctl->atm_type == 1)
5357 result = read_atm_bin(filename, ctl, atm);
5358
5359 /* Read netCDF data... */
5360 else if (ctl->atm_type == 2)
5361 result = read_atm_nc(filename, ctl, atm);
5362
5363 /* Read CLaMS data... */
5364 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
5365 result = read_atm_clams(filename, ctl, atm);
5366
5367 /* Error... */
5368 else
5369 ERRMSG("Atmospheric data type not supported!");
5370
5371 /* Check result... */
5372 if (result != 1)
5373 return 0;
5374
5375 /* Check number of air parcels... */
5376 if (atm->np < 1)
5377 ERRMSG("Can not read any data!");
5378
5379 /* Write info... */
5380 double mini, maxi;
5381 LOG(2, "Number of particles: %d", atm->np);
5382 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5383 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5384 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5385 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5386 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5387 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5388 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5389 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5390 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5391 for (int iq = 0; iq < ctl->nq; iq++) {
5392 char msg[5 * LEN];
5393 sprintf(msg, "Quantity %s range: %s ... %s %s",
5394 ctl->qnt_name[iq], ctl->qnt_format[iq],
5395 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5396 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5397 LOG(2, msg, mini, maxi);
5398 }
5399
5400 /* Return success... */
5401 return 1;
5402}
5403
5404/*****************************************************************************/
5405
5407 const ctl_t *ctl,
5408 clim_t *clim) {
5409
5410 /* Set timer... */
5411 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
5412
5413 /* Init tropopause climatology... */
5414 clim_tropo_init(clim);
5415
5416 /* Read photolysis rates... */
5417 if (ctl->clim_photo[0] != '-')
5418 read_clim_photo(ctl->clim_photo, &clim->photo);
5419
5420 /* Read HNO3 climatology... */
5421 if (ctl->clim_hno3_filename[0] != '-')
5422 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
5423
5424 /* Read OH climatology... */
5425 if (ctl->clim_oh_filename[0] != '-') {
5426 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
5427 if (ctl->oh_chem_beta > 0)
5428 clim_oh_diurnal_correction(ctl, clim);
5429 }
5430
5431 /* Read H2O2 climatology... */
5432 if (ctl->clim_h2o2_filename[0] != '-')
5433 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
5434
5435 /* Read HO2 climatology... */
5436 if (ctl->clim_ho2_filename[0] != '-')
5437 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
5438
5439 /* Read O(1D) climatology... */
5440 if (ctl->clim_o1d_filename[0] != '-')
5441 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
5442
5443 /* Read CFC-10 time series... */
5444 if (ctl->clim_ccl4_timeseries[0] != '-')
5446
5447 /* Read CFC-11 time series... */
5448 if (ctl->clim_ccl3f_timeseries[0] != '-')
5450
5451 /* Read CFC-12 time series... */
5452 if (ctl->clim_ccl2f2_timeseries[0] != '-')
5454
5455 /* Read N2O time series... */
5456 if (ctl->clim_n2o_timeseries[0] != '-')
5457 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
5458
5459 /* Read SF6 time series... */
5460 if (ctl->clim_sf6_timeseries[0] != '-')
5461 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
5462}
5463
5464/*****************************************************************************/
5465
5467 const char *filename,
5468 int argc,
5469 char *argv[],
5470 ctl_t *ctl) {
5471
5472 /* Set timer... */
5473 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
5474
5475 /* Write info... */
5476 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
5477 "(executable: %s | version: %s | compiled: %s, %s)\n",
5478 argv[0], VERSION, __DATE__, __TIME__);
5479
5480 /* Initialize quantity indices... */
5481 ctl->qnt_idx = -1;
5482 ctl->qnt_ens = -1;
5483 ctl->qnt_stat = -1;
5484 ctl->qnt_m = -1;
5485 ctl->qnt_vmr = -1;
5486 ctl->qnt_rp = -1;
5487 ctl->qnt_rhop = -1;
5488 ctl->qnt_ps = -1;
5489 ctl->qnt_ts = -1;
5490 ctl->qnt_zs = -1;
5491 ctl->qnt_us = -1;
5492 ctl->qnt_vs = -1;
5493 ctl->qnt_ess = -1;
5494 ctl->qnt_nss = -1;
5495 ctl->qnt_shf = -1;
5496 ctl->qnt_lsm = -1;
5497 ctl->qnt_sst = -1;
5498 ctl->qnt_pbl = -1;
5499 ctl->qnt_pt = -1;
5500 ctl->qnt_tt = -1;
5501 ctl->qnt_zt = -1;
5502 ctl->qnt_h2ot = -1;
5503 ctl->qnt_zg = -1;
5504 ctl->qnt_p = -1;
5505 ctl->qnt_t = -1;
5506 ctl->qnt_rho = -1;
5507 ctl->qnt_u = -1;
5508 ctl->qnt_v = -1;
5509 ctl->qnt_w = -1;
5510 ctl->qnt_h2o = -1;
5511 ctl->qnt_o3 = -1;
5512 ctl->qnt_lwc = -1;
5513 ctl->qnt_rwc = -1;
5514 ctl->qnt_iwc = -1;
5515 ctl->qnt_swc = -1;
5516 ctl->qnt_cc = -1;
5517 ctl->qnt_pct = -1;
5518 ctl->qnt_pcb = -1;
5519 ctl->qnt_cl = -1;
5520 ctl->qnt_plcl = -1;
5521 ctl->qnt_plfc = -1;
5522 ctl->qnt_pel = -1;
5523 ctl->qnt_cape = -1;
5524 ctl->qnt_cin = -1;
5525 ctl->qnt_o3c = -1;
5526 ctl->qnt_hno3 = -1;
5527 ctl->qnt_oh = -1;
5528 ctl->qnt_h2o2 = -1;
5529 ctl->qnt_ho2 = -1;
5530 ctl->qnt_o1d = -1;
5531 ctl->qnt_mloss_oh = -1;
5532 ctl->qnt_mloss_h2o2 = -1;
5533 ctl->qnt_mloss_kpp = -1;
5534 ctl->qnt_mloss_wet = -1;
5535 ctl->qnt_mloss_dry = -1;
5536 ctl->qnt_mloss_decay = -1;
5537 ctl->qnt_loss_rate = -1;
5538 ctl->qnt_psat = -1;
5539 ctl->qnt_psice = -1;
5540 ctl->qnt_pw = -1;
5541 ctl->qnt_sh = -1;
5542 ctl->qnt_rh = -1;
5543 ctl->qnt_rhice = -1;
5544 ctl->qnt_theta = -1;
5545 ctl->qnt_zeta = -1;
5546 ctl->qnt_zeta_d = -1;
5547 ctl->qnt_zeta_dot = -1;
5548 ctl->qnt_eta = -1;
5549 ctl->qnt_eta_dot = -1;
5550 ctl->qnt_tvirt = -1;
5551 ctl->qnt_lapse = -1;
5552 ctl->qnt_vh = -1;
5553 ctl->qnt_vz = -1;
5554 ctl->qnt_pv = -1;
5555 ctl->qnt_tdew = -1;
5556 ctl->qnt_tice = -1;
5557 ctl->qnt_tsts = -1;
5558 ctl->qnt_tnat = -1;
5559 ctl->qnt_Cx = -1;
5560 ctl->qnt_Ch2o = -1;
5561 ctl->qnt_Co3 = -1;
5562 ctl->qnt_Cco = -1;
5563 ctl->qnt_Coh = -1;
5564 ctl->qnt_Ch = -1;
5565 ctl->qnt_Cho2 = -1;
5566 ctl->qnt_Ch2o2 = -1;
5567 ctl->qnt_Co1d = -1;
5568 ctl->qnt_Co3p = -1;
5569 ctl->qnt_Cccl4 = -1;
5570 ctl->qnt_Cccl3f = -1;
5571 ctl->qnt_Cccl2f2 = -1;
5572 ctl->qnt_Cn2o = -1;
5573 ctl->qnt_Csf6 = -1;
5574 ctl->qnt_aoa = -1;
5575
5576#ifdef DD
5577 ctl->qnt_destination = -1;
5578 ctl->qnt_subdomain = -1;
5579#endif
5580
5581 /* Read quantities... */
5582 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
5583 if (ctl->nq > NQ)
5584 ERRMSG("Too many quantities!");
5585 for (int iq = 0; iq < ctl->nq; iq++) {
5586
5587 /* Read quantity name and format... */
5588 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
5589 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
5590 ctl->qnt_longname[iq]);
5591 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
5592 ctl->qnt_format[iq]);
5593 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
5594 sprintf(ctl->qnt_format[iq], "%%.2f");
5595
5596 /* Try to identify quantity... */
5597 SET_QNT(qnt_idx, "idx", "particle index", "-")
5598 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
5599 SET_QNT(qnt_stat, "stat", "station flag", "-")
5600 SET_QNT(qnt_m, "m", "mass", "kg")
5601 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
5602 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
5603 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
5604 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
5605 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
5606 SET_QNT(qnt_zs, "zs", "surface height", "km")
5607 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
5608 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
5609 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
5610 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
5611 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
5612 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
5613 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
5614 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
5615 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
5616 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
5617 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
5618 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
5619 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
5620 SET_QNT(qnt_p, "p", "pressure", "hPa")
5621 SET_QNT(qnt_t, "t", "temperature", "K")
5622 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
5623 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
5624 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
5625 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
5626 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
5627 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
5628 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
5629 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
5630 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
5631 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
5632 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
5633 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
5634 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
5635 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
5636 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
5637 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
5638 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
5639 SET_QNT(qnt_cape, "cape", "convective available potential energy",
5640 "J/kg")
5641 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
5642 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
5643 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
5644 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
5645 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
5646 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
5647 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
5648 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
5649 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
5650 "mass loss due to H2O2 chemistry", "kg")
5651 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
5652 "kg")
5653 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
5654 "kg")
5655 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
5656 "kg")
5657 SET_QNT(qnt_mloss_decay, "mloss_decay",
5658 "mass loss due to exponential decay", "kg")
5659 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
5660 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
5661 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
5662 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
5663 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
5664 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
5665 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
5666 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
5667 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
5668 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
5669 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
5670 "K/day")
5671 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
5672 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
5673 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
5674 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
5675 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
5676 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
5677 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
5678 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
5679 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
5680 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
5681 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
5682 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
5683 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
5684 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
5685 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
5686 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
5687 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
5688 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
5689 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
5690 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
5691 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
5692 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
5693 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
5694 "ppv")
5695 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
5696 "ppv")
5697 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
5698 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
5699 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
5700#ifdef DD
5701 SET_QNT(qnt_destination, "destination",
5702 "subdomain index of destination", "-")
5703 SET_QNT(qnt_subdomain, "subdomain", "current subdomain index", "-")
5704#endif
5705 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
5706 }
5707
5708 /* Vertical coordinate and velocity... */
5709 ctl->advect_vert_coord =
5710 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
5711 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
5712 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
5713
5714 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
5715 ERRMSG("Add quantity zeta for diabatic advection!");
5716 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
5717 ERRMSG("Add quantity eta for etadot avection!");
5718
5719 ctl->met_vert_coord =
5720 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
5721 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
5722 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
5723
5724 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
5725 ERRMSG
5726 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
5727 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
5728 ERRMSG
5729 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
5730
5731 /* Time steps of simulation... */
5732 ctl->direction =
5733 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
5734 if (ctl->direction != -1 && ctl->direction != 1)
5735 ERRMSG("Set DIRECTION to -1 or 1!");
5736 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
5737 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
5738
5739 /* Meteo data... */
5740 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
5741 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
5742 ctl->met_convention =
5743 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
5744 ctl->met_type =
5745 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
5746 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
5747 ERRMSG
5748 ("Please use meteo files in netcdf format for diabatic calculations.");
5749 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
5750 ERRMSG
5751 ("Please use meteo files in netcdf format for etadot calculations.");
5752 ctl->met_clams =
5753 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
5754 ctl->met_nc_scale =
5755 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
5756 ctl->met_nc_level =
5757 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
5758 ctl->met_nc_quant =
5759 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
5760 ctl->met_zstd_level =
5761 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
5762 for (int i = 0; i < METVAR; i++) {
5763 char defprec[LEN] = "0", deftol[LEN] = "0.0";
5764 if (i == 0) /* geopotential height */
5765 sprintf(deftol, "0.5");
5766 else if (i == 1) /* temperature */
5767 sprintf(deftol, "5.0");
5768 else /* other variables */
5769 sprintf(defprec, "8");
5770 ctl->met_comp_prec[i] =
5771 (int) scan_ctl(filename, argc, argv, "MET_COMP_PREC", i, defprec, NULL);
5772 ctl->met_comp_tol[i] =
5773 scan_ctl(filename, argc, argv, "MET_COMP_TOL", i, deftol, NULL);
5774 }
5775 ctl->met_cms_batch =
5776 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
5777 ctl->met_cms_zstd =
5778 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
5779 ctl->met_cms_heur =
5780 (int) scan_ctl(filename, argc, argv, "MET_CMS_HEUR", -1, "1", NULL);
5781 ctl->met_cms_eps_z =
5782 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
5783 ctl->met_cms_eps_t =
5784 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
5785 ctl->met_cms_eps_u =
5786 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
5787 ctl->met_cms_eps_v =
5788 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
5789 ctl->met_cms_eps_w =
5790 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
5791 ctl->met_cms_eps_pv =
5792 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
5793 ctl->met_cms_eps_h2o =
5794 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
5795 ctl->met_cms_eps_o3 =
5796 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
5797 ctl->met_cms_eps_lwc =
5798 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
5799 ctl->met_cms_eps_rwc =
5800 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
5801 ctl->met_cms_eps_iwc =
5802 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
5803 ctl->met_cms_eps_swc =
5804 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
5805 ctl->met_cms_eps_cc =
5806 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
5807 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
5808 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
5809 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
5810 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
5811 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
5812 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
5813 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
5814 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
5815 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
5816 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
5817 ctl->met_detrend =
5818 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
5819 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
5820 if (ctl->met_np > EP)
5821 ERRMSG("Too many pressure levels!");
5822 ctl->met_press_level_def =
5823 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
5824 NULL);
5825 if (ctl->met_press_level_def >= 0) {
5826 level_definitions(ctl);
5827 } else {
5828 if (ctl->met_np > 0) {
5829 for (int ip = 0; ip < ctl->met_np; ip++)
5830 ctl->met_p[ip] =
5831 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
5832 }
5833 }
5834 ctl->met_nlev =
5835 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
5836 if (ctl->met_nlev > EP)
5837 ERRMSG("Too many model levels!");
5838 for (int ip = 0; ip < ctl->met_nlev; ip++)
5839 ctl->met_lev_hyam[ip] =
5840 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
5841 for (int ip = 0; ip < ctl->met_nlev; ip++)
5842 ctl->met_lev_hybm[ip] =
5843 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
5844 ctl->met_geopot_sx =
5845 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
5846 ctl->met_geopot_sy =
5847 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
5848 ctl->met_relhum =
5849 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
5850 ctl->met_cape =
5851 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
5852 if (ctl->met_cape < 0 || ctl->met_cape > 1)
5853 ERRMSG("Set MET_CAPE to 0 or 1!");
5854 ctl->met_pbl =
5855 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
5856 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
5857 ERRMSG("Set MET_PBL to 0 ... 3!");
5858 ctl->met_pbl_min =
5859 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
5860 ctl->met_pbl_max =
5861 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
5862 ctl->met_tropo =
5863 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
5864 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
5865 ERRMSG("Set MET_TROPO to 0 ... 5!");
5866 ctl->met_tropo_pv =
5867 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
5868 ctl->met_tropo_theta =
5869 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
5870 ctl->met_tropo_spline =
5871 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
5872 ctl->met_dt_out =
5873 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
5874 ctl->met_cache =
5875 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
5876 ctl->met_mpi_share =
5877 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
5878
5879 /* Sorting... */
5880 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
5881
5882 /* Isosurface parameters... */
5883 ctl->isosurf =
5884 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
5885 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
5886
5887 /* Random number generator... */
5888 ctl->rng_type =
5889 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
5890 if (ctl->rng_type < 0 || ctl->rng_type > 2)
5891 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
5892
5893 /* Advection parameters... */
5894 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
5895 if (!
5896 (ctl->advect == 0 || ctl->advect == 1 || ctl->advect == 2
5897 || ctl->advect == 4))
5898 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
5899
5900 /* Diffusion parameters... */
5901 ctl->diffusion
5902 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
5903 if (ctl->diffusion < 0 || ctl->diffusion > 2)
5904 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
5905 ctl->turb_dx_pbl =
5906 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
5907 ctl->turb_dx_trop =
5908 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
5909 ctl->turb_dx_strat =
5910 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
5911 ctl->turb_dz_pbl =
5912 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
5913 ctl->turb_dz_trop =
5914 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
5915 ctl->turb_dz_strat =
5916 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
5917 ctl->turb_mesox =
5918 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
5919 ctl->turb_mesoz =
5920 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5921
5922 /* Convection... */
5923 ctl->conv_mix_pbl
5924 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
5925 ctl->conv_pbl_trans
5926 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
5927 ctl->conv_cape
5928 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5929 ctl->conv_cin
5930 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5931 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5932
5933 /* Boundary conditions... */
5934 ctl->bound_mass =
5935 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5936 ctl->bound_mass_trend =
5937 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5938 ctl->bound_vmr =
5939 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5940 ctl->bound_vmr_trend =
5941 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5942 ctl->bound_lat0 =
5943 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5944 ctl->bound_lat1 =
5945 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5946 ctl->bound_p0 =
5947 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5948 ctl->bound_p1 =
5949 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5950 ctl->bound_dps =
5951 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5952 ctl->bound_dzs =
5953 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
5954 ctl->bound_zetas =
5955 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
5956 ctl->bound_pbl =
5957 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
5958
5959 /* Species parameters... */
5960 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
5961 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
5962 ctl->molmass = 120.907;
5963 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
5964 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5965 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5966 ctl->molmass = 137.359;
5967 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5968 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5969 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5970 ctl->molmass = 16.043;
5971 ctl->oh_chem_reaction = 2;
5972 ctl->oh_chem[0] = 2.45e-12;
5973 ctl->oh_chem[1] = 1775;
5974 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5975 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5976 } else if (strcasecmp(ctl->species, "CO") == 0) {
5977 ctl->molmass = 28.01;
5978 ctl->oh_chem_reaction = 3;
5979 ctl->oh_chem[0] = 6.9e-33;
5980 ctl->oh_chem[1] = 2.1;
5981 ctl->oh_chem[2] = 1.1e-12;
5982 ctl->oh_chem[3] = -1.3;
5983 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5984 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5985 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5986 ctl->molmass = 44.009;
5987 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5988 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5989 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5990 ctl->molmass = 18.01528;
5991 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5992 ctl->molmass = 44.013;
5993 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5994 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5995 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5996 ctl->molmass = 17.031;
5997 ctl->oh_chem_reaction = 2;
5998 ctl->oh_chem[0] = 1.7e-12;
5999 ctl->oh_chem[1] = 710;
6000 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
6001 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
6002 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
6003 ctl->molmass = 63.012;
6004 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
6005 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
6006 } else if (strcasecmp(ctl->species, "NO") == 0) {
6007 ctl->molmass = 30.006;
6008 ctl->oh_chem_reaction = 3;
6009 ctl->oh_chem[0] = 7.1e-31;
6010 ctl->oh_chem[1] = 2.6;
6011 ctl->oh_chem[2] = 3.6e-11;
6012 ctl->oh_chem[3] = 0.1;
6013 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
6014 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6015 } else if (strcasecmp(ctl->species, "NO2") == 0) {
6016 ctl->molmass = 46.005;
6017 ctl->oh_chem_reaction = 3;
6018 ctl->oh_chem[0] = 1.8e-30;
6019 ctl->oh_chem[1] = 3.0;
6020 ctl->oh_chem[2] = 2.8e-11;
6021 ctl->oh_chem[3] = 0.0;
6022 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
6023 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6024 } else if (strcasecmp(ctl->species, "O3") == 0) {
6025 ctl->molmass = 47.997;
6026 ctl->oh_chem_reaction = 2;
6027 ctl->oh_chem[0] = 1.7e-12;
6028 ctl->oh_chem[1] = 940;
6029 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
6030 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
6031 } else if (strcasecmp(ctl->species, "SF6") == 0) {
6032 ctl->molmass = 146.048;
6033 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
6034 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
6035 } else if (strcasecmp(ctl->species, "SO2") == 0) {
6036 ctl->molmass = 64.066;
6037 ctl->oh_chem_reaction = 3;
6038 ctl->oh_chem[0] = 2.9e-31;
6039 ctl->oh_chem[1] = 4.1;
6040 ctl->oh_chem[2] = 1.7e-12;
6041 ctl->oh_chem[3] = -0.2;
6042 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
6043 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
6044 }
6045
6046 /* Molar mass... */
6047 char defstr[LEN];
6048 sprintf(defstr, "%g", ctl->molmass);
6049 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
6050
6051 /* OH chemistry... */
6052 sprintf(defstr, "%d", ctl->oh_chem_reaction);
6053 ctl->oh_chem_reaction =
6054 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
6055 NULL);
6056 for (int ip = 0; ip < 4; ip++) {
6057 sprintf(defstr, "%g", ctl->oh_chem[ip]);
6058 ctl->oh_chem[ip] =
6059 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
6060 }
6061 ctl->oh_chem_beta =
6062 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
6063
6064 /* H2O2 chemistry... */
6065 ctl->h2o2_chem_reaction =
6066 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
6067
6068 /* KPP chemistry... */
6069 ctl->kpp_chem =
6070 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
6071 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
6072
6073 /* First order tracer chemistry... */
6074 ctl->tracer_chem =
6075 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
6076
6077 /* Wet deposition... */
6078 for (int ip = 0; ip < 2; ip++) {
6079 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
6080 ctl->wet_depo_ic_h[ip] =
6081 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
6082 }
6083 for (int ip = 0; ip < 1; ip++) {
6084 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
6085 ctl->wet_depo_bc_h[ip] =
6086 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
6087 }
6088 ctl->wet_depo_so2_ph =
6089 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
6090 ctl->wet_depo_ic_a =
6091 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
6092 ctl->wet_depo_ic_b =
6093 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
6094 ctl->wet_depo_bc_a =
6095 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
6096 ctl->wet_depo_bc_b =
6097 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
6098 ctl->wet_depo_pre[0] =
6099 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
6100 ctl->wet_depo_pre[1] =
6101 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
6103 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
6105 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
6106
6107 /* Dry deposition... */
6108 ctl->dry_depo_vdep =
6109 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
6110 ctl->dry_depo_dp =
6111 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
6112
6113 /* Climatological data... */
6114 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
6115 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
6116 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
6117 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
6118 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
6119 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
6120 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
6121 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
6122 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
6123 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
6124 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
6125 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
6126 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
6127 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
6128 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
6129 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
6130 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
6131 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
6132 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
6133 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
6134 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
6135 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
6136
6137 /* Mixing... */
6138 ctl->mixing_dt =
6139 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
6140 ctl->mixing_trop =
6141 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
6142 ctl->mixing_strat =
6143 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
6144 ctl->mixing_z0 =
6145 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
6146 ctl->mixing_z1 =
6147 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
6148 ctl->mixing_nz =
6149 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
6150 ctl->mixing_lon0 =
6151 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
6152 ctl->mixing_lon1 =
6153 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
6154 ctl->mixing_nx =
6155 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
6156 ctl->mixing_lat0 =
6157 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
6158 ctl->mixing_lat1 =
6159 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
6160 ctl->mixing_ny =
6161 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
6162
6163 /* Chemistry grid... */
6164 ctl->chemgrid_z0 =
6165 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
6166 ctl->chemgrid_z1 =
6167 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
6168 ctl->chemgrid_nz =
6169 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
6170 ctl->chemgrid_lon0 =
6171 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
6172 ctl->chemgrid_lon1 =
6173 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
6174 ctl->chemgrid_nx =
6175 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
6176 ctl->chemgrid_lat0 =
6177 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
6178 ctl->chemgrid_lat1 =
6179 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
6180 ctl->chemgrid_ny =
6181 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
6182
6183 /* Exponential decay... */
6184 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
6185 ctl->tdec_strat =
6186 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
6187
6188 /* PSC analysis... */
6189 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
6190 ctl->psc_hno3 =
6191 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
6192
6193 /* Output of atmospheric data... */
6194 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
6195 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
6196 ctl->atm_dt_out =
6197 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
6198 ctl->atm_filter =
6199 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
6200 ctl->atm_stride =
6201 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
6202 ctl->atm_type =
6203 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
6204 ctl->atm_type_out =
6205 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
6206 if (ctl->atm_type_out == -1)
6207 ctl->atm_type_out = ctl->atm_type;
6208 ctl->atm_nc_level =
6209 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
6210 for (int iq = 0; iq < ctl->nq; iq++)
6211 ctl->atm_nc_quant[iq] =
6212 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
6213 ctl->obs_type =
6214 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
6215
6216 /* Output of CSI data... */
6217 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
6218 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
6219 ctl->csi_dt_out =
6220 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
6221 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
6222 ctl->csi_obsmin =
6223 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
6224 ctl->csi_modmin =
6225 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
6226 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
6227 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
6228 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
6229 ctl->csi_lon0 =
6230 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
6231 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
6232 ctl->csi_nx =
6233 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
6234 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
6235 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
6236 ctl->csi_ny =
6237 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
6238
6239 /* Output of ensemble data... */
6240 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
6241 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
6242 ctl->ens_dt_out =
6243 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
6244
6245 /* Output of grid data... */
6246 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
6247 ctl->grid_basename);
6248 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
6249 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
6250 ctl->grid_dt_out =
6251 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
6252 ctl->grid_sparse =
6253 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
6254 ctl->grid_nc_level =
6255 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
6256 for (int iq = 0; iq < ctl->nq; iq++)
6257 ctl->grid_nc_quant[iq] =
6258 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
6259 ctl->grid_stddev =
6260 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
6261 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
6262 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
6263 ctl->grid_nz =
6264 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
6265 ctl->grid_lon0 =
6266 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
6267 ctl->grid_lon1 =
6268 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
6269 ctl->grid_nx =
6270 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
6271 ctl->grid_lat0 =
6272 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
6273 ctl->grid_lat1 =
6274 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
6275 ctl->grid_ny =
6276 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
6277 ctl->grid_type =
6278 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
6279
6280 /* Output of profile data... */
6281 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
6282 ctl->prof_basename);
6283 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
6284 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
6285 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
6286 ctl->prof_nz =
6287 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
6288 ctl->prof_lon0 =
6289 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
6290 ctl->prof_lon1 =
6291 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
6292 ctl->prof_nx =
6293 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
6294 ctl->prof_lat0 =
6295 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
6296 ctl->prof_lat1 =
6297 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
6298 ctl->prof_ny =
6299 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
6300
6301 /* Output of sample data... */
6302 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
6303 ctl->sample_basename);
6304 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
6305 ctl->sample_kernel);
6306 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
6307 ctl->sample_obsfile);
6308 ctl->sample_dx =
6309 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
6310 ctl->sample_dz =
6311 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
6312
6313 /* Output of station data... */
6314 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
6315 ctl->stat_basename);
6316 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
6317 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
6318 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
6319 ctl->stat_t0 =
6320 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
6321 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
6322
6323 /* Output of VTK data... */
6324 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
6325 ctl->vtk_dt_out =
6326 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
6327 ctl->vtk_stride =
6328 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
6329 ctl->vtk_scale =
6330 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
6331 ctl->vtk_offset =
6332 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
6333 ctl->vtk_sphere =
6334 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
6335
6336 /* Domain decomposition... */
6337 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
6339 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
6340 (ctl->dd == 1) ? "2" : "1", NULL);
6341 ctl->dd_subdomains_zonal =
6342 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
6343 (ctl->dd == 1) ? "2" : "1", NULL);
6345 ctl->dd = 1;
6346 else if (ctl->dd == 1)
6347 ERRMSG("Please provide zonal and meridional subdomain numbers!")
6348 ctl->dd_nbr_neighbours =
6349 (int) scan_ctl(filename, argc, argv, "DD_NBR_NEIGHBOURS", -1, "8",
6350 NULL);
6351 ctl->dd_halos_size =
6352 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
6353}
6354
6355/*****************************************************************************/
6356
6358 const char *filename,
6359 const ctl_t *ctl,
6360 const clim_t *clim,
6361 met_t *met,
6362 dd_t *dd) {
6363
6364 /* Write info... */
6365 LOG(1, "Read meteo data: %s", filename);
6366
6367 /* Set rank... */
6368 int rank = 0;
6369#ifdef MPI
6370 if (ctl->met_mpi_share)
6371 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
6372#endif
6373
6374 /* Check rank... */
6375 if (!ctl->met_mpi_share || rank == 0) {
6376
6377 /* Read netCDF data... */
6378 if (ctl->met_type == 0) {
6379 if (read_met_nc(filename, ctl, met, dd) != 1)
6380 return 0;
6381 }
6382
6383 /* Read binary data... */
6384 else if ((ctl->met_type >= 1 && ctl->met_type <= 5) || ctl->met_type == 7) {
6385 if (read_met_bin(filename, ctl, met) != 1)
6386 return 0;
6387 }
6388
6389#ifdef ECCODES
6390 /* Read grib data... */
6391 else if (ctl->met_type == 6) {
6392 if (read_met_grib(filename, ctl, met) != 1)
6393 return 0;
6394 }
6395#endif
6396
6397 /* Not implemented... */
6398 else
6399 ERRMSG("MET_TYPE not implemented!");
6400
6401 /* Preprocessing for netCDF and grib files... */
6402 if (ctl->met_type == 0 || ctl->met_type == 6) {
6403
6404 /* Extrapolate data for lower boundary... */
6406
6407 /* Fix polar winds... */
6409
6410 /* Create periodic boundary conditions... */
6411#ifndef DD
6412 read_met_periodic(met);
6413#endif
6414
6415 /* Downsampling... */
6416 read_met_sample(ctl, met);
6417
6418 /* Calculate geopotential heights... */
6419 read_met_geopot(ctl, met);
6420
6421 /* Calculate potential vorticity... */
6422 read_met_pv(met);
6423
6424 /* Calculate boundary layer data... */
6425 read_met_pbl(ctl, met);
6426
6427 /* Calculate tropopause data... */
6428 read_met_tropo(ctl, clim, met);
6429
6430 /* Calculate cloud properties... */
6431 read_met_cloud(met);
6432
6433 /* Calculate convective available potential energy... */
6434 read_met_cape(ctl, clim, met);
6435
6436 /* Calculate total column ozone... */
6437 read_met_ozone(met);
6438
6439 /* Detrending... */
6440 read_met_detrend(ctl, met);
6441
6442 /* Check meteo data and smooth zeta profiles ... */
6443 read_met_monotonize(ctl, met);
6444 }
6445 }
6446
6447 /* Broadcast data via MPI... */
6448#ifdef MPI
6449 if (ctl->met_mpi_share) {
6450
6451 /* Set timer... */
6452 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
6453 LOG(2, "Broadcast data on rank %d...", rank);
6454
6455 /* Broadcast... */
6456 broadcast_large_data(met, sizeof(met_t));
6457 }
6458#endif
6459
6460 /* Return success... */
6461 return 1;
6462}
6463
6464/*****************************************************************************/
6465
6467 ctl_t *ctl,
6468 cache_t *cache,
6469 clim_t *clim,
6470 met_t **met0,
6471 met_t **met1,
6472 atm_t *atm,
6473 double t,
6474 dd_t *dd) {
6475
6476 /* Initialize modules... */
6477 if (t == ctl->t_start) {
6478
6479 /* Initialize isosurface data... */
6480 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6481 module_isosurf_init(ctl, cache, *met0, *met1, atm);
6482
6483 /* Initialize advection... */
6484 module_advect_init(ctl, cache, *met0, *met1, atm);
6485
6486 /* Initialize chemistry... */
6487 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
6488 }
6489
6490 /* Set time steps of air parcels... */
6491 module_timesteps(ctl, cache, *met0, atm, t);
6492
6493 /* Sort particles... */
6494 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
6495 module_sort(ctl, *met0, atm);
6496
6497
6498 /* Check positions (initial)... */
6499 module_position(cache, *met0, *met1, atm);
6500
6501 /* Advection... */
6502 if (ctl->advect > 0)
6503 module_advect(ctl, cache, *met0, *met1, atm);
6504
6505 /* Turbulent diffusion... */
6506 if (ctl->diffusion == 1
6507 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
6508 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
6509 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
6510 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
6511
6512 /* Mesoscale diffusion... */
6513 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
6514 module_diff_meso(ctl, cache, *met0, *met1, atm);
6515
6516 /* Diffusion... */
6517 if (ctl->diffusion == 2)
6518 module_diff_pbl(ctl, cache, *met0, *met1, atm);
6519
6520 /* Convection... */
6521 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
6522 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
6523 module_convection(ctl, cache, *met0, *met1, atm);
6524
6525 /* Sedimentation... */
6526 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
6527 module_sedi(ctl, cache, *met0, *met1, atm);
6528
6529 /* Isosurface... */
6530 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6531 module_isosurf(ctl, cache, *met0, *met1, atm);
6532
6533 /* Check positions (final)... */
6534 module_position(cache, *met0, *met1, atm);
6535
6536 /* Interpolate meteo data... */
6537 if (ctl->met_dt_out > 0
6538 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
6539 module_meteo(ctl, cache, clim, *met0, *met1, atm);
6540
6541 /* Check boundary conditions (initial)... */
6542 if ((ctl->bound_lat0 < ctl->bound_lat1)
6543 && (ctl->bound_p0 > ctl->bound_p1))
6544 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6545
6546 /* Initialize quantity of total loss rate... */
6547 if (ctl->qnt_loss_rate >= 0) {
6548 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
6549 atm->q[ctl->qnt_loss_rate][ip] = 0;
6550 }
6551 }
6552
6553 /* Decay of particle mass... */
6554 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
6555 module_decay(ctl, cache, clim, atm);
6556
6557 /* Interparcel mixing... */
6558 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
6559 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
6560 module_mixing(ctl, clim, atm, t);
6561
6562 /* Calculate the tracer vmr in the chemistry grid... */
6563 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
6564 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
6565 module_chem_grid(ctl, *met0, *met1, atm, t);
6566
6567 /* OH chemistry... */
6568 if (ctl->oh_chem_reaction != 0)
6569 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
6570
6571 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
6572 if (ctl->h2o2_chem_reaction != 0)
6573 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
6574
6575 /* First-order tracer chemistry... */
6576 if (ctl->tracer_chem)
6577 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
6578
6579 /* Domain decomposition... */
6580 if (dd->init) {
6581#ifdef DD
6582 module_dd(ctl, atm, cache, dd, met0);
6583#else
6584 ERRMSG("DD initialized, but model is compiled without DD.")
6585#endif
6586 }
6587
6588 /* KPP chemistry... */
6589 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
6590#ifdef KPP
6591 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
6592#else
6593 ERRMSG("Code was compiled without KPP!");
6594#endif
6595 }
6596
6597 /* Wet deposition... */
6598 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
6599 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
6600 module_wet_depo(ctl, cache, *met0, *met1, atm);
6601
6602 /* Dry deposition... */
6603 if (ctl->dry_depo_vdep > 0)
6604 module_dry_depo(ctl, cache, *met0, *met1, atm);
6605
6606 /* Check boundary conditions (final)... */
6607 if ((ctl->bound_lat0 < ctl->bound_lat1)
6608 && (ctl->bound_p0 > ctl->bound_p1))
6609 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6610}
6611
6612/*****************************************************************************/
6613
6615 const ctl_t *ctl,
6616 const cache_t *cache,
6617 const clim_t *clim,
6618 met_t **met0,
6619 met_t **met1,
6620 const atm_t *atm) {
6621
6622 /* Update GPU... */
6623 if (ctl != NULL) {
6624#ifdef _OPENACC
6625 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6626#pragma acc update device(ctl[:1])
6627#endif
6628 }
6629
6630 if (cache != NULL) {
6631#ifdef _OPENACC
6632 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6633#pragma acc update device(cache[:1])
6634#endif
6635 }
6636
6637 if (clim != NULL) {
6638#ifdef _OPENACC
6639 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6640#pragma acc update device(clim[:1])
6641#endif
6642 }
6643
6644 if (met0 != NULL) {
6645#ifdef _OPENACC
6646 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6647 met_t *met0up = *met0;
6648#pragma acc update device(met0up[:1])
6649#endif
6650 }
6651
6652 if (met1 != NULL) {
6653#ifdef _OPENACC
6654 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6655 met_t *met1up = *met1;
6656#pragma acc update device(met1up[:1])
6657#endif
6658 }
6659
6660 if (atm != NULL) {
6661#ifdef _OPENACC
6662 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6663#pragma acc update device(atm[:1])
6664#endif
6665 }
6666}
6667
6668/*****************************************************************************/
6669
6671 const ctl_t *ctl,
6672 const cache_t *cache,
6673 const clim_t *clim,
6674 met_t **met0,
6675 met_t **met1,
6676 const atm_t *atm) {
6677
6678 /* Update GPU... */
6679 if (ctl != NULL) {
6680#ifdef _OPENACC
6681 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6682#pragma acc update host(ctl[:1])
6683#endif
6684 }
6685
6686 if (cache != NULL) {
6687#ifdef _OPENACC
6688 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6689#pragma acc update host(cache[:1])
6690#endif
6691 }
6692
6693 if (clim != NULL) {
6694#ifdef _OPENACC
6695 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6696#pragma acc update host(clim[:1])
6697#endif
6698 }
6699
6700 if (met0 != NULL) {
6701#ifdef _OPENACC
6702 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6703 met_t *met0up = *met0;
6704#pragma acc update host(met0up[:1])
6705#endif
6706 }
6707
6708 if (met1 != NULL) {
6709#ifdef _OPENACC
6710 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6711 met_t *met1up = *met1;
6712#pragma acc update host(met1up[:1])
6713#endif
6714 }
6715
6716 if (atm != NULL) {
6717#ifdef _OPENACC
6718 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6719#pragma acc update host(atm[:1])
6720#endif
6721 }
6722}
6723
6724/*****************************************************************************/
6725
6727 const char *filename,
6728 const ctl_t *ctl,
6729 const atm_t *atm,
6730 const double t) {
6731
6732 /* Set timer... */
6733 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
6734
6735 /* Write info... */
6736 LOG(1, "Write atmospheric data: %s", filename);
6737
6738 /* Write ASCII data... */
6739 if (ctl->atm_type_out == 0)
6740 write_atm_asc(filename, ctl, atm, t);
6741
6742 /* Write binary data... */
6743 else if (ctl->atm_type_out == 1)
6744 write_atm_bin(filename, ctl, atm);
6745
6746 /* Write netCDF data... */
6747 else if (ctl->atm_type_out == 2)
6748 write_atm_nc(filename, ctl, atm);
6749
6750 /* Write CLaMS trajectory data... */
6751 else if (ctl->atm_type_out == 3)
6752 write_atm_clams_traj(filename, ctl, atm, t);
6753
6754 /* Write CLaMS pos data... */
6755 else if (ctl->atm_type_out == 4)
6756 write_atm_clams(filename, ctl, atm);
6757
6758 /* Error... */
6759 else
6760 ERRMSG("Atmospheric data type not supported!");
6761
6762 /* Write info... */
6763 double mini, maxi;
6764 LOG(2, "Number of particles: %d", atm->np);
6765 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6766 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6767 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6768 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6769 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6770 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6771 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
6772 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6773 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
6774 for (int iq = 0; iq < ctl->nq; iq++) {
6775 char msg[5 * LEN];
6776 sprintf(msg, "Quantity %s range: %s ... %s %s",
6777 ctl->qnt_name[iq], ctl->qnt_format[iq],
6778 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6779 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6780 LOG(2, msg, mini, maxi);
6781 }
6782}
6783
6784/*****************************************************************************/
6785
6787 const char *filename,
6788 const ctl_t *ctl,
6789 met_t *met) {
6790
6791 /* Set timer... */
6792 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
6793
6794 /* Write info... */
6795 LOG(1, "Write meteo data: %s", filename);
6796
6797 /* Check compression flags... */
6798#ifndef ZFP
6799 if (ctl->met_type == 3)
6800 ERRMSG("MPTRAC was compiled without ZFP compression!");
6801#endif
6802#ifndef ZSTD
6803 if (ctl->met_type == 4)
6804 ERRMSG("MPTRAC was compiled without ZSTD compression!");
6805#endif
6806#ifndef CMS
6807 if (ctl->met_type == 5)
6808 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6809#endif
6810#ifndef SZ3
6811 if (ctl->met_type == 7)
6812 ERRMSG("MPTRAC was compiled without SZ3 compression!");
6813#endif
6814
6815 /* Write netCDF data... */
6816 if (ctl->met_type == 0)
6817 write_met_nc(filename, ctl, met);
6818
6819 /* Write binary data... */
6820 else if (ctl->met_type >= 1 && ctl->met_type <= 7)
6821 write_met_bin(filename, ctl, met);
6822
6823 /* Not implemented... */
6824 else
6825 ERRMSG("MET_TYPE not implemented!");
6826}
6827
6828/*****************************************************************************/
6829
6831 const char *dirname,
6832 const ctl_t *ctl,
6833 met_t *met0,
6834 met_t *met1,
6835 atm_t *atm,
6836 const double t) {
6837
6838 char ext[10], filename[2 * LEN];
6839
6840 double r;
6841
6842 int year, mon, day, hour, min, sec;
6843
6844 /* Get time... */
6845 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
6846
6847 /* Update host... */
6848 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
6849 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
6850 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
6851 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
6852 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
6853 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
6854 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
6855
6856 /* Write atmospheric data... */
6857 if (ctl->atm_basename[0] != '-' &&
6858 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
6859 if (ctl->atm_type_out == 0)
6860 sprintf(ext, "tab");
6861 else if (ctl->atm_type_out == 1)
6862 sprintf(ext, "bin");
6863 else if (ctl->atm_type_out == 2)
6864 sprintf(ext, "nc");
6865 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6866 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
6867 mptrac_write_atm(filename, ctl, atm, t);
6868 }
6869
6870 /* Write gridded data... */
6871 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
6872 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6873 dirname, ctl->grid_basename, year, mon, day, hour, min,
6874 ctl->grid_type == 0 ? "tab" : "nc");
6875 write_grid(filename, ctl, met0, met1, atm, t);
6876 }
6877
6878 /* Write CSI data... */
6879 if (ctl->csi_basename[0] != '-') {
6880 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
6881 write_csi(filename, ctl, atm, t);
6882 }
6883
6884 /* Write ensemble data... */
6885 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
6886 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
6887 dirname, ctl->ens_basename, year, mon, day, hour, min);
6888 write_ens(filename, ctl, atm, t);
6889 }
6890
6891 /* Write profile data... */
6892 if (ctl->prof_basename[0] != '-') {
6893 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
6894 write_prof(filename, ctl, met0, met1, atm, t);
6895 }
6896
6897 /* Write sample data... */
6898 if (ctl->sample_basename[0] != '-') {
6899 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
6900 write_sample(filename, ctl, met0, met1, atm, t);
6901 }
6902
6903 /* Write station data... */
6904 if (ctl->stat_basename[0] != '-') {
6905 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
6906 write_station(filename, ctl, atm, t);
6907 }
6908
6909 /* Write VTK data... */
6910 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
6911 static int nvtk;
6912 if (t == ctl->t_start)
6913 nvtk = 0;
6914 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
6915 write_vtk(filename, ctl, atm, t);
6916 }
6917}
6918
6919/*****************************************************************************/
6920
6922 const double p,
6923 const double h2o,
6924 const double hno3) {
6925
6926 /* Check water vapor volume mixing ratio... */
6927 const double h2o_help = MAX(h2o, 0.1e-6);
6928
6929 /* Calculate T_NAT... */
6930 const double p_hno3 = hno3 * p / 1.333224;
6931 const double p_h2o = h2o_help * p / 1.333224;
6932 const double a = 0.009179 - 0.00088 * log10(p_h2o);
6933 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
6934 const double c = -11397.0 / a;
6935 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
6936 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
6937 if (x2 > 0)
6938 tnat = x2;
6939
6940 return tnat;
6941}
6942
6943/*****************************************************************************/
6944
6946 const ctl_t *ctl,
6947 const atm_t *atm,
6948 const int ip,
6949 const double pbl,
6950 const double ps) {
6951
6952 /* Get pressure range... */
6953 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
6954 const double p0 = pbl;
6955
6956 /* Get weighting factor... */
6957 if (atm->p[ip] > p0)
6958 return 1;
6959 else if (atm->p[ip] < p1)
6960 return 0;
6961 else
6962 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
6963}
6964
6965/*****************************************************************************/
6966
6968 const char *filename,
6969 const ctl_t *ctl,
6970 atm_t *atm) {
6971
6972 /* Open file... */
6973 FILE *in;
6974 if (!(in = fopen(filename, "r"))) {
6975 WARN("Cannot open file!");
6976 return 0;
6977 }
6978
6979 /* Read line... */
6980 char line[LEN];
6981 while (fgets(line, LEN, in)) {
6982
6983 /* Read data... */
6984 char *tok;
6985 TOK(line, tok, "%lg", atm->time[atm->np]);
6986 TOK(NULL, tok, "%lg", atm->p[atm->np]);
6987 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
6988 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
6989 for (int iq = 0; iq < ctl->nq; iq++)
6990 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
6991
6992 /* Convert altitude to pressure... */
6993 atm->p[atm->np] = P(atm->p[atm->np]);
6994
6995 /* Increment data point counter... */
6996 if ((++atm->np) > NP)
6997 ERRMSG("Too many data points!");
6998 }
6999
7000 /* Close file... */
7001 fclose(in);
7002
7003 /* Return success... */
7004 return 1;
7005}
7006
7007/*****************************************************************************/
7008
7010 const char *filename,
7011 const ctl_t *ctl,
7012 atm_t *atm) {
7013
7014 /* Open file... */
7015 FILE *in;
7016 if (!(in = fopen(filename, "r")))
7017 return 0;
7018
7019 /* Check version of binary data... */
7020 int version;
7021 FREAD(&version, int,
7022 1,
7023 in);
7024 if (version != 100)
7025 ERRMSG("Wrong version of binary data!");
7026
7027 /* Read data... */
7028 FREAD(&atm->np, int,
7029 1,
7030 in);
7031 FREAD(atm->time, double,
7032 (size_t) atm->np,
7033 in);
7034 FREAD(atm->p, double,
7035 (size_t) atm->np,
7036 in);
7037 FREAD(atm->lon, double,
7038 (size_t) atm->np,
7039 in);
7040 FREAD(atm->lat, double,
7041 (size_t) atm->np,
7042 in);
7043 for (int iq = 0; iq < ctl->nq; iq++)
7044 FREAD(atm->q[iq], double,
7045 (size_t) atm->np,
7046 in);
7047
7048 /* Read final flag... */
7049 int final;
7050 FREAD(&final, int,
7051 1,
7052 in);
7053 if (final != 999)
7054 ERRMSG("Error while reading binary data!");
7055
7056 /* Close file... */
7057 fclose(in);
7058
7059 /* Return success... */
7060 return 1;
7061}
7062
7063/*****************************************************************************/
7064
7066 const char *filename,
7067 const ctl_t *ctl,
7068 atm_t *atm) {
7069
7070 int ncid, varid;
7071
7072 /* Open file... */
7073 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7074 return 0;
7075
7076 /* Get dimensions... */
7077 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
7078
7079 /* Get time... */
7080 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
7081 NC(nc_get_var_double(ncid, varid, atm->time));
7082 } else {
7083 WARN("TIME_INIT not found use time instead!");
7084 double time_init;
7085 NC_GET_DOUBLE("time", &time_init, 1);
7086 for (int ip = 0; ip < atm->np; ip++) {
7087 atm->time[ip] = time_init;
7088 }
7089 }
7090
7091 /* Read zeta coordinate, pressure is optional... */
7092 if (ctl->advect_vert_coord == 1) {
7093 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
7094 NC_GET_DOUBLE("PRESS", atm->p, 0);
7095 }
7096
7097 /* Read pressure, zeta coordinate is optional... */
7098 else {
7099 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
7100 NC(nc_get_var_double(ncid, varid, atm->p));
7101 } else {
7102 WARN("PRESS_INIT not found use PRESS instead!");
7103 nc_inq_varid(ncid, "PRESS", &varid);
7104 NC(nc_get_var_double(ncid, varid, atm->p));
7105 }
7106 }
7107
7108 /* Read further quantities if requested... */
7109 for (int iq = 0; iq < ctl->nq; iq++)
7110 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7111
7112 /* Read longitude and latitude... */
7113 NC_GET_DOUBLE("LON", atm->lon, 1);
7114 NC_GET_DOUBLE("LAT", atm->lat, 1);
7115
7116 /* Close file... */
7117 NC(nc_close(ncid));
7118
7119 /* Return success... */
7120 return 1;
7121}
7122
7123/*****************************************************************************/
7124
7126 const char *filename,
7127 const ctl_t *ctl,
7128 atm_t *atm) {
7129
7130 int ncid, varid;
7131
7132 /* Open file... */
7133 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7134 return 0;
7135
7136 /* Get dimensions... */
7137 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
7138
7139 /* Read geolocations... */
7140 NC_GET_DOUBLE("time", atm->time, 1);
7141 NC_GET_DOUBLE("press", atm->p, 1);
7142 NC_GET_DOUBLE("lon", atm->lon, 1);
7143 NC_GET_DOUBLE("lat", atm->lat, 1);
7144
7145 /* Read variables... */
7146 for (int iq = 0; iq < ctl->nq; iq++)
7147 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7148
7149 /* Close file... */
7150 NC(nc_close(ncid));
7151
7152 /* Return success... */
7153 return 1;
7154}
7155
7156/*****************************************************************************/
7157
7159 const char *filename,
7160 clim_photo_t *photo) {
7161
7162 int ncid, varid;
7163
7164 /* Write info... */
7165 LOG(1, "Read photolysis rates: %s", filename);
7166
7167 /* Open netCDF file... */
7168 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7169 WARN("Photolysis rate data are missing!");
7170 return;
7171 }
7172
7173 /* Read pressure data... */
7174 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
7175 NC_GET_DOUBLE("press", photo->p, 1);
7176 if (photo->p[0] < photo->p[1])
7177 ERRMSG("Pressure data are not descending!");
7178
7179 /* Read total column ozone data... */
7180 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
7181 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
7182 if (photo->o3c[0] > photo->o3c[1])
7183 ERRMSG("Total column ozone data are not ascending!");
7184
7185 /* Read solar zenith angle data... */
7186 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
7187 NC_GET_DOUBLE("sza", photo->sza, 1);
7188 if (photo->sza[0] > photo->sza[1])
7189 ERRMSG("Solar zenith angle data are not ascending!");
7190
7191 /* Read data... */
7192 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
7193 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
7194 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
7195 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
7196 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
7197 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
7198 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
7199 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
7200 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
7201
7202 /* Close netCDF file... */
7203 NC(nc_close(ncid));
7204
7205 /* Write info... */
7206 LOG(2, "Number of pressure levels: %d", photo->np);
7207 LOG(2, "Altitude levels: %g, %g ... %g km",
7208 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
7209 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7210 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
7211 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
7212 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
7213 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
7214 RAD2DEG(photo->sza[photo->nsza - 1]));
7215 LOG(2, "Number of total column ozone values: %d", photo->no3c);
7216 LOG(2, "Total column ozone: %g, %g ... %g DU",
7217 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
7218 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
7219 photo->n2o[0][0][0], photo->n2o[1][0][0],
7220 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7221 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
7222 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
7223 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7224 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
7225 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
7226 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7227 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
7228 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
7229 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7230 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
7231 photo->o2[0][0][0], photo->o2[1][0][0],
7232 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7233 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
7234 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
7235 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7236 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
7237 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
7238 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7239 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
7240 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
7241 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7242 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
7243 photo->h2o[0][0][0], photo->h2o[1][0][0],
7244 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7245}
7246
7247/*****************************************************************************/
7248
7250 const int ncid,
7251 const char *varname,
7252 const clim_photo_t *photo,
7253 double var[CP][CSZA][CO3]) {
7254
7255 /* Allocate... */
7256 double *help;
7257 ALLOC(help, double,
7258 photo->np * photo->nsza * photo->no3c);
7259
7260 /* Read varible... */
7261 int varid;
7262 NC_GET_DOUBLE(varname, help, 1);
7263
7264 /* Copy data... */
7265 for (int ip = 0; ip < photo->np; ip++)
7266 for (int is = 0; is < photo->nsza; is++)
7267 for (int io = 0; io < photo->no3c; io++)
7268 var[ip][is][io] =
7269 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
7270
7271 /* Free... */
7272 free(help);
7273}
7274
7275/*****************************************************************************/
7276
7278 const char *filename,
7279 clim_ts_t *ts) {
7280
7281 /* Write info... */
7282 LOG(1, "Read climatological time series: %s", filename);
7283
7284 /* Open file... */
7285 FILE *in;
7286 if (!(in = fopen(filename, "r"))) {
7287 WARN("Cannot open file!");
7288 return 0;
7289 }
7290
7291 /* Read data... */
7292 char line[LEN];
7293 int nh = 0;
7294 while (fgets(line, LEN, in))
7295 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
7296
7297 /* Convert years to seconds... */
7298 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
7299
7300 /* Check data... */
7301 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
7302 ERRMSG("Time series must be ascending!");
7303
7304 /* Count time steps... */
7305 if ((++nh) >= CTS)
7306 ERRMSG("Too many data points!");
7307 }
7308
7309 /* Close file... */
7310 fclose(in);
7311
7312 /* Check number of data points... */
7313 ts->ntime = nh;
7314 if (nh < 2)
7315 ERRMSG("Not enough data points!");
7316
7317 /* Write info... */
7318 LOG(2, "Number of time steps: %d", ts->ntime);
7319 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
7320 ts->time[nh - 1]);
7321 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
7322 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
7323 (size_t) nh));
7324
7325 /* Exit success... */
7326 return 1;
7327}
7328
7329/*****************************************************************************/
7330
7332 const char *filename,
7333 const char *varname,
7334 clim_zm_t *zm) {
7335
7336 int ncid, varid, it, iy, iz, iz2, nt;
7337
7338 double *help, varmin = 1e99, varmax = -1e99;
7339
7340 /* Write info... */
7341 LOG(1, "Read %s data: %s", varname, filename);
7342
7343 /* Open netCDF file... */
7344 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7345 WARN("%s climatology data are missing!", varname);
7346 return;
7347 }
7348
7349 /* Read pressure data... */
7350 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
7351 NC_GET_DOUBLE("press", zm->p, 1);
7352 if (zm->p[0] < zm->p[1])
7353 ERRMSG("Pressure data are not descending!");
7354
7355 /* Read latitudes... */
7356 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
7357 NC_GET_DOUBLE("lat", zm->lat, 1);
7358 if (zm->lat[0] > zm->lat[1])
7359 ERRMSG("Latitude data are not ascending!");
7360
7361 /* Set time data (for monthly means)... */
7362 zm->ntime = 12;
7363 zm->time[0] = 1209600.00;
7364 zm->time[1] = 3888000.00;
7365 zm->time[2] = 6393600.00;
7366 zm->time[3] = 9072000.00;
7367 zm->time[4] = 11664000.00;
7368 zm->time[5] = 14342400.00;
7369 zm->time[6] = 16934400.00;
7370 zm->time[7] = 19612800.00;
7371 zm->time[8] = 22291200.00;
7372 zm->time[9] = 24883200.00;
7373 zm->time[10] = 27561600.00;
7374 zm->time[11] = 30153600.00;
7375
7376 /* Check number of timesteps... */
7377 NC_INQ_DIM("time", &nt, 12, 12, 1);
7378
7379 /* Read data... */
7380 ALLOC(help, double,
7381 zm->nlat * zm->np * zm->ntime);
7382 NC_GET_DOUBLE(varname, help, 1);
7383 for (it = 0; it < zm->ntime; it++)
7384 for (iz = 0; iz < zm->np; iz++)
7385 for (iy = 0; iy < zm->nlat; iy++)
7386 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
7387 free(help);
7388
7389 /* Fix data gaps... */
7390 for (it = 0; it < zm->ntime; it++)
7391 for (iy = 0; iy < zm->nlat; iy++)
7392 for (iz = 0; iz < zm->np; iz++) {
7393 if (zm->vmr[it][iz][iy] < 0) {
7394 for (iz2 = 0; iz2 < zm->np; iz2++)
7395 if (zm->vmr[it][iz2][iy] >= 0) {
7396 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7397 break;
7398 }
7399 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
7400 if (zm->vmr[it][iz2][iy] >= 0) {
7401 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7402 break;
7403 }
7404 }
7405 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
7406 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
7407 }
7408
7409 /* Close netCDF file... */
7410 NC(nc_close(ncid));
7411
7412 /* Write info... */
7413 LOG(2, "Number of time steps: %d", zm->ntime);
7414 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
7415 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
7416 LOG(2, "Number of pressure levels: %d", zm->np);
7417 LOG(2, "Altitude levels: %g, %g ... %g km",
7418 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
7419 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
7420 zm->p[1], zm->p[zm->np - 1]);
7421 LOG(2, "Number of latitudes: %d", zm->nlat);
7422 LOG(2, "Latitudes: %g, %g ... %g deg",
7423 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
7424 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
7425 varmax);
7426}
7427
7428/*****************************************************************************/
7429
7431 const char *filename,
7432 double kz[EP],
7433 double kw[EP],
7434 int *nk) {
7435
7436 /* Write info... */
7437 LOG(1, "Read kernel function: %s", filename);
7438
7439 /* Open file... */
7440 FILE *in;
7441 if (!(in = fopen(filename, "r")))
7442 ERRMSG("Cannot open file!");
7443
7444 /* Read data... */
7445 char line[LEN];
7446 int n = 0;
7447 while (fgets(line, LEN, in))
7448 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
7449 if (n > 0 && kz[n] < kz[n - 1])
7450 ERRMSG("Height levels must be ascending!");
7451 if ((++n) >= EP)
7452 ERRMSG("Too many height levels!");
7453 }
7454
7455 /* Close file... */
7456 fclose(in);
7457
7458 /* Check number of data points... */
7459 *nk = n;
7460 if (n < 2)
7461 ERRMSG("Not enough height levels!");
7462
7463 /* Normalize kernel function... */
7464 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
7465 for (int iz = 0; iz < n; iz++)
7466 kw[iz] /= kmax;
7467}
7468
7469/*****************************************************************************/
7470
7472 const char *filename,
7473 const ctl_t *ctl,
7474 met_t *met) {
7475
7476 FILE *in;
7477
7478 double r;
7479
7480 int year, mon, day, hour, min, sec;
7481
7482 /* Set timer... */
7483 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
7484
7485 /* Open file... */
7486 if (!(in = fopen(filename, "r"))) {
7487 WARN("Cannot open file!");
7488 return 0;
7489 }
7490
7491 /* Check type of binary data... */
7492 int met_type;
7493 FREAD(&met_type, int,
7494 1,
7495 in);
7496 if (met_type != ctl->met_type)
7497 ERRMSG("Wrong MET_TYPE of binary data!");
7498
7499 /* Check version of binary data... */
7500 int version;
7501 FREAD(&version, int,
7502 1,
7503 in);
7504 if (version != 103)
7505 ERRMSG("Wrong version of binary data!");
7506
7507 /* Read time... */
7508 FREAD(&met->time, double,
7509 1,
7510 in);
7511 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7512 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7513 met->time, year, mon, day, hour, min);
7514 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7515 || day < 1 || day > 31 || hour < 0 || hour > 23)
7516 ERRMSG("Error while reading time!");
7517
7518 /* Read dimensions... */
7519 FREAD(&met->nx, int,
7520 1,
7521 in);
7522 LOG(2, "Number of longitudes: %d", met->nx);
7523 if (met->nx < 2 || met->nx > EX)
7524 ERRMSG("Number of longitudes out of range!");
7525
7526 FREAD(&met->ny, int,
7527 1,
7528 in);
7529 LOG(2, "Number of latitudes: %d", met->ny);
7530 if (met->ny < 2 || met->ny > EY)
7531 ERRMSG("Number of latitudes out of range!");
7532
7533 FREAD(&met->np, int,
7534 1,
7535 in);
7536 LOG(2, "Number of levels: %d", met->np);
7537 if (met->np < 2 || met->np > EP)
7538 ERRMSG("Number of levels out of range!");
7539
7540 /* Read grid... */
7541 FREAD(met->lon, double,
7542 (size_t) met->nx,
7543 in);
7544 LOG(2, "Longitudes: %g, %g ... %g deg",
7545 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7546
7547 FREAD(met->lat, double,
7548 (size_t) met->ny,
7549 in);
7550 LOG(2, "Latitudes: %g, %g ... %g deg",
7551 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7552
7553 FREAD(met->p, double,
7554 (size_t) met->np,
7555 in);
7556 LOG(2, "Altitude levels: %g, %g ... %g km",
7557 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7558 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7559 met->p[0], met->p[1], met->p[met->np - 1]);
7560
7561 /* Read surface data... */
7562 read_met_bin_2d(in, met, met->ps, "PS");
7563 read_met_bin_2d(in, met, met->ts, "TS");
7564 read_met_bin_2d(in, met, met->zs, "ZS");
7565 read_met_bin_2d(in, met, met->us, "US");
7566 read_met_bin_2d(in, met, met->vs, "VS");
7567 read_met_bin_2d(in, met, met->ess, "ESS");
7568 read_met_bin_2d(in, met, met->nss, "NSS");
7569 read_met_bin_2d(in, met, met->shf, "SHF");
7570 read_met_bin_2d(in, met, met->lsm, "LSM");
7571 read_met_bin_2d(in, met, met->sst, "SST");
7572 read_met_bin_2d(in, met, met->pbl, "PBL");
7573 read_met_bin_2d(in, met, met->pt, "PT");
7574 read_met_bin_2d(in, met, met->tt, "TT");
7575 read_met_bin_2d(in, met, met->zt, "ZT");
7576 read_met_bin_2d(in, met, met->h2ot, "H2OT");
7577 read_met_bin_2d(in, met, met->pct, "PCT");
7578 read_met_bin_2d(in, met, met->pcb, "PCB");
7579 read_met_bin_2d(in, met, met->cl, "CL");
7580 read_met_bin_2d(in, met, met->plcl, "PLCL");
7581 read_met_bin_2d(in, met, met->plfc, "PLFC");
7582 read_met_bin_2d(in, met, met->pel, "PEL");
7583 read_met_bin_2d(in, met, met->cape, "CAPE");
7584 read_met_bin_2d(in, met, met->cin, "CIN");
7585 read_met_bin_2d(in, met, met->o3c, "O3C");
7586
7587 /* Read level data... */
7588 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
7589 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
7590 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
7591 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
7592 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
7593 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
7594 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
7595 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
7596 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
7597 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
7598 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
7599 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
7600 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
7601
7602 /* Read final flag... */
7603 int final;
7604 FREAD(&final, int,
7605 1,
7606 in);
7607 if (final != 999)
7608 ERRMSG("Error while reading binary data!");
7609
7610 /* Close file... */
7611 fclose(in);
7612
7613 /* Return success... */
7614 return 1;
7615}
7616
7617/*****************************************************************************/
7618
7620 FILE *in,
7621 const met_t *met,
7622 float var[EX][EY],
7623 const char *varname) {
7624
7625 float *help;
7626
7627 /* Allocate... */
7628 ALLOC(help, float,
7629 EX * EY);
7630
7631 /* Read uncompressed... */
7632 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
7633 FREAD(help, float,
7634 (size_t) (met->nx * met->ny),
7635 in);
7636
7637 /* Copy data... */
7638 for (int ix = 0; ix < met->nx; ix++)
7639 for (int iy = 0; iy < met->ny; iy++)
7640 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
7641
7642 /* Free... */
7643 free(help);
7644}
7645
7646/*****************************************************************************/
7647
7649 FILE *in,
7650 const ctl_t *ctl,
7651 const met_t *met,
7652 float var[EX][EY][EP],
7653 const char *varname,
7654 const float bound_min,
7655 const float bound_max) {
7656
7657 float *help;
7658
7659 /* Allocate... */
7660 ALLOC(help, float,
7661 EX * EY * EP);
7662
7663 /* Read uncompressed data... */
7664 if (ctl->met_type == 1) {
7665 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
7666 FREAD(help, float,
7667 (size_t) (met->nx * met->ny * met->np),
7668 in);
7669 }
7670
7671 /* Read packed data... */
7672 else if (ctl->met_type == 2)
7673 compress_pck(varname, help, (size_t) (met->ny * met->nx),
7674 (size_t) met->np, 1, in);
7675
7676 /* Read ZFP data... */
7677 else if (ctl->met_type == 3) {
7678#ifdef ZFP
7679 int precision;
7680 FREAD(&precision, int,
7681 1,
7682 in);
7683
7684 double tolerance;
7685 FREAD(&tolerance, double,
7686 1,
7687 in);
7688
7689 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
7690 tolerance, 1, in);
7691#else
7692 ERRMSG("MPTRAC was compiled without ZFP compression!");
7693#endif
7694 }
7695
7696 /* Read zstd data... */
7697 else if (ctl->met_type == 4) {
7698#ifdef ZSTD
7699 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
7700 ctl->met_zstd_level, in);
7701#else
7702 ERRMSG("MPTRAC was compiled without ZSTD compression!");
7703#endif
7704 }
7705
7706 /* Read cmultiscale data... */
7707 else if (ctl->met_type == 5) {
7708#ifdef CMS
7709 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
7710 (size_t) met->np, 1, in);
7711#else
7712 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
7713#endif
7714 }
7715
7716 /* Read SZ3 data... */
7717 else if (ctl->met_type == 7) {
7718#ifdef SZ3
7719 int precision;
7720 FREAD(&precision, int,
7721 1,
7722 in);
7723
7724 double tolerance;
7725 FREAD(&tolerance, double,
7726 1,
7727 in);
7728
7729 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
7730 tolerance, 1, in);
7731#else
7732 ERRMSG("MPTRAC was compiled without sz3 compression!");
7733#endif
7734 }
7735
7736 /* Copy data... */
7737#pragma omp parallel for default(shared) collapse(2)
7738 for (int ix = 0; ix < met->nx; ix++)
7739 for (int iy = 0; iy < met->ny; iy++)
7740 for (int ip = 0; ip < met->np; ip++) {
7741 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7742 if (var[ix][iy][ip] < bound_min)
7743 var[ix][iy][ip] = bound_min;
7744 else if (var[ix][iy][ip] > bound_max)
7745 var[ix][iy][ip] = bound_max;
7746 }
7747
7748 /* Free... */
7749 free(help);
7750}
7751
7752/*****************************************************************************/
7753
7755 const ctl_t *ctl,
7756 const clim_t *clim,
7757 met_t *met) {
7758
7759 /* Check parameters... */
7760 if (ctl->met_cape != 1)
7761 return;
7762
7763 /* Set timer... */
7764 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
7765 LOG(2, "Calculate CAPE...");
7766
7767 /* Vertical spacing (about 100 m)... */
7768 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
7769
7770 /* Loop over columns... */
7771#pragma omp parallel for default(shared) collapse(2)
7772 for (int ix = 0; ix < met->nx; ix++)
7773 for (int iy = 0; iy < met->ny; iy++) {
7774
7775 /* Get potential temperature and water vapor at lowest 50 hPa... */
7776 int n = 0;
7777 double h2o = 0, t, theta = 0;
7778 double pbot = MIN(met->ps[ix][iy], met->p[0]);
7779 double ptop = pbot - 50.;
7780 for (int ip = 0; ip < met->np; ip++) {
7781 if (met->p[ip] <= pbot) {
7782 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
7783 h2o += met->h2o[ix][iy][ip];
7784 n++;
7785 }
7786 if (met->p[ip] < ptop && n > 0)
7787 break;
7788 }
7789 theta /= n;
7790 h2o /= n;
7791
7792 /* Cannot compute anything if water vapor is missing... */
7793 met->plcl[ix][iy] = NAN;
7794 met->plfc[ix][iy] = NAN;
7795 met->pel[ix][iy] = NAN;
7796 met->cape[ix][iy] = NAN;
7797 met->cin[ix][iy] = NAN;
7798 if (h2o <= 0)
7799 continue;
7800
7801 /* Find lifted condensation level (LCL)... */
7802 ptop = P(20.);
7803 pbot = met->ps[ix][iy];
7804 do {
7805 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
7806 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
7807 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
7808 ptop = met->plcl[ix][iy];
7809 else
7810 pbot = met->plcl[ix][iy];
7811 } while (pbot - ptop > 0.1);
7812
7813 /* Calculate CIN up to LCL... */
7815 double dcape, dz, h2o_env, t_env;
7816 double p = met->ps[ix][iy];
7817 met->cape[ix][iy] = met->cin[ix][iy] = 0;
7818 do {
7819 dz = dz0 * TVIRT(t, h2o);
7820 p /= pfac;
7821 t = theta / pow(1000. / p, 0.286);
7822 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7823 &t_env, ci, cw, 1);
7824 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7825 &h2o_env, ci, cw, 0);
7826 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7827 TVIRT(t_env, h2o_env) * dz;
7828 if (dcape < 0)
7829 met->cin[ix][iy] += fabsf((float) dcape);
7830 } while (p > met->plcl[ix][iy]);
7831
7832 /* Calculate level of free convection (LFC), equilibrium level (EL),
7833 and convective available potential energy (CAPE)... */
7834 dcape = 0;
7835 p = met->plcl[ix][iy];
7836 t = theta / pow(1000. / p, 0.286);
7837 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
7838 do {
7839 dz = dz0 * TVIRT(t, h2o);
7840 p /= pfac;
7841 t -= lapse_rate(t, h2o) * dz;
7842 double psat = PSAT(t);
7843 h2o = psat / (p - (1. - EPS) * psat);
7844 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7845 &t_env, ci, cw, 1);
7846 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7847 &h2o_env, ci, cw, 0);
7848 double dcape_old = dcape;
7849 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7850 TVIRT(t_env, h2o_env) * dz;
7851 if (dcape > 0) {
7852 met->cape[ix][iy] += (float) dcape;
7853 if (!isfinite(met->plfc[ix][iy]))
7854 met->plfc[ix][iy] = (float) p;
7855 } else if (dcape_old > 0)
7856 met->pel[ix][iy] = (float) p;
7857 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
7858 met->cin[ix][iy] += fabsf((float) dcape);
7859 } while (p > ptop);
7860
7861 /* Check results... */
7862 if (!isfinite(met->plfc[ix][iy]))
7863 met->cin[ix][iy] = NAN;
7864 }
7865}
7866
7867/*****************************************************************************/
7868
7870 met_t *met) {
7871
7872 /* Set timer... */
7873 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
7874 LOG(2, "Calculate cloud data...");
7875
7876 /* Thresholds for cloud detection... */
7877 const double ccmin = 0.01, cwmin = 1e-6;
7878
7879 /* Loop over columns... */
7880#pragma omp parallel for default(shared) collapse(2)
7881 for (int ix = 0; ix < met->nx; ix++)
7882 for (int iy = 0; iy < met->ny; iy++) {
7883
7884 /* Init... */
7885 met->pct[ix][iy] = NAN;
7886 met->pcb[ix][iy] = NAN;
7887 met->cl[ix][iy] = 0;
7888
7889 /* Loop over pressure levels... */
7890 for (int ip = 0; ip < met->np - 1; ip++) {
7891
7892 /* Check pressure... */
7893 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
7894 continue;
7895
7896 /* Check ice water and liquid water content... */
7897 if (met->cc[ix][iy][ip] > ccmin
7898 && (met->lwc[ix][iy][ip] > cwmin
7899 || met->rwc[ix][iy][ip] > cwmin
7900 || met->iwc[ix][iy][ip] > cwmin
7901 || met->swc[ix][iy][ip] > cwmin)) {
7902
7903 /* Get cloud top pressure ... */
7904 met->pct[ix][iy]
7905 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
7906
7907 /* Get cloud bottom pressure ... */
7908 if (!isfinite(met->pcb[ix][iy]))
7909 met->pcb[ix][iy]
7910 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
7911 }
7912
7913 /* Get cloud water... */
7914 met->cl[ix][iy] += (float)
7915 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
7916 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
7917 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
7918 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
7919 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
7920 }
7921 }
7922}
7923
7924/*****************************************************************************/
7925
7927 const ctl_t *ctl,
7928 met_t *met) {
7929
7930 met_t *help;
7931
7932 /* Check parameters... */
7933 if (ctl->met_detrend <= 0)
7934 return;
7935
7936 /* Set timer... */
7937 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
7938 LOG(2, "Detrend meteo data...");
7939
7940 /* Allocate... */
7941 ALLOC(help, met_t, 1);
7942
7943 /* Calculate standard deviation... */
7944 const double sigma = ctl->met_detrend / 2.355;
7945 const double tssq = 2. * SQR(sigma);
7946
7947 /* Calculate box size in latitude... */
7948 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
7949 sy = MIN(MAX(1, sy), met->ny / 2);
7950
7951 /* Calculate background... */
7952#pragma omp parallel for default(shared) collapse(2)
7953 for (int ix = 0; ix < met->nx; ix++) {
7954 for (int iy = 0; iy < met->ny; iy++) {
7955
7956 /* Calculate Cartesian coordinates... */
7957 double x0[3];
7958 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
7959
7960 /* Calculate box size in longitude... */
7961 int sx =
7962 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
7963 fabs(met->lon[1] - met->lon[0]));
7964 sx = MIN(MAX(1, sx), met->nx / 2);
7965
7966 /* Init... */
7967 float wsum = 0;
7968 for (int ip = 0; ip < met->np; ip++) {
7969 help->t[ix][iy][ip] = 0;
7970 help->u[ix][iy][ip] = 0;
7971 help->v[ix][iy][ip] = 0;
7972 help->w[ix][iy][ip] = 0;
7973 }
7974
7975 /* Loop over neighboring grid points... */
7976 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
7977 int ix3 = ix2;
7978 if (ix3 < 0)
7979 ix3 += met->nx;
7980 else if (ix3 >= met->nx)
7981 ix3 -= met->nx;
7982 for (int iy2 = MAX(iy - sy, 0);
7983 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
7984
7985 /* Calculate Cartesian coordinates... */
7986 double x1[3];
7987 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
7988
7989 /* Calculate weighting factor... */
7990 const float w = (float) exp(-DIST2(x0, x1) / tssq);
7991
7992 /* Add data... */
7993 wsum += w;
7994 for (int ip = 0; ip < met->np; ip++) {
7995 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
7996 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
7997 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
7998 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
7999 }
8000 }
8001 }
8002
8003 /* Normalize... */
8004 for (int ip = 0; ip < met->np; ip++) {
8005 help->t[ix][iy][ip] /= wsum;
8006 help->u[ix][iy][ip] /= wsum;
8007 help->v[ix][iy][ip] /= wsum;
8008 help->w[ix][iy][ip] /= wsum;
8009 }
8010 }
8011 }
8012
8013 /* Subtract background... */
8014#pragma omp parallel for default(shared) collapse(3)
8015 for (int ix = 0; ix < met->nx; ix++)
8016 for (int iy = 0; iy < met->ny; iy++)
8017 for (int ip = 0; ip < met->np; ip++) {
8018 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
8019 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
8020 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
8021 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
8022 }
8023
8024 /* Free... */
8025 free(help);
8026}
8027
8028/*****************************************************************************/
8029
8031 met_t *met) {
8032
8033 /* Set timer... */
8034 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
8035 LOG(2, "Extrapolate meteo data...");
8036
8037 /* Loop over columns... */
8038#pragma omp parallel for default(shared) collapse(2)
8039 for (int ix = 0; ix < met->nx; ix++)
8040 for (int iy = 0; iy < met->ny; iy++) {
8041
8042 /* Find lowest valid data point... */
8043 int ip0;
8044 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
8045 if (!isfinite(met->t[ix][iy][ip0])
8046 || !isfinite(met->u[ix][iy][ip0])
8047 || !isfinite(met->v[ix][iy][ip0])
8048 || !isfinite(met->w[ix][iy][ip0]))
8049 break;
8050
8051 /* Extrapolate... */
8052 for (int ip = ip0; ip >= 0; ip--) {
8053 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
8054 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
8055 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
8056 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
8057 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
8058 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
8059 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
8060 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
8061 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
8062 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
8063 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
8064 }
8065 }
8066}
8067
8068/*****************************************************************************/
8069
8071 const ctl_t *ctl,
8072 met_t *met) {
8073
8074 float *help;
8075
8076 double logp[EP];
8077
8078 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
8079
8080 /* Set timer... */
8081 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
8082 LOG(2, "Calculate geopotential heights...");
8083
8084 /* Allocate... */
8085 ALLOC(help, float,
8086 EX * EY * EP);
8087
8088 /* Calculate log pressure... */
8089#pragma omp parallel for default(shared)
8090 for (int ip = 0; ip < met->np; ip++)
8091 logp[ip] = log(met->p[ip]);
8092
8093 /* Apply hydrostatic equation to calculate geopotential heights... */
8094#pragma omp parallel for default(shared) collapse(2)
8095 for (int ix = 0; ix < met->nx; ix++)
8096 for (int iy = 0; iy < met->ny; iy++) {
8097
8098 /* Get surface height and pressure... */
8099 const double zs = met->zs[ix][iy];
8100 const double lnps = log(met->ps[ix][iy]);
8101
8102 /* Get temperature and water vapor at the surface... */
8103 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
8104 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
8105 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
8106 const double h2os =
8107 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
8108 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
8109
8110 /* Upper part of profile... */
8111 met->z[ix][iy][ip0 + 1]
8112 = (float) (zs +
8113 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
8114 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
8115 for (int ip = ip0 + 2; ip < met->np; ip++)
8116 met->z[ix][iy][ip]
8117 = (float) (met->z[ix][iy][ip - 1] +
8118 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
8119 met->h2o[ix][iy][ip - 1], logp[ip],
8120 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8121
8122 /* Lower part of profile... */
8123 met->z[ix][iy][ip0]
8124 = (float) (zs +
8125 ZDIFF(lnps, ts, h2os, logp[ip0],
8126 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
8127 for (int ip = ip0 - 1; ip >= 0; ip--)
8128 met->z[ix][iy][ip]
8129 = (float) (met->z[ix][iy][ip + 1] +
8130 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
8131 met->h2o[ix][iy][ip + 1], logp[ip],
8132 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8133 }
8134
8135 /* Check control parameters... */
8136 if (dx == 0 || dy == 0)
8137 return;
8138
8139 /* Default smoothing parameters... */
8140 if (dx < 0 || dy < 0) {
8141 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
8142 dx = 3;
8143 dy = 2;
8144 } else {
8145 dx = 6;
8146 dy = 4;
8147 }
8148 }
8149
8150 /* Calculate weights for smoothing... */
8151 float ws[dx + 1][dy + 1];
8152#pragma omp parallel for default(shared) collapse(2)
8153 for (int ix = 0; ix <= dx; ix++)
8154 for (int iy = 0; iy < dy; iy++)
8155 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
8156 * (1.0f - (float) iy / (float) dy);
8157
8158 /* Copy data... */
8159#pragma omp parallel for default(shared) collapse(3)
8160 for (int ix = 0; ix < met->nx; ix++)
8161 for (int iy = 0; iy < met->ny; iy++)
8162 for (int ip = 0; ip < met->np; ip++)
8163 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
8164
8165 /* Horizontal smoothing... */
8166#pragma omp parallel for default(shared) collapse(3)
8167 for (int ip = 0; ip < met->np; ip++)
8168 for (int ix = 0; ix < met->nx; ix++)
8169 for (int iy = 0; iy < met->ny; iy++) {
8170 float res = 0, wsum = 0;
8171 int iy0 = MAX(iy - dy + 1, 0);
8172 int iy1 = MIN(iy + dy - 1, met->ny - 1);
8173 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
8174 int ix3 = ix2;
8175 if (ix3 < 0)
8176 ix3 += met->nx;
8177 else if (ix3 >= met->nx)
8178 ix3 -= met->nx;
8179 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
8180 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
8181 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
8182 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
8183 wsum += w;
8184 }
8185 }
8186 if (wsum > 0)
8187 met->z[ix][iy][ip] = res / wsum;
8188 else
8189 met->z[ix][iy][ip] = NAN;
8190 }
8191
8192 /* Free... */
8193 free(help);
8194}
8195
8196/*****************************************************************************/
8197
8199 const char *filename,
8200 const int ncid,
8201 const ctl_t *ctl,
8202 met_t *met,
8203 dd_t *dd) {
8204
8205 char levname[LEN], tstr[10];
8206
8207 double rtime = 0, r, r2;
8208
8209 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
8210 year, mon, day, hour, min, sec;
8211
8212 size_t dimlen;
8213
8214 /* Set timer... */
8215 SELECT_TIMER("READ_MET_NC_GRID", "INPUT", NVTX_READ);
8216 LOG(2, "Read meteo grid information...");
8217
8218 /* MPTRAC meteo files... */
8219 if (!ctl->met_clams) {
8220
8221 /* Get time from filename... */
8222 met->time = time_from_filename(filename, 16);
8223
8224 /* Check time information from data file... */
8225 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8226 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
8227 NC(nc_get_var_double(ncid, varid, &rtime));
8228 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
8229 WARN("Time information in meteo file does not match filename!");
8230 } else
8231 WARN("Time information in meteo file is missing!");
8232 }
8233
8234 /* CLaMS meteo files... */
8235 else {
8236
8237 /* Read time from file... */
8238 NC_GET_DOUBLE("time", &rtime, 0);
8239
8240 /* Get time from filename (considering the century)... */
8241 if (rtime < 0)
8242 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
8243 else
8244 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
8245 year = atoi(tstr);
8246 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
8247 mon = atoi(tstr);
8248 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
8249 day = atoi(tstr);
8250 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
8251 hour = atoi(tstr);
8252 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
8253 }
8254
8255 /* Check time... */
8256 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8257 || day < 1 || day > 31 || hour < 0 || hour > 23)
8258 ERRMSG("Cannot read time from filename!");
8259 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
8260 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8261 met->time, year2, mon2, day2, hour2, min2);
8262
8263 /* Get vertical dimension... */
8264 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
8265 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
8266 ERRMSG
8267 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
8268
8269 NC(nc_inq_varndims(ncid, varid, &ndims));
8270 NC(nc_inq_vardimid(ncid, varid, dimids));
8271
8272 if (ndims == 4) {
8273 NC(nc_inq_dim
8274 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
8275 } else if (ndims == 3) {
8276 NC(nc_inq_dim
8277 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
8278 } else
8279 ERRMSG("Cannot determine vertical dimension!")
8280 met->np = (int) dimlen;
8281
8282 LOG(2, "Number of levels: %d", met->np);
8283 if (met->np < 2 || met->np > EP)
8284 ERRMSG("Number of levels out of range!");
8285
8286 if (!ctl->dd) {
8287
8288 /* Get grid dimensions... */
8289 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
8290 LOG(2, "Number of longitudes: %d", met->nx);
8291
8292 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
8293 LOG(2, "Number of latitudes: %d", met->ny);
8294
8295 /* Read longitudes and latitudes... */
8296 NC_GET_DOUBLE("lon", met->lon, 1);
8297 LOG(2, "Longitudes: %g, %g ... %g deg",
8298 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
8299 NC_GET_DOUBLE("lat", met->lat, 1);
8300 LOG(2, "Latitudes: %g, %g ... %g deg",
8301 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
8302
8303 } else {
8304
8305 /* Use 'naive', i.e. equidistant lat-lon domain decomposition... */
8306 read_met_nc_grid_dd_naive(dd, ctl, met, ncid);
8307
8308 }
8309
8310 /* Read pressure levels... */
8311 if (ctl->met_np <= 0) {
8312 NC_GET_DOUBLE(levname, met->p, 1);
8313 for (int ip = 0; ip < met->np; ip++)
8314 met->p[ip] /= 100.;
8315 LOG(2, "Altitude levels: %g, %g ... %g km",
8316 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
8317 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8318 met->p[0], met->p[1], met->p[met->np - 1]);
8319 }
8320
8321 /* Read hybrid levels... */
8322 if (strcasecmp(levname, "hybrid") == 0)
8323 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
8324
8325 /* Read model level coefficients from file... */
8326 if (ctl->met_vert_coord == 2) {
8327 NC_GET_DOUBLE("hyam", met->hyam, 1);
8328 NC_GET_DOUBLE("hybm", met->hybm, 1);
8329 }
8330
8331 /* Copy model level coefficients from control parameters... */
8332 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
8333 if (ctl->met_nlev <= 0)
8334 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
8335 for (int ip = 0; ip < ctl->met_nlev; ip++) {
8336 met->hyam[ip] = ctl->met_lev_hyam[ip];
8337 met->hybm[ip] = ctl->met_lev_hybm[ip];
8338 }
8339 }
8340
8341 /* Calculate eta levels... */
8342 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
8343 met->eta[k] = met->hyam[k] / 100000.0 + met->hybm[k];
8344 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
8345 ERRMSG("Eta levels must be ascending!");
8346 }
8347
8348 /* Check horizontal grid spacing... */
8349 for (int ix = 2; ix < met->nx; ix++)
8350 if (fabs
8351 (fabs(met->lon[ix] - met->lon[ix - 1]) -
8352 fabs(met->lon[1] - met->lon[0])) > 0.001)
8353 ERRMSG("No regular grid spacing in longitudes!");
8354 for (int iy = 2; iy < met->ny; iy++)
8355 if (fabs
8356 (fabs(met->lat[iy] - met->lat[iy - 1]) -
8357 fabs(met->lat[1] - met->lat[0])) > 0.001) {
8358 WARN("No regular grid spacing in latitudes!");
8359 break;
8360 }
8361}
8362
8363/*****************************************************************************/
8364
8366 const int ncid,
8367 const ctl_t *ctl,
8368 met_t *met,
8369 dd_t *dd) {
8370
8371 /* Set timer... */
8372 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
8373 LOG(2, "Read surface data...");
8374
8375 /* Read surface pressure... */
8376 if (read_met_nc_2d
8377 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
8378 1.0f, 1)) {
8379 for (int ix = 0; ix < met->nx; ix++)
8380 for (int iy = 0; iy < met->ny; iy++)
8381 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8382 } else
8383 if (!read_met_nc_2d
8384 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
8385 0.01f, 1)) {
8386 WARN("Cannot not read surface pressure data (use lowest level)!");
8387 for (int ix = 0; ix < met->nx; ix++)
8388 for (int iy = 0; iy < met->ny; iy++)
8389 met->ps[ix][iy]
8390 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
8391 }
8392
8393 /* MPTRAC meteo data... */
8394 if (ctl->met_clams == 0) {
8395
8396 /* Read geopotential height at the surface... */
8397 if (!read_met_nc_2d
8398 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8399 (float) (1. / (1000. * G0)), 1))
8400 if (!read_met_nc_2d
8401 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8402 (float) (1. / 1000.), 1))
8403 WARN("Cannot read surface geopotential height!");
8404 }
8405
8406 /* CLaMS meteo data... */
8407 else {
8408
8409 /* Read geopotential height at the surface
8410 (use lowermost level of 3-D data field)... */
8411 float *help;
8412 ALLOC(help, float,
8413 EX * EY * EP);
8414 memcpy(help, met->pl, sizeof(met->pl));
8415 if (!read_met_nc_3d
8416 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
8417 (float) (1e-3 / G0)))
8418 ERRMSG("Cannot read geopotential height!");
8419 for (int ix = 0; ix < met->nx; ix++)
8420 for (int iy = 0; iy < met->ny; iy++)
8421 met->zs[ix][iy] = met->pl[ix][iy][0];
8422 memcpy(met->pl, help, sizeof(met->pl));
8423 free(help);
8424 }
8425
8426 /* Read temperature at the surface... */
8427 if (!read_met_nc_2d
8428 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
8429 1))
8430 WARN("Cannot read surface temperature!");
8431
8432 /* Read zonal wind at the surface... */
8433 if (!read_met_nc_2d
8434 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
8435 met->us, 1.0, 1))
8436 WARN("Cannot read surface zonal wind!");
8437
8438 /* Read meridional wind at the surface... */
8439 if (!read_met_nc_2d
8440 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
8441 met->vs, 1.0, 1))
8442 WARN("Cannot read surface meridional wind!");
8443
8444 /* Read eastward turbulent surface stress... */
8445 if (!read_met_nc_2d
8446 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
8447 1.0, 1))
8448 WARN("Cannot read eastward turbulent surface stress!");
8449
8450 /* Read northward turbulent surface stress... */
8451 if (!read_met_nc_2d
8452 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
8453 1.0, 1))
8454 WARN("Cannot read nothward turbulent surface stress!");
8455
8456 /* Read surface sensible heat flux... */
8457 if (!read_met_nc_2d
8458 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
8459 1.0, 1))
8460 WARN("Cannot read surface sensible heat flux!");
8461
8462 /* Read land-sea mask... */
8463 if (!read_met_nc_2d
8464 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
8465 1.0, 1))
8466 WARN("Cannot read land-sea mask!");
8467
8468 /* Read sea surface temperature... */
8469 if (!read_met_nc_2d
8470 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
8471 1.0, 1))
8472 WARN("Cannot read sea surface temperature!");
8473
8474 /* Read PBL... */
8475 if (ctl->met_pbl == 0)
8476 if (!read_met_nc_2d
8477 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8478 0.01f, 1))
8479 WARN("Cannot read planetary boundary layer pressure!");
8480 if (ctl->met_pbl == 1)
8481 if (!read_met_nc_2d
8482 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8483 0.001f, 1))
8484 WARN("Cannot read planetary boundary layer height!");
8485
8486 /* Read CAPE... */
8487 if (ctl->met_cape == 0)
8488 if (!read_met_nc_2d
8489 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
8490 met->cape, 1.0, 1))
8491 WARN("Cannot read CAPE!");
8492
8493 /* Read CIN... */
8494 if (ctl->met_cape == 0)
8495 if (!read_met_nc_2d
8496 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
8497 1.0, 1))
8498 WARN("Cannot read convective inhibition!");
8499}
8500
8501/*****************************************************************************/
8502
8504 const int ncid,
8505 const ctl_t *ctl,
8506 met_t *met,
8507 dd_t *dd) {
8508
8509 /* Set timer... */
8510 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT", NVTX_READ);
8511 LOG(2, "Read level data...");
8512
8513 /* Read temperature... */
8514 if (!read_met_nc_3d
8515 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
8516 ERRMSG("Cannot read temperature!");
8517
8518 /* Read horizontal wind and vertical velocity... */
8519 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
8520 ERRMSG("Cannot read zonal wind!");
8521 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
8522 ERRMSG("Cannot read meridional wind!");
8523 if (!read_met_nc_3d
8524 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
8525 WARN("Cannot read vertical velocity!");
8526
8527 /* Read water vapor... */
8528 if (!ctl->met_relhum) {
8529 if (!read_met_nc_3d
8530 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
8531 (float) (MA / MH2O)))
8532 WARN("Cannot read specific humidity!");
8533 } else {
8534 if (!read_met_nc_3d
8535 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
8536 WARN("Cannot read relative humidity!");
8537#pragma omp parallel for default(shared) collapse(2)
8538 for (int ix = 0; ix < met->nx; ix++)
8539 for (int iy = 0; iy < met->ny; iy++)
8540 for (int ip = 0; ip < met->np; ip++) {
8541 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
8542 met->h2o[ix][iy][ip] =
8543 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
8544 }
8545 }
8546
8547 /* Read ozone... */
8548 if (!read_met_nc_3d
8549 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
8550 (float) (MA / MO3)))
8551 WARN("Cannot read ozone data!");
8552
8553 /* Read cloud data... */
8554 if (!read_met_nc_3d
8555 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
8556 WARN("Cannot read cloud liquid water content!");
8557 if (!read_met_nc_3d
8558 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
8559 WARN("Cannot read cloud rain water content!");
8560 if (!read_met_nc_3d
8561 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
8562 WARN("Cannot read cloud ice water content!");
8563 if (!read_met_nc_3d
8564 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
8565 WARN("Cannot read cloud snow water content!");
8566 if (!read_met_nc_3d
8567 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
8568 WARN("Cannot read cloud cover!");
8569
8570 /* Read zeta and zeta_dot... */
8571 if (ctl->advect_vert_coord == 1) {
8572 if (!read_met_nc_3d
8573 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
8574 WARN("Cannot read ZETA!");
8575 if (!read_met_nc_3d
8576 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
8577 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
8578 WARN("Cannot read ZETA_DOT!");
8579 }
8580
8581 /* Read eta and eta_dot... */
8582 else if (ctl->advect_vert_coord == 3) {
8583#pragma omp parallel for default(shared)
8584 for (int ix = 0; ix < met->nx; ix++)
8585 for (int iy = 0; iy < met->ny; iy++)
8586 for (int ip = 0; ip < met->np; ip++)
8587 met->zetal[ix][iy][ip] =
8588 (float) (met->hyam[ip] / 100000.0 + met->hybm[ip]);
8589 if (!read_met_nc_3d
8590 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
8591 1.0))
8592 WARN("Cannot read eta vertical velocity!");
8593 }
8594
8595 /* Store velocities on model levels... */
8596 if (ctl->met_vert_coord != 0) {
8597#pragma omp parallel for default(shared)
8598 for (int ix = 0; ix < met->nx; ix++)
8599 for (int iy = 0; iy < met->ny; iy++)
8600 for (int ip = 0; ip < met->np; ip++) {
8601 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
8602 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
8603 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
8604 }
8605
8606 /* Save number of model levels... */
8607 met->npl = met->np;
8608 }
8609
8610 /* Get pressure on model levels... */
8611 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
8612
8613 /* Read 3-D pressure field... */
8614 if (ctl->met_vert_coord == 1) {
8615 if (!read_met_nc_3d
8616 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
8617 0.01f))
8618 if (!read_met_nc_3d
8619 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
8620 ERRMSG("Cannot read pressure on model levels!");
8621 }
8622
8623 /* Use a and b coefficients for full levels (at layer midpoints)... */
8624 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
8625
8626 /* Check number of levels... */
8627 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
8628 ERRMSG("Mismatch in number of model levels!");
8629
8630 /* Calculate pressure... */
8631 for (int ix = 0; ix < met->nx; ix++)
8632 for (int iy = 0; iy < met->ny; iy++)
8633 for (int ip = 0; ip < met->np; ip++)
8634 met->pl[ix][iy][ip] =
8635 (float) (met->hyam[ip] / 100. +
8636 met->hybm[ip] * met->ps[ix][iy]);
8637 }
8638
8639 /* Use a and b coefficients for half levels (at layer interfaces)... */
8640 else if (ctl->met_vert_coord == 4) {
8641
8642 /* Check number of levels... */
8643 if (met->np + 1 != ctl->met_nlev)
8644 ERRMSG("Mismatch in number of model levels!");
8645
8646 /* Calculate pressure... */
8647#pragma omp parallel for default(shared) collapse(2)
8648 for (int ix = 0; ix < met->nx; ix++)
8649 for (int iy = 0; iy < met->ny; iy++)
8650 for (int ip = 0; ip < met->np; ip++) {
8651 const double p0 =
8652 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
8653 const double p1 =
8654 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
8655 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
8656 }
8657 }
8658
8659 /* Check ordering of pressure levels... */
8660 for (int ix = 0; ix < met->nx; ix++)
8661 for (int iy = 0; iy < met->ny; iy++)
8662 for (int ip = 1; ip < met->np; ip++)
8663 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
8664 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
8665 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
8666 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
8667 ERRMSG("Pressure profiles are not monotonic!");
8668 }
8669
8670 /* Interpolate from model levels to pressure levels... */
8671 if (ctl->met_np > 0) {
8672
8673 /* Interpolate variables... */
8674 read_met_ml2pl(ctl, met, met->t, "T");
8675 read_met_ml2pl(ctl, met, met->u, "U");
8676 read_met_ml2pl(ctl, met, met->v, "V");
8677 read_met_ml2pl(ctl, met, met->w, "W");
8678 read_met_ml2pl(ctl, met, met->h2o, "H2O");
8679 read_met_ml2pl(ctl, met, met->o3, "O3");
8680 read_met_ml2pl(ctl, met, met->lwc, "LWC");
8681 read_met_ml2pl(ctl, met, met->rwc, "RWC");
8682 read_met_ml2pl(ctl, met, met->iwc, "IWC");
8683 read_met_ml2pl(ctl, met, met->swc, "SWC");
8684 read_met_ml2pl(ctl, met, met->cc, "CC");
8685
8686 /* Set new pressure levels... */
8687 met->np = ctl->met_np;
8688 for (int ip = 0; ip < met->np; ip++)
8689 met->p[ip] = ctl->met_p[ip];
8690 }
8691
8692 /* Check ordering of pressure levels... */
8693 for (int ip = 1; ip < met->np; ip++)
8694 if (met->p[ip - 1] < met->p[ip])
8695 ERRMSG("Pressure levels must be descending!");
8696}
8697
8698/*****************************************************************************/
8699
8701 const int ncid,
8702 const char *varname,
8703 const char *varname2,
8704 const char *varname3,
8705 const char *varname4,
8706 const char *varname5,
8707 const char *varname6,
8708 const ctl_t *ctl,
8709 const met_t *met,
8710 dd_t *dd,
8711 float dest[EX][EY],
8712 const float scl,
8713 const int init) {
8714
8715 char varsel[LEN];
8716
8717 float offset, scalfac;
8718
8719 int varid;
8720
8721 /* Check if variable exists... */
8722 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8723 sprintf(varsel, "%s", varname);
8724 else if (varname2 != NULL
8725 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8726 sprintf(varsel, "%s", varname2);
8727 else if (varname3 != NULL
8728 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8729 sprintf(varsel, "%s", varname3);
8730 else if (varname4 != NULL
8731 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8732 sprintf(varsel, "%s", varname4);
8733 else if (varname5 != NULL
8734 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
8735 sprintf(varsel, "%s", varname5);
8736 else if (varname6 != NULL
8737 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
8738 sprintf(varsel, "%s", varname6);
8739 else
8740 return 0;
8741
8742 /* Read packed data... */
8743 if (ctl->met_nc_scale && !ctl->dd
8744 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8745 && nc_get_att_float(ncid, varid, "scale_factor",
8746 &scalfac) == NC_NOERR) {
8747
8748 /* Allocate... */
8749 short *help;
8750 ALLOC(help, short,
8751 EX * EY * EP);
8752
8753 /* Read fill value and missing value... */
8754 short fillval, missval;
8755 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8756 fillval = 0;
8757 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
8758 missval = 0;
8759
8760 /* Write info... */
8761 LOG(2, "Read 2-D variable: %s"
8762 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
8763 varsel, fillval, missval, scalfac, offset);
8764
8765 /* Read data... */
8766 NC(nc_get_var_short(ncid, varid, help));
8767
8768 /* Check meteo data layout... */
8769 if (ctl->met_convention != 0)
8770 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
8771
8772 /* Copy and check data... */
8773 omp_set_dynamic(1);
8774#pragma omp parallel for default(shared)
8775 for (int ix = 0; ix < met->nx; ix++)
8776 for (int iy = 0; iy < met->ny; iy++) {
8777 if (init)
8778 dest[ix][iy] = 0;
8779 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
8780 if ((fillval == 0 || aux != fillval)
8781 && (missval == 0 || aux != missval)
8782 && fabsf(aux * scalfac + offset) < 1e14f)
8783 dest[ix][iy] += scl * (aux * scalfac + offset);
8784 else
8785 dest[ix][iy] = NAN;
8786 }
8787 omp_set_dynamic(0);
8788
8789 /* Free... */
8790 free(help);
8791 }
8792
8793 /* Unpacked data... */
8794 else if (!ctl->dd) {
8795
8796 /* Allocate... */
8797 float *help;
8798 ALLOC(help, float,
8799 EX * EY);
8800
8801 /* Read fill value and missing value... */
8802 float fillval, missval;
8803 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8804 fillval = 0;
8805 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8806 missval = 0;
8807
8808 /* Write info... */
8809 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8810 varsel, fillval, missval);
8811
8812 /* Read data... */
8813 NC(nc_get_var_float(ncid, varid, help));
8814
8815 /* Check meteo data layout... */
8816 if (ctl->met_convention == 0) {
8817
8818 /* Copy and check data (ordering: lat, lon)... */
8819 omp_set_dynamic(1);
8820#pragma omp parallel for default(shared)
8821 for (int ix = 0; ix < met->nx; ix++)
8822 for (int iy = 0; iy < met->ny; iy++) {
8823 if (init)
8824 dest[ix][iy] = 0;
8825 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
8826 if ((fillval == 0 || aux != fillval)
8827 && (missval == 0 || aux != missval)
8828 && fabsf(aux) < 1e14f)
8829 dest[ix][iy] += scl * aux;
8830 else
8831 dest[ix][iy] = NAN;
8832 }
8833 omp_set_dynamic(0);
8834
8835 } else {
8836
8837 /* Copy and check data (ordering: lon, lat)... */
8838 omp_set_dynamic(1);
8839#pragma omp parallel for default(shared)
8840 for (int iy = 0; iy < met->ny; iy++)
8841 for (int ix = 0; ix < met->nx; ix++) {
8842 if (init)
8843 dest[ix][iy] = 0;
8844 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
8845 if ((fillval == 0 || aux != fillval)
8846 && (missval == 0 || aux != missval)
8847 && fabsf(aux) < 1e14f)
8848 dest[ix][iy] += scl * aux;
8849 else
8850 dest[ix][iy] = NAN;
8851 }
8852 omp_set_dynamic(0);
8853 }
8854
8855 /* Free... */
8856 free(help);
8857
8858 }
8859 /* Domain decomposed data... */
8860 else {
8861
8862 /* Read fill value and missing value... */
8863 float fillval, missval;
8864 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8865 fillval = 0;
8866 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8867 missval = 0;
8868
8869 /* Write info... */
8870 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8871 varsel, fillval, missval);
8872
8873 /* Define hyperslab... */
8874 float *help;
8875 size_t help_subdomain_start[3];
8876 size_t help_subdomain_count[3];
8877
8878 help_subdomain_start[0] = 0;
8879 help_subdomain_start[1] = dd->subdomain_start[2];
8880 help_subdomain_start[2] = dd->subdomain_start[3];
8881
8882 help_subdomain_count[0] = 1;
8883 help_subdomain_count[1] = dd->subdomain_count[2]; //y
8884 help_subdomain_count[2] = dd->subdomain_count[3]; //x
8885
8886 ALLOC(help, float,
8887 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]
8888 );
8889
8890 /* Read data... */
8891 NC(nc_get_vara_float
8892 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
8893
8894 /* Read halos at boundaries... */
8895 size_t help_halo_bnd_start[3];
8896 size_t help_halo_bnd_count[3];
8897
8898 help_halo_bnd_start[0] = 0;
8899 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
8900 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
8901
8902 help_halo_bnd_count[0] = 1;
8903 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
8904 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
8905
8906 float *help_halo;
8907 ALLOC(help_halo, float,
8908 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
8909 NC(nc_get_vara_float
8910 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
8911
8912 /* Check meteo data layout... */
8913 if (ctl->met_convention == 0) {
8914 /* Copy and check data (ordering: lat, lon)... */
8915#pragma omp parallel for default(shared) num_threads(12)
8916 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
8917 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
8918 if (init == 1)
8919 dest[ix + dd->halo_offset_start][iy] = 0;
8920 const float aux =
8921 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
8922 if ((fillval == 0 || aux != fillval)
8923 && (missval == 0 || aux != missval)
8924 && fabsf(aux) < 1e14f) {
8925 dest[ix + dd->halo_offset_start][iy] += scl * aux;
8926 } else
8927 dest[ix + dd->halo_offset_start][iy] = NAN;
8928 }
8929
8930 /* Copy and check data (ordering: lat, lon)... */
8931#pragma omp parallel for default(shared) num_threads(12)
8932 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
8933 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
8934 if (init == 1)
8935 dest[ix + dd->halo_offset_end][iy] = 0;
8936 const float aux =
8937 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
8938 if ((fillval == 0 || aux != fillval)
8939 && (missval == 0 || aux != missval)
8940 && fabsf(aux) < 1e14f)
8941 dest[ix + dd->halo_offset_end][iy] += scl * aux;
8942 else {
8943 dest[ix + dd->halo_offset_end][iy] = NAN;
8944 }
8945 }
8946
8947 } else {
8948 ERRMSG("Domain decomposition with data convection incompatible!");
8949 }
8950
8951 /* Free... */
8952 free(help);
8953 free(help_halo);
8954 }
8955
8956 /* Return... */
8957 return 1;
8958}
8959
8960/*****************************************************************************/
8961
8963 const int ncid,
8964 const char *varname,
8965 const char *varname2,
8966 const char *varname3,
8967 const char *varname4,
8968 const ctl_t *ctl,
8969 const met_t *met,
8970 dd_t *dd,
8971 float dest[EX][EY][EP],
8972 const float scl) {
8973
8974 SELECT_TIMER("read_met_nc_3d", "INPUT", NVTX_READ);
8975
8976 char varsel[LEN];
8977
8978 float offset, scalfac;
8979
8980 int varid;
8981
8982 /* Check if variable exists... */
8983 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8984 sprintf(varsel, "%s", varname);
8985 else if (varname2 != NULL
8986 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8987 sprintf(varsel, "%s", varname2);
8988 else if (varname3 != NULL
8989 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8990 sprintf(varsel, "%s", varname3);
8991 else if (varname4 != NULL
8992 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8993 sprintf(varsel, "%s", varname4);
8994 else
8995 return 0;
8996
8997 if (ctl->met_nc_scale && !ctl->dd
8998 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8999 && nc_get_att_float(ncid, varid, "scale_factor",
9000 &scalfac) == NC_NOERR) {
9001
9002 /* Allocate... */
9003 short *help;
9004 ALLOC(help, short,
9005 EX * EY * EP);
9006
9007 /* Read fill value and missing value... */
9008 short fillval, missval;
9009 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9010 fillval = 0;
9011 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9012 missval = 0;
9013
9014 /* Write info... */
9015 LOG(2, "Read 3-D variable: %s "
9016 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9017 varsel, fillval, missval, scalfac, offset);
9018
9019 /* Read data... */
9020 NC(nc_get_var_short(ncid, varid, help));
9021
9022 /* Check meteo data layout... */
9023 if (ctl->met_convention != 0)
9024 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9025
9026 /* Copy and check data... */
9027 omp_set_dynamic(1);
9028#pragma omp parallel for default(shared)
9029 for (int ix = 0; ix < met->nx; ix++)
9030 for (int iy = 0; iy < met->ny; iy++)
9031 for (int ip = 0; ip < met->np; ip++) {
9032 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9033 if ((fillval == 0 || aux != fillval)
9034 && (missval == 0 || aux != missval)
9035 && fabsf(aux * scalfac + offset) < 1e14f)
9036 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
9037 else
9038 dest[ix][iy][ip] = NAN;
9039 }
9040 omp_set_dynamic(0);
9041
9042 /* Free... */
9043 free(help);
9044 }
9045
9046 /* Unpacked data... */
9047 else if (!ctl->dd) {
9048
9049 /* Allocate... */
9050 float *help;
9051 ALLOC(help, float,
9052 EX * EY * EP);
9053
9054 /* Read fill value and missing value... */
9055 float fillval, missval;
9056 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9057 fillval = 0;
9058 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9059 missval = 0;
9060
9061 /* Write info... */
9062 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9063 varsel, fillval, missval);
9064
9065 /* Read data... */
9066 NC(nc_get_var_float(ncid, varid, help));
9067
9068 /* Check meteo data layout... */
9069 if (ctl->met_convention == 0) {
9070
9071 /* Copy and check data (ordering: lev, lat, lon)... */
9072 omp_set_dynamic(1);
9073#pragma omp parallel for default(shared)
9074 for (int ix = 0; ix < met->nx; ix++)
9075 for (int iy = 0; iy < met->ny; iy++)
9076 for (int ip = 0; ip < met->np; ip++) {
9077 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9078 if ((fillval == 0 || aux != fillval)
9079 && (missval == 0 || aux != missval)
9080 && fabsf(aux) < 1e14f)
9081 dest[ix][iy][ip] = scl * aux;
9082 else
9083 dest[ix][iy][ip] = NAN;
9084 }
9085 omp_set_dynamic(0);
9086
9087 } else {
9088
9089 /* Copy and check data (ordering: lon, lat, lev)... */
9090 omp_set_dynamic(1);
9091#pragma omp parallel for default(shared)
9092 for (int ip = 0; ip < met->np; ip++)
9093 for (int iy = 0; iy < met->ny; iy++)
9094 for (int ix = 0; ix < met->nx; ix++) {
9095 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9096 if ((fillval == 0 || aux != fillval)
9097 && (missval == 0 || aux != missval)
9098 && fabsf(aux) < 1e14f)
9099 dest[ix][iy][ip] = scl * aux;
9100 else
9101 dest[ix][iy][ip] = NAN;
9102 }
9103 omp_set_dynamic(0);
9104 }
9105
9106 /* Free... */
9107 free(help);
9108
9109 }
9110 /* Domain decomposed data... */
9111 else {
9112
9113 /* Read fill value and missing value... */
9114 float fillval, missval;
9115 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9116 fillval = 0;
9117 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9118 missval = 0;
9119
9120 /* Write info... */
9121 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9122 varsel, fillval, missval);
9123
9124 SELECT_TIMER("read_met_nc_3d_CP1", "INPUT", NVTX_READ);
9125
9126 /* Define hyperslab... */
9127
9128 /* Allocate... */
9129 float *help;
9130 ALLOC(help, float,
9131 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
9132 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
9133
9134 SELECT_TIMER("read_met_nc_3d_CP2", "INPUT", NVTX_READ);
9135
9136 /* Use default NetCDF parallel I/O behavior */
9137 NC(nc_get_vara_float
9138 (ncid, varid, dd->subdomain_start, dd->subdomain_count, help));
9139
9140 /* Read halos separately at boundaries... */
9141 float *help_halo;
9142 ALLOC(help_halo, float,
9143 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
9144 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
9145
9146 SELECT_TIMER("read_met_nc_3d_CP3", "INPUT", NVTX_READ);
9147
9148 /* Halo read also uses independent access */
9149 NC(nc_get_vara_float(ncid,
9150 varid,
9151 dd->halo_bnd_start, dd->halo_bnd_count, help_halo));
9152
9153 SELECT_TIMER("read_met_nc_3d_CP4", "INPUT", NVTX_READ);
9154
9155 /* Check meteo data layout... */
9156 if (ctl->met_convention == 0) {
9157 /* Copy and check data (ordering: lev, lat, lon)... */
9158#pragma omp parallel for default(shared) num_threads(12)
9159 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
9160 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9161 for (int ip = 0; ip < met->np; ip++) {
9162 const float aux =
9163 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
9164 (int) dd->subdomain_count[3])];
9165 if ((fillval == 0 || aux != fillval)
9166 && (missval == 0 || aux != missval)
9167 && fabsf(aux) < 1e14f)
9168 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9169 else
9170 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9171 }
9172
9173#pragma omp parallel for default(shared) num_threads(12)
9174 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
9175 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9176 for (int ip = 0; ip < met->np; ip++) {
9177 const float aux =
9178 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
9179 (int) dd->halo_bnd_count[3])];
9180 if ((fillval == 0 || aux != fillval)
9181 && (missval == 0 || aux != missval)
9182 && fabsf(aux) < 1e14f)
9183 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9184 else
9185 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9186 }
9187
9188 } else {
9189
9190 /* Copy and check data (ordering: lon, lat, lev)... */
9191#pragma omp parallel for default(shared) num_threads(12)
9192 for (int ip = 0; ip < met->np; ip++)
9193 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9194 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
9195 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9196 if ((fillval == 0 || aux != fillval)
9197 && (missval == 0 || aux != missval)
9198 && fabsf(aux) < 1e14f)
9199 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9200 else
9201 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9202 }
9203
9204#pragma omp parallel for default(shared) num_threads(12)
9205 for (int ip = 0; ip < met->np; ip++)
9206 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9207 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
9208 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9209 if ((fillval == 0 || aux != fillval)
9210 && (missval == 0 || aux != missval)
9211 && fabsf(aux) < 1e14f)
9212 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9213 else
9214 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9215 }
9216 }
9217
9218 /* Free... */
9219 free(help);
9220 free(help_halo);
9221 }
9222
9223 /* Return... */
9224 return 1;
9225}
9226
9227/*****************************************************************************/
9228
9229#ifdef ECCODES
9230int read_met_grib(
9231 const char *filename,
9232 const ctl_t *ctl,
9233 met_t *met) {
9234
9235 /* Set filenames... */
9236 size_t filename_len = strlen(filename) + 1;
9237 char sf_filename[filename_len];
9238 char ml_filename[filename_len];
9239 strcpy(sf_filename, filename);
9240 strcpy(ml_filename, filename);
9241 get_met_replace(ml_filename, "XX", "ml");
9242 get_met_replace(sf_filename, "XX", "sf");
9243
9244 /* Open files... */
9245 FILE *ml_file = fopen(ml_filename, "rb");
9246 FILE *sf_file = fopen(sf_filename, "rb");
9247 if (ml_file == NULL || sf_file == NULL) {
9248 if (ml_file != NULL) {
9249 fclose(ml_file);
9250 WARN("Cannot open file: %s", sf_filename);
9251 }
9252 if (sf_file != NULL) {
9253 fclose(sf_file);
9254 WARN("Cannot open file: %s", ml_filename);
9255 }
9256 return 0;
9257 }
9258
9259 /* Get handles for model level data... */
9260 int ml_num_messages = 0, err = 0;
9261 ECC(codes_count_in_file(0, ml_file, &ml_num_messages));
9262 codes_handle **ml_handles =
9263 (codes_handle **) malloc(sizeof(codes_handle *) *
9264 (size_t) ml_num_messages);
9265 for (int i = 0; i < ml_num_messages; i++) {
9266 codes_handle *h = NULL;
9267 if ((h = codes_grib_handle_new_from_file(0, ml_file, &err)) != NULL)
9268 ml_handles[i] = h;
9269 }
9270
9271 /* Get handles for surface data... */
9272 int sf_num_messages = 0;
9273 ECC(codes_count_in_file(0, sf_file, &sf_num_messages));
9274 codes_handle **sf_handles =
9275 (codes_handle **) malloc(sizeof(codes_handle *) *
9276 (size_t) sf_num_messages);
9277 for (int i = 0; i < sf_num_messages; i++) {
9278 codes_handle *h = NULL;
9279 if ((h = codes_grib_handle_new_from_file(0, sf_file, &err)) != NULL)
9280 sf_handles[i] = h;
9281 }
9282
9283 /* Close files... */
9284 fclose(ml_file);
9285 fclose(sf_file);
9286
9287 /* Read grid data... */
9288 read_met_grib_grid(ml_handles, ml_num_messages, met);
9289
9290 /* Read surface data... */
9291 read_met_grib_surface(sf_handles, sf_num_messages, ctl, met);
9292 for (int i = 0; i < sf_num_messages; i++)
9293 codes_handle_delete(sf_handles[i]);
9294 free(sf_handles);
9295
9296 /* Compute 3D pressure field... */
9297 size_t value_count = 0;
9298 ECC(codes_get_size(ml_handles[0], "pv", &value_count));
9299 if (value_count % 2 != 0)
9300 ERRMSG("Unexpected pv array length!");
9301 size_t nlevels = value_count / 2 - 1; /* number of full model levels */
9302 double *values;
9303 ALLOC(values, double,
9304 value_count);
9305 ECC(codes_get_double_array(ml_handles[0], "pv", values, &value_count));
9306 double *a_vals = values;
9307 double *b_vals = values + nlevels;
9308 if (met->npl > (int) nlevels)
9309 ERRMSG("met->npl exceeds number of pressure levels in GRIB!");
9310 for (int nx = 0; nx < met->nx; nx++)
9311 for (int ny = 0; ny < met->ny; ny++)
9312 for (int level = 0; level <= met->npl; level++) {
9313 const float p1 = (float) (a_vals[level] * 0.01f +
9314 met->ps[nx][ny] * b_vals[level]);
9315 const float p2 = (float) (a_vals[level + 1] * 0.01f +
9316 met->ps[nx][ny] * b_vals[level + 1]);
9317 met->pl[nx][ny][level] = 0.5f * (p1 + p2);
9318 }
9319 free(values);
9320
9321 /* Read model level data... */
9322 read_met_grib_levels(ml_handles, ml_num_messages, ctl, met);
9323 for (int i = 0; i < ml_num_messages; i++)
9324 codes_handle_delete(ml_handles[i]);
9325 free(ml_handles);
9326
9327 /* Return success... */
9328 return 1;
9329}
9330#endif
9331
9332/*****************************************************************************/
9333
9334#ifdef ECCODES
9336 codes_handle **handles,
9337 int count_handles,
9338 met_t *met) {
9339
9340 /* Set timer... */
9341 SELECT_TIMER("READ_MET_GRIB_GRID", "INPUT", NVTX_READ);
9342 LOG(2, "Read meteo grid information...");
9343
9344 /* Read date and time... */
9345 char datestr[LEN], timestr[LEN];
9346 size_t s_date = sizeof(datestr);
9347 ECC(codes_get_string(handles[0], "dataDate", datestr, &s_date));
9348 size_t s_time = sizeof(timestr);
9349 ECC(codes_get_string(handles[0], "dataTime", timestr, &s_time));
9350 int year, month, day, hour;
9351 if (sscanf(datestr, "%4d%2d%2d", &year, &month, &day) != 3)
9352 ERRMSG("Failed to parse dataDate: %s", datestr);
9353 if (sscanf(timestr, "%2d", &hour) != 1)
9354 ERRMSG("Failed to parse dataTime: %s", timestr);
9355 time2jsec(year, month, day, hour, 0, 0, 0, &(met->time));
9356 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)", met->time, year, month,
9357 day, hour, 0);
9358
9359 /* Read grid information... */
9360 long count_lat = 0, count_lon = 0;
9361 ECC(codes_get_long(handles[0], "Nj", &count_lat));
9362 ECC(codes_get_long(handles[0], "Ni", &count_lon));
9363 met->ny = (int) count_lat;
9364 met->nx = (int) count_lon;
9365
9366 /* Check grid dimensions... */
9367 LOG(2, "Number of longitudes: %d", met->nx);
9368 if (met->nx < 2 || met->nx > EX)
9369 ERRMSG("Number of longitudes out of range!");
9370 LOG(2, "Number of latitudes: %d", met->ny);
9371 if (met->ny < 2 || met->ny > EY)
9372 ERRMSG("Number of latitudes out of range!");
9373
9374 double first_lon, last_lon, first_lat, last_lat, inc_lon, inc_lat;
9375 ECC(codes_get_double
9376 (handles[0], "longitudeOfFirstGridPointInDegrees", &first_lon));
9377 ECC(codes_get_double
9378 (handles[0], "latitudeOfFirstGridPointInDegrees", &first_lat));
9379 ECC(codes_get_double
9380 (handles[0], "longitudeOfLastGridPointInDegrees", &last_lon));
9381 ECC(codes_get_double
9382 (handles[0], "latitudeOfLastGridPointInDegrees", &last_lat));
9383 ECC(codes_get_double(handles[0], "iDirectionIncrementInDegrees", &inc_lon));
9384 ECC(codes_get_double(handles[0], "jDirectionIncrementInDegrees", &inc_lat));
9385
9386 long jscanpos, iscanneg;
9387 ECC(codes_get_long(handles[0], "iScansNegatively", &iscanneg));
9388 ECC(codes_get_long(handles[0], "jScansPositively", &jscanpos));
9389
9390 /* Compute longitude-latitude grid... */
9391 int counter = 0;
9392 if (iscanneg == 0)
9393 for (double i = first_lon; i <= last_lon + 1e-6; i += inc_lon) {
9394 met->lon[counter] = i;
9395 counter++;
9396 } else
9397 for (double i = first_lon; i > last_lon - 1e-6; i -= inc_lon) {
9398 met->lon[counter] = i;
9399 counter++;
9400 }
9401
9402 counter = 0;
9403 if (jscanpos == 0)
9404 for (double i = first_lat; i > last_lat - 1e-6; i -= inc_lat) {
9405 met->lat[counter] = i;
9406 counter++;
9407 } else
9408 for (double i = first_lat; i <= last_lat + 1e-6; i += inc_lat) {
9409 met->lat[counter] = i;
9410 counter++;
9411 }
9412
9413 /* Write info... */
9414 LOG(2, "Longitudes: %g, %g ... %g deg",
9415 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9416 LOG(2, "Latitudes: %g, %g ... %g deg",
9417 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9418
9419 /* Read vertical levels... */
9420 int max_level = 0;
9421 for (int i = 0; i < count_handles; i++) {
9422 long level;
9423 ECC(codes_get_long(handles[i], "level", &level));
9424 if (level > max_level)
9425 max_level = (int) level;
9426 }
9427 met->npl = max_level;
9428
9429 /* Check number of levels... */
9430 LOG(2, "Number of levels: %d", met->npl);
9431 if (met->npl < 2 || met->npl > EP)
9432 ERRMSG("Number of levels out of range!");
9433}
9434#endif
9435
9436/*****************************************************************************/
9437
9438#ifdef ECCODES
9440 codes_handle **handles,
9441 const int num_messages,
9442 const ctl_t *ctl,
9443 met_t *met) {
9444
9445 /* Set timer... */
9446 SELECT_TIMER("READ_MET_GRIB_LEVELS", "INPUT", NVTX_READ);
9447 LOG(2, "Read level data...");
9448
9449 /* Init... */
9450 int t_flag = 0, u_flag = 0, v_flag = 0, w_flag = 0, o3_flag = 0, h2o_flag =
9451 0, lwc_flag = 0, rwc_flag = 0, iwc_flag = 0, swc_flag = 0, cc_flag = 0;
9452
9453 /* Iterate over all messages... */
9454 for (int i = 0; i < num_messages; i++) {
9455
9456 size_t max_size = LEN;
9457 char short_name[max_size];
9458 size_t value_count;
9459 double *values;
9460
9461 /* Get the current level */
9462 long current_level;
9463 ECC(codes_get_long(handles[i], "level", &current_level));
9464 current_level -= 1;
9465
9466 /* Retrieve data from current message */
9467 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
9468 ECC(codes_get_size(handles[i], "values", &value_count));
9469 ALLOC(values, double,
9470 value_count);
9471 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
9472
9473 /* Read temperature... */
9474 ECC_READ_3D("t", current_level, met->t, 1.0, t_flag);
9475
9476 /* Read horizontal wind and vertical velocity... */
9477 ECC_READ_3D("u", current_level, met->u, 1.0, u_flag);
9478 ECC_READ_3D("v", current_level, met->v, 1.0, v_flag);
9479 ECC_READ_3D("w", current_level, met->w, 0.01f, w_flag);
9480
9481 /* Read water vapor and ozone... */
9482 ECC_READ_3D("q", current_level, met->h2o, (float) (MA / MH2O), h2o_flag);
9483 ECC_READ_3D("o3", current_level, met->o3, (float) (MA / MO3), o3_flag);
9484
9485 /* Read cloud data... */
9486 ECC_READ_3D("clwc", current_level, met->lwc, 1.0, lwc_flag);
9487 ECC_READ_3D("crwc", current_level, met->rwc, 1.0, rwc_flag);
9488 ECC_READ_3D("ciwc", current_level, met->iwc, 1.0, iwc_flag);
9489 ECC_READ_3D("cswc", current_level, met->swc, 1.0, swc_flag);
9490 ECC_READ_3D("cc", current_level, met->cc, 1.0, cc_flag);
9491
9492 /*Free allocated array */
9493 free(values);
9494 }
9495
9496 /* Check whether data were found... */
9497 if (t_flag != met->npl)
9498 ERRMSG("Cannot read temperature!");
9499 if (u_flag != met->npl)
9500 ERRMSG("Cannot read zonal wind!");
9501 if (v_flag != met->npl)
9502 ERRMSG("Cannot read meridional wind!");
9503 if (w_flag != met->npl)
9504 WARN("Cannot read vertical velocity!");
9505 if (h2o_flag != met->npl)
9506 WARN("Cannot read specific humidity!");
9507 if (o3_flag != met->npl)
9508 WARN("Cannot read ozone data!");
9509 if (lwc_flag != met->npl)
9510 WARN("Cannot read cloud liquid water content!");
9511 if (rwc_flag != met->npl)
9512 WARN("Cannot read cloud rain water content!");
9513 if (iwc_flag != met->npl)
9514 WARN("Cannot read cloud ice water content!");
9515 if (swc_flag != met->npl)
9516 WARN("Cannot read cloud snow water content!");
9517 if (cc_flag != met->npl)
9518 WARN("Cannot read cloud cover!");
9519
9520 /* Check ordering of pressure levels... */
9521 for (int ix = 0; ix < met->nx; ix++)
9522 for (int iy = 0; iy < met->ny; iy++)
9523 for (int ip = 1; ip < met->np; ip++)
9524 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
9525 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
9526 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
9527 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip])) {
9528 LOG(1, "%f %f %f %f", met->pl[ix][iy][0], met->pl[ix][iy][1],
9529 met->pl[ix][iy][ip - 1], met->pl[ix][iy][ip]);
9530 ERRMSG("Pressure profiles are not monotonic!");
9531 }
9532
9533 /* Interpolate from model levels to pressure levels... */
9534 if (ctl->met_np > 0) {
9535 met->np = ctl->met_np;
9536
9537 /* Interpolate variables... */
9538 read_met_ml2pl(ctl, met, met->t, "T");
9539 read_met_ml2pl(ctl, met, met->u, "U");
9540 read_met_ml2pl(ctl, met, met->v, "V");
9541 read_met_ml2pl(ctl, met, met->w, "W");
9542 read_met_ml2pl(ctl, met, met->h2o, "H2O");
9543 read_met_ml2pl(ctl, met, met->o3, "O3");
9544 read_met_ml2pl(ctl, met, met->lwc, "LWC");
9545 read_met_ml2pl(ctl, met, met->rwc, "RWC");
9546 read_met_ml2pl(ctl, met, met->iwc, "IWC");
9547 read_met_ml2pl(ctl, met, met->swc, "SWC");
9548 read_met_ml2pl(ctl, met, met->cc, "CC");
9549
9550 /* Set new pressure levels... */
9551 for (int ip = 0; ip < met->np; ip++)
9552 met->p[ip] = ctl->met_p[ip];
9553 }
9554
9555 /* Check ordering of pressure levels... */
9556 for (int ip = 1; ip < met->np; ip++)
9557 if (met->p[ip - 1] < met->p[ip])
9558 ERRMSG("Pressure levels must be descending!");
9559}
9560#endif
9561
9562/*****************************************************************************/
9563
9564#ifdef ECCODES
9566 codes_handle **handles,
9567 const int num_messages,
9568 const ctl_t *ctl,
9569 met_t *met) {
9570
9571 /* Set timer... */
9572 SELECT_TIMER("READ_MET_GRIB_SURFACE", "INPUT", NVTX_READ);
9573 LOG(2, "Read surface data...");
9574
9575 /* Init... */
9576 int sp_flag = 0, z_flag = 0, t_flag = 0, u_flag = 0, v_flag = 0, lsm_flag =
9577 0, sst_flag = 0, cape_flag = 0, cin_flag = 0, pbl_flag = 0;
9578
9579 /* Iterate over all messages... */
9580 for (int i = 0; i < num_messages; i++) {
9581
9582 size_t max_size = LEN, value_count;
9583
9584 char short_name[max_size];
9585
9586 /* Store values with shortname... */
9587 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
9588 ECC(codes_get_size(handles[i], "values", &value_count));
9589 double *values = (double *) malloc(value_count * sizeof(double));
9590 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
9591
9592 /*Read surface pressure... */
9593 ECC_READ_2D("sp", met->ps, 0.01f, sp_flag);
9594
9595 /*Read geopotential height at the surface... */
9596 ECC_READ_2D("z", met->zs, (float) (1. / (1000. * G0)), z_flag);
9597
9598 /* Read temperature at the surface... */
9599 ECC_READ_2D("2t", met->ts, 1.0f, t_flag);
9600
9601 /* Read zonal wind at the surface... */
9602 ECC_READ_2D("10u", met->us, 1.0f, u_flag);
9603
9604 /* Read meridional wind at the surface... */
9605 ECC_READ_2D("10v", met->vs, 1.0f, v_flag);
9606
9607 /* Read land-sea mask... */
9608 ECC_READ_2D("lsm", met->lsm, 1.0f, lsm_flag);
9609
9610 /* Read sea surface temperature... */
9611 ECC_READ_2D("sst", met->sst, 1.0f, sst_flag);
9612 if (ctl->met_cape == 0) {
9613
9614 /* Read CAPE... */
9615 ECC_READ_2D("cape", met->cape, 1.0f, cape_flag);
9616
9617 /* Read CIN... */
9618 ECC_READ_2D("cin", met->cin, 1.0f, cin_flag);
9619 }
9620
9621 /* Read PBL... */
9622 if (ctl->met_pbl == 0)
9623 ECC_READ_2D("blh", met->pbl, 0.0001f, pbl_flag);
9624 }
9625
9626 /* Check whether data have been read... */
9627 if (sp_flag == 0)
9628 WARN("Cannot read surface pressure data!");
9629 if (z_flag == 0)
9630 WARN("Cannot read surface geopotential height!");
9631 if (t_flag == 0)
9632 WARN("Cannot read surface temperature!");
9633 if (u_flag == 0)
9634 WARN("Cannot read surface zonal wind!");
9635 if (v_flag == 0)
9636 WARN("Cannot read surface meridional wind!");
9637 if (lsm_flag == 0)
9638 WARN("Cannot read land-sea mask!");
9639 if (sst_flag == 0)
9640 WARN("Cannot read sea surface temperature!");
9641 if (ctl->met_cape == 0) {
9642 if (cape_flag == 0)
9643 WARN("Cannot read CAPE!");
9644 if (cin_flag == 0)
9645 WARN("Cannot read convective inhibition!");
9646 }
9647 if (ctl->met_pbl == 0 && pbl_flag == 0)
9648 WARN("Cannot read planetary boundary layer!");
9649}
9650#endif
9651
9652/*****************************************************************************/
9653
9655 const ctl_t *ctl,
9656 const met_t *met,
9657 float var[EX][EY][EP],
9658 const char *varname) {
9659
9660 double aux[EP], p[EP];
9661
9662 /* Set timer... */
9663 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
9664 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
9665
9666 /* Loop over columns... */
9667#pragma omp parallel for default(shared) private(aux,p) collapse(2)
9668 for (int ix = 0; ix < met->nx; ix++)
9669 for (int iy = 0; iy < met->ny; iy++) {
9670
9671 /* Copy pressure profile... */
9672 for (int ip = 0; ip < met->np; ip++)
9673 p[ip] = met->pl[ix][iy][ip];
9674
9675 /* Interpolate... */
9676 for (int ip = 0; ip < ctl->met_np; ip++) {
9677 double pt = ctl->met_p[ip];
9678 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
9679 pt = p[0];
9680 else if ((pt > p[met->np - 1] && p[1] > p[0])
9681 || (pt < p[met->np - 1] && p[1] < p[0]))
9682 pt = p[met->np - 1];
9683 const int ip2 = locate_irr(p, met->np, pt);
9684 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
9685 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
9686 }
9687
9688 /* Copy data... */
9689 for (int ip = 0; ip < ctl->met_np; ip++)
9690 var[ix][iy][ip] = (float) aux[ip];
9691 }
9692}
9693
9694/*****************************************************************************/
9695
9697 const ctl_t *ctl,
9698 met_t *met) {
9699
9700 /* Check parameters... */
9701 if (ctl->advect_vert_coord != 1)
9702 return;
9703
9704 /* Set timer... */
9705 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
9706 LOG(2, "Make zeta profiles monotone...");
9707
9708 /* Create monotone zeta profiles... */
9709#pragma omp parallel for default(shared) collapse(2)
9710 for (int i = 0; i < met->nx; i++)
9711 for (int j = 0; j < met->ny; j++) {
9712 int k = 1;
9713
9714 while (k < met->npl) { /* Check if there is an inversion at level k... */
9715 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
9716 /* Find the upper level k+l over the inversion... */
9717 int l = 0;
9718 do {
9719 l++;
9720 }
9721 while ((met->zetal[i][j][k - 1] >=
9722 met->zetal[i][j][k + l]) & (k + l < met->npl));
9723
9724 /* Interpolate linear between the top and bottom
9725 of the inversion... */
9726 float s =
9727 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
9728 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9729
9730 for (int m = k; m < k + l; m++) {
9731 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9732 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
9733 }
9734
9735 /* Search for more inversions above the last inversion ... */
9736 k = k + l;
9737 } else {
9738 k++;
9739 }
9740 }
9741 }
9742
9743 /* Create monotone pressure profiles... */
9744#pragma omp parallel for default(shared) collapse(2)
9745 for (int i = 0; i < met->nx; i++)
9746 for (int j = 0; j < met->ny; j++) {
9747 int k = 1;
9748
9749 while (k < met->npl) { /* Check if there is an inversion at level k... */
9750 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
9751
9752 /* Find the upper level k+l over the inversion... */
9753 int l = 0;
9754 do {
9755 l++;
9756 }
9757 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
9758 met->npl));
9759
9760 /* Interpolate linear between the top and bottom
9761 of the inversion... */
9762 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
9763 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9764
9765 for (int m = k; m < k + l; m++) {
9766 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9767 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
9768 }
9769
9770 /* Search for more inversions above the last inversion ... */
9771 k += l;
9772 } else {
9773 k++;
9774 }
9775 }
9776 }
9777}
9778
9779/*****************************************************************************/
9780
9782 const char *filename,
9783 const ctl_t *ctl,
9784 met_t *met,
9785 dd_t *dd) {
9786
9787 int ncid;
9788
9789 /* Open file... */
9790#ifdef DD
9791 if (ctl->dd) {
9792 NC(nc_open_par
9793 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
9794 &ncid))
9795 }
9796#else
9797 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
9798 WARN("Cannot open file!");
9799 return 0;
9800 }
9801#endif
9802
9803 /* Read coordinates of meteo data... */
9804 read_met_nc_grid(filename, ncid, ctl, met, dd);
9805
9806 /* Read surface data... */
9807 read_met_nc_surface(ncid, ctl, met, dd);
9808
9809 /* Read meteo data on vertical levels... */
9810 read_met_nc_levels(ncid, ctl, met, dd);
9811
9812 /* Close file... */
9813 NC(nc_close(ncid));
9814
9815 /* Return success... */
9816 return 1;
9817}
9818
9819/*****************************************************************************/
9820
9822 dd_t *dd,
9823 const ctl_t *ctl,
9824 met_t *met,
9825 const int ncid) {
9826
9827 int varid;
9828
9829 /* Get the MPI information... */
9830#ifdef MPI
9831 MPI_Comm_rank(MPI_COMM_WORLD, &dd->rank);
9832 MPI_Comm_size(MPI_COMM_WORLD, &dd->size);
9833#endif
9834
9835 int help_nx_glob;
9836 int help_ny_glob;
9837
9838 /* Get grid dimensions... */
9839 NC_INQ_DIM("lon", &help_nx_glob, 0, 0, 0);
9840 LOG(2, "Number of longitudes: %d", help_nx_glob);
9841 met->nx = (int) floor(help_nx_glob / ctl->dd_subdomains_zonal);
9842
9843 NC_INQ_DIM("lat", &help_ny_glob, 0, 0, 0);
9844 LOG(2, "Number of latitudes: %d", help_ny_glob);
9845 met->ny = (int) floor(help_ny_glob / ctl->dd_subdomains_meridional);
9846
9847 double *help_lon_glob;
9848 double *help_lat_glob;
9849 ALLOC(help_lon_glob, double,
9850 help_nx_glob);
9851 ALLOC(help_lat_glob, double,
9852 help_ny_glob);
9853
9854 /* Read global longitudes and latitudes... */
9855 NC_GET_DOUBLE("lon", help_lon_glob, 1);
9856 LOG(2, "Longitudes: %g, %g ... %g deg",
9857 help_lon_glob[0], help_lon_glob[1], help_lon_glob[help_nx_glob - 1]);
9858 NC_GET_DOUBLE("lat", help_lat_glob, 1);
9859 LOG(2, "Latitudes: %g, %g ... %g deg",
9860 help_lat_glob[0], help_lat_glob[1], help_lat_glob[help_ny_glob - 1]);
9861
9862 /* Determine hyperslabs for reading the data in parallel... */
9863
9864 /* Check for edge cases... */
9865 int left = (dd->rank <= ctl->dd_subdomains_meridional - 1);
9866 int right = (dd->rank >= dd->size - ctl->dd_subdomains_meridional);
9867 int top = (dd->rank % ctl->dd_subdomains_meridional == 0);
9868 int bottom =
9869 (dd->rank % ctl->dd_subdomains_meridional ==
9870 ctl->dd_subdomains_meridional - 1);
9871
9872 /* Set the hyperslab for the subdomain... */
9873 dd->subdomain_start[0] = 0;
9874 dd->subdomain_start[1] = 0;
9875 dd->subdomain_start[2] =
9876 (size_t) ((dd->rank % ctl->dd_subdomains_meridional) * met->ny);
9877 dd->subdomain_start[3] =
9878 (size_t) (floor(dd->rank / ctl->dd_subdomains_meridional) * met->nx);
9879
9880 /* Extend subdomains at the right and bottom to fit the full domain. */
9881 if (right) {
9882 int gap = help_nx_glob - ctl->dd_subdomains_zonal * met->nx;
9883 if (gap > 0) {
9884 met->nx = met->nx + gap;
9885 WARN("Extended subdomains at the right to fit to full domain.");
9886 }
9887 }
9888 if (bottom) {
9889 int gap = help_ny_glob - ctl->dd_subdomains_meridional * met->ny;
9890 if (gap > 0) {
9891 met->ny = met->ny + gap;
9892 WARN("Extended subdomains at the bottom to fit to full domain.");
9893 }
9894 }
9895
9896 /* Block-size, i.e. count */
9897 dd->subdomain_count[0] = 1;
9898 dd->subdomain_count[1] = (size_t) met->np;
9899 dd->subdomain_count[2] = (size_t) met->ny;
9900 dd->subdomain_count[3] = (size_t) met->nx;
9901
9902 /* Create halos and include them into the subdomain... */
9903 if (!left && !right) {
9904 // If we are not at the left or right edge extend in zonal direction...
9905 // Move the start one point to the left...
9906 dd->subdomain_count[3] =
9907 dd->subdomain_count[3] + (size_t) (ctl->dd_halos_size * 2);
9908 dd->subdomain_start[3] =
9909 dd->subdomain_start[3] - (size_t) ctl->dd_halos_size;
9910 } else {
9911 // If we are at the left or right edge, extend only in one zonal direction...
9912 dd->subdomain_count[3] =
9913 dd->subdomain_count[3] + (size_t) ctl->dd_halos_size;
9914 if (!left)
9915 // If we are not at the left edge, move the start to the left...
9916 dd->subdomain_start[3] =
9917 dd->subdomain_start[3] - (size_t) ctl->dd_halos_size;
9918 }
9919
9920 if (!top && !bottom) {
9921 // If we are not at the upper or lower edge extend in meridional direction...
9922 // Move the start point one point down...
9923 dd->subdomain_count[2] =
9924 dd->subdomain_count[2] + (size_t) (ctl->dd_halos_size * 2);
9925 dd->subdomain_start[2] =
9926 dd->subdomain_start[2] - (size_t) ctl->dd_halos_size;
9927 } else {
9928 // If we are at the top or the lower edge only extend in one mer. direction...
9929 dd->subdomain_count[2] =
9930 dd->subdomain_count[2] + (size_t) ctl->dd_halos_size;
9931 if (!top)
9932 // If we are not at the top, move the start one upward...
9933 dd->subdomain_start[2] =
9934 dd->subdomain_start[2] - (size_t) ctl->dd_halos_size;
9935 }
9936
9937 /* Set boundary halo hyperslabs ... */
9938 double lon_shift = 0;
9939 if (left || right) {
9940
9941 met->nx = met->nx + ctl->dd_halos_size;
9942
9943 dd->halo_bnd_start[0] = 0;
9944 dd->halo_bnd_start[1] = 0;
9945 dd->halo_bnd_start[3] = (size_t) (left ? (help_nx_glob - ctl->dd_halos_size) : (0)); //x
9946 dd->halo_bnd_start[2] = dd->subdomain_start[2]; //y
9947
9948 dd->halo_bnd_count[0] = 1;
9949 dd->halo_bnd_count[1] = (size_t) met->np;
9950 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
9951 dd->halo_bnd_count[2] =
9952 (size_t) met->ny +
9953 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
9954
9955 dd->halo_offset_start = (left ? (int) dd->halo_bnd_count[3] : 0);
9956 dd->halo_offset_end = (left ? 0 : (int) dd->subdomain_count[3]);
9957 lon_shift = (left ? -360 : 360);
9958
9959 } else {
9960
9961 dd->halo_bnd_start[0] = 0;
9962 dd->halo_bnd_start[1] = 0;
9963 dd->halo_bnd_start[3] = 0;
9964 dd->halo_bnd_start[2] = 0;
9965
9966 dd->halo_bnd_count[0] = 0;
9967 dd->halo_bnd_count[1] = 0;
9968 dd->halo_bnd_count[3] = 0;
9969 dd->halo_bnd_count[2] = 0;
9970 }
9971
9972 /* Get the range of the entire meteodata... */
9973 /* Handle both periodic (global) and non-periodic (regional) longitude grids */
9974 double lon_range = 360;
9975 //if (dd_is_periodic_longitude(met, help_nx_glob)) {
9976 /* For global grids with periodic boundaries, use full 360 degrees */
9977 //lon_range = 360.0;
9978 //LOG(3, "Detected periodic longitude boundaries, using lon_range = 360.0");
9979 //} else {
9980 /* For regional grids, use the actual data range */
9981 //lon_range = help_lon_glob[help_nx_glob - 1] - help_lon_glob[0];
9982 //LOG(3, "Detected non-periodic longitude boundaries, using lon_range = %g", lon_range);
9983 //}
9984
9985 double lat_range = help_lat_glob[help_ny_glob - 1] - help_lat_glob[0];
9986
9987 /* Focus on subdomain latitudes and longitudes... */
9988 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9989 met->lat[iy] = help_lat_glob[(int) dd->subdomain_start[2] + iy];
9990
9991 /* Focus on subdomain longitudes... */
9992 /* Keep space at the beginning or end of the array for halo... */
9993 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
9994 met->lon[ix + dd->halo_offset_start] =
9995 help_lon_glob[(int) dd->subdomain_start[3] + ix];
9996
9997 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
9998 met->lon[ix + dd->halo_offset_end] =
9999 help_lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
10000
10001 /* Reset the grid dimensions... */
10002 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
10003 met->ny = (int) dd->subdomain_count[2];
10004
10005 /* Determine subdomain edges... */
10006 dd->subdomain_lon_min = floor(dd->rank / ctl->dd_subdomains_meridional)
10007 * (lon_range) / (double) ctl->dd_subdomains_zonal;
10009 + (lon_range) / (double) ctl->dd_subdomains_zonal;
10010
10011 /* Latitudes in descending order (90 to -90) */
10012 if (lat_range < 0) {
10013 dd->subdomain_lat_max = 90 + (dd->rank % ctl->dd_subdomains_meridional)
10014 * (lat_range) / (double) ctl->dd_subdomains_meridional;
10016 + (lat_range) / (double) ctl->dd_subdomains_meridional;
10017 } else {
10018 WARN
10019 ("lat_range > 0, but is expected to be negative, i.e. latitudes should range from 90 to -90")
10020 dd->subdomain_lat_min = -90 + (dd->rank % ctl->dd_subdomains_meridional)
10021 * (lat_range) / (double) ctl->dd_subdomains_meridional;
10023 + (lat_range) / (double) ctl->dd_subdomains_meridional;
10024 }
10025
10026 LOG(2, "Total longitude range: %g deg", lon_range);
10027 LOG(2, "Total latitude range: %g deg", lat_range);
10028
10029 LOG(2, "Define subdomain properties.");
10030 LOG(2, "MPI information: Rank %d, Size %d", dd->rank, dd->size);
10031 LOG(2, "Edge position: l=%d,r=%d,t=%d, b=%d", (int) left, (int) right,
10032 (int) top, (int) bottom);
10033 LOG(2, "Sizes for limits: EX %d EY %d EP %d", EX, EY, EP);
10034 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d", met->nx,
10035 met->ny, met->np);
10036 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
10037 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
10038 (int) dd->halo_bnd_count[1]);
10039 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
10040 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
10041 (int) dd->subdomain_count[1]);
10042 LOG(2, "Subdomain start: nx %ld ny %ld np %ld", dd->subdomain_start[3],
10043 dd->subdomain_start[2], dd->subdomain_start[1]);
10044 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld", dd->halo_bnd_start[3],
10045 dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
10046 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
10047
10048 LOG(2, " %d Subdomain longitudes: %g, %g ... %g deg (edges: %g to %g)",
10049 dd->rank, met->lon[0], met->lon[1], met->lon[met->nx - 1],
10051 LOG(2, " %d Subdomain latitudes: %g, %g ... %g deg (edges: %g to %g)",
10052 dd->rank, met->lat[0], met->lat[1], met->lat[met->ny - 1],
10054
10055 free(help_lon_glob);
10056 free(help_lat_glob);
10057}
10058
10059/*****************************************************************************/
10060
10062 const ctl_t *ctl,
10063 met_t *met) {
10064
10065 /* Set timer... */
10066 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
10067 LOG(2, "Calculate planetary boundary layer...");
10068
10069 /* Convert PBL height from meteo file to pressure... */
10070 if (ctl->met_pbl == 1) {
10071
10072 /* Loop over grid points... */
10073#pragma omp parallel for default(shared) collapse(2)
10074 for (int ix = 0; ix < met->nx; ix++)
10075 for (int iy = 0; iy < met->ny; iy++) {
10076
10077 /* Get pressure at top of PBL... */
10078 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
10079 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
10080 met->pbl[ix][iy] =
10081 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
10082 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
10083 }
10084 }
10085
10086 /* Determine PBL based on Richardson number... */
10087 else if (ctl->met_pbl == 2) {
10088
10089 /* Parameters used to estimate the height of the PBL
10090 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
10091 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
10092
10093 /* Loop over grid points... */
10094#pragma omp parallel for default(shared) collapse(2)
10095 for (int ix = 0; ix < met->nx; ix++)
10096 for (int iy = 0; iy < met->ny; iy++) {
10097
10098 /* Set bottom level of PBL... */
10099 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
10100
10101 /* Find lowest level near the bottom... */
10102 int ip;
10103 for (ip = 1; ip < met->np; ip++)
10104 if (met->p[ip] < pbl_bot)
10105 break;
10106
10107 /* Get near surface data... */
10108 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
10109 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
10110 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
10111
10112 /* Init... */
10113 double rib_old = 0;
10114
10115 /* Loop over levels... */
10116 for (; ip < met->np; ip++) {
10117
10118 /* Get squared horizontal wind speed... */
10119 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
10120 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
10121 vh2 = MAX(vh2, SQR(umin));
10122
10123 /* Calculate bulk Richardson number... */
10124 const double rib =
10125 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
10126 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
10127 met->h2o[ix][iy][ip]) - tvs) / vh2;
10128
10129 /* Check for critical value... */
10130 if (rib >= rib_crit) {
10131 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
10132 rib, met->p[ip], rib_crit));
10133 if (met->pbl[ix][iy] > pbl_bot)
10134 met->pbl[ix][iy] = (float) pbl_bot;
10135 break;
10136 }
10137
10138 /* Save Richardson number... */
10139 rib_old = rib;
10140 }
10141 }
10142 }
10143
10144 /* Determine PBL based on potential temperature... */
10145 if (ctl->met_pbl == 3) {
10146
10147 /* Parameters used to estimate the height of the PBL
10148 (following HYSPLIT model)... */
10149 const double dtheta = 2.0, zmin = 0.1;
10150
10151 /* Loop over grid points... */
10152#pragma omp parallel for default(shared) collapse(2)
10153 for (int ix = 0; ix < met->nx; ix++)
10154 for (int iy = 0; iy < met->ny; iy++) {
10155
10156 /* Potential temperature at the surface... */
10157 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
10158
10159 /* Find topmost level where theta exceeds surface value by 2 K... */
10160 int ip;
10161 for (ip = met->np - 2; ip > 0; ip--)
10162 if (met->p[ip] >= 300.)
10163 if (met->p[ip] > met->ps[ix][iy]
10164 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
10165 break;
10166
10167 /* Interpolate... */
10168 met->pbl[ix][iy]
10169 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
10170 met->p[ip + 1],
10171 THETA(met->p[ip], met->t[ix][iy][ip]),
10172 met->p[ip], theta0 + dtheta));
10173
10174 /* Check minimum value... */
10175 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
10176 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
10177 met->pbl[ix][iy] = (float) pbl_min;
10178 }
10179 }
10180
10181 /* Loop over grid points... */
10182#pragma omp parallel for default(shared) collapse(2)
10183 for (int ix = 0; ix < met->nx; ix++)
10184 for (int iy = 0; iy < met->ny; iy++) {
10185
10186 /* Check minimum value... */
10187 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
10188 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
10189
10190 /* Check maximum value... */
10191 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
10192 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
10193 }
10194}
10195
10196/*****************************************************************************/
10197
10199 met_t *met) {
10200
10201 /* Set timer... */
10202 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
10203 LOG(2, "Apply periodic boundary conditions...");
10204
10205 /* Check longitudes... */
10206 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
10207 + met->lon[1] - met->lon[0] - 360) < 0.01))
10208 return;
10209
10210 /* Increase longitude counter... */
10211 if ((++met->nx) >= EX)
10212 ERRMSG("Cannot create periodic boundary conditions!");
10213
10214 /* Set longitude... */
10215 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
10216
10217 /* Loop over latitudes and pressure levels... */
10218#pragma omp parallel for default(shared)
10219 for (int iy = 0; iy < met->ny; iy++) {
10220 met->ps[met->nx - 1][iy] = met->ps[0][iy];
10221 met->zs[met->nx - 1][iy] = met->zs[0][iy];
10222 met->ts[met->nx - 1][iy] = met->ts[0][iy];
10223 met->us[met->nx - 1][iy] = met->us[0][iy];
10224 met->vs[met->nx - 1][iy] = met->vs[0][iy];
10225 met->ess[met->nx - 1][iy] = met->ess[0][iy];
10226 met->nss[met->nx - 1][iy] = met->nss[0][iy];
10227 met->shf[met->nx - 1][iy] = met->shf[0][iy];
10228 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
10229 met->sst[met->nx - 1][iy] = met->sst[0][iy];
10230 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
10231 met->cape[met->nx - 1][iy] = met->cape[0][iy];
10232 met->cin[met->nx - 1][iy] = met->cin[0][iy];
10233 for (int ip = 0; ip < met->np; ip++) {
10234 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
10235 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
10236 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
10237 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
10238 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
10239 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
10240 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
10241 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
10242 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
10243 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
10244 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
10245 }
10246 for (int ip = 0; ip < met->npl; ip++) {
10247 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
10248 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
10249 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
10250 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
10251 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
10252 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
10253 }
10254 }
10255}
10256
10257/*****************************************************************************/
10258
10260 met_t *met) {
10261
10262 /* Set timer... */
10263 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
10264 LOG(2, "Apply fix for polar winds...");
10265
10266 /* Check latitudes... */
10267 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
10268 return;
10269
10270 /* Loop over hemispheres... */
10271 for (int ihem = 0; ihem < 2; ihem++) {
10272
10273 /* Set latitude indices... */
10274 int i89 = 1, i90 = 0, sign = 1;
10275 if (ihem == 1) {
10276 i89 = met->ny - 2;
10277 i90 = met->ny - 1;
10278 }
10279 if (met->lat[i90] < 0)
10280 sign = -1;
10281
10282 /* Look-up table of cosinus and sinus... */
10283 double clon[EX], slon[EX];
10284#pragma omp parallel for default(shared)
10285 for (int ix = 0; ix < met->nx; ix++) {
10286 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
10287 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
10288 }
10289
10290 /* Loop over levels... */
10291#pragma omp parallel for default(shared)
10292 for (int ip = 0; ip < met->np; ip++) {
10293
10294 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
10295 double vel89x = 0, vel89y = 0;
10296 for (int ix = 0; ix < met->nx; ix++) {
10297 vel89x +=
10298 (met->u[ix][i89][ip] * clon[ix] -
10299 met->v[ix][i89][ip] * slon[ix]) / met->nx;
10300 vel89y +=
10301 (met->u[ix][i89][ip] * slon[ix] +
10302 met->v[ix][i89][ip] * clon[ix]) / met->nx;
10303 }
10304
10305 /* Replace 90 degree winds by 89 degree mean... */
10306 for (int ix = 0; ix < met->nx; ix++) {
10307 met->u[ix][i90][ip]
10308 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
10309 met->v[ix][i90][ip]
10310 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
10311 }
10312 }
10313 }
10314}
10315
10316/*****************************************************************************/
10317
10319 met_t *met) {
10320
10321 double pows[EP];
10322
10323 /* Set timer... */
10324 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
10325 LOG(2, "Calculate potential vorticity...");
10326
10327 /* Set powers... */
10328#pragma omp parallel for default(shared)
10329 for (int ip = 0; ip < met->np; ip++)
10330 pows[ip] = pow(1000. / met->p[ip], 0.286);
10331
10332 /* Loop over grid points... */
10333#pragma omp parallel for default(shared)
10334 for (int ix = 0; ix < met->nx; ix++) {
10335
10336 /* Set indices... */
10337 const int ix0 = MAX(ix - 1, 0);
10338 const int ix1 = MIN(ix + 1, met->nx - 1);
10339
10340 /* Loop over grid points... */
10341 for (int iy = 0; iy < met->ny; iy++) {
10342
10343 /* Set indices... */
10344 const int iy0 = MAX(iy - 1, 0);
10345 const int iy1 = MIN(iy + 1, met->ny - 1);
10346
10347 /* Set auxiliary variables... */
10348 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
10349 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
10350 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
10351 const double c0 = cos(DEG2RAD(met->lat[iy0]));
10352 const double c1 = cos(DEG2RAD(met->lat[iy1]));
10353 const double cr = cos(DEG2RAD(latr));
10354 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
10355
10356 /* Loop over grid points... */
10357 for (int ip = 0; ip < met->np; ip++) {
10358
10359 /* Get gradients in longitude... */
10360 const double dtdx
10361 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
10362 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
10363
10364 /* Get gradients in latitude... */
10365 const double dtdy
10366 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
10367 const double dudy
10368 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
10369
10370 /* Set indices... */
10371 const int ip0 = MAX(ip - 1, 0);
10372 const int ip1 = MIN(ip + 1, met->np - 1);
10373
10374 /* Get gradients in pressure... */
10375 double dtdp, dudp, dvdp;
10376 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
10377 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
10378 if (ip != ip0 && ip != ip1) {
10379 double denom = dp0 * dp1 * (dp0 + dp1);
10380 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
10381 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
10382 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
10383 / denom;
10384 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
10385 - dp1 * dp1 * met->u[ix][iy][ip0]
10386 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
10387 / denom;
10388 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
10389 - dp1 * dp1 * met->v[ix][iy][ip0]
10390 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
10391 / denom;
10392 } else {
10393 const double denom = dp0 + dp1;
10394 dtdp =
10395 (met->t[ix][iy][ip1] * pows[ip1] -
10396 met->t[ix][iy][ip0] * pows[ip0]) / denom;
10397 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
10398 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
10399 }
10400
10401 /* Calculate PV... */
10402 met->pv[ix][iy][ip] = (float)
10403 (1e6 * G0 *
10404 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
10405 }
10406 }
10407 }
10408
10409 /* Fix for polar regions... */
10410#pragma omp parallel for default(shared)
10411 for (int ix = 0; ix < met->nx; ix++)
10412 for (int ip = 0; ip < met->np; ip++) {
10413 met->pv[ix][0][ip]
10414 = met->pv[ix][1][ip]
10415 = met->pv[ix][2][ip];
10416 met->pv[ix][met->ny - 1][ip]
10417 = met->pv[ix][met->ny - 2][ip]
10418 = met->pv[ix][met->ny - 3][ip];
10419 }
10420}
10421
10422/*****************************************************************************/
10423
10425 met_t *met) {
10426
10427 /* Set timer... */
10428 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
10429 LOG(2, "Calculate total column ozone...");
10430
10431 /* Loop over columns... */
10432#pragma omp parallel for default(shared) collapse(2)
10433 for (int ix = 0; ix < met->nx; ix++)
10434 for (int iy = 0; iy < met->ny; iy++) {
10435
10436 /* Integrate... */
10437 double cd = 0;
10438 for (int ip = 1; ip < met->np; ip++)
10439 if (met->p[ip - 1] <= met->ps[ix][iy]) {
10440 const double vmr =
10441 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
10442 const double dp = met->p[ip - 1] - met->p[ip];
10443 cd += vmr * MO3 / MA * dp * 1e2 / G0;
10444 }
10445
10446 /* Convert to Dobson units... */
10447 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
10448 }
10449}
10450
10451/*****************************************************************************/
10452
10454 const ctl_t *ctl,
10455 met_t *met) {
10456
10457 met_t *help;
10458
10459 /* Check parameters... */
10460 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
10461 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
10462 return;
10463
10464 /* Set timer... */
10465 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
10466 LOG(2, "Downsampling of meteo data...");
10467
10468 /* Allocate... */
10469 ALLOC(help, met_t, 1);
10470
10471 /* Copy data... */
10472 help->nx = met->nx;
10473 help->ny = met->ny;
10474 help->np = met->np;
10475 memcpy(help->lon, met->lon, sizeof(met->lon));
10476 memcpy(help->lat, met->lat, sizeof(met->lat));
10477 memcpy(help->p, met->p, sizeof(met->p));
10478
10479 /* Smoothing... */
10480 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
10481 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
10482 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
10483 help->ps[ix][iy] = 0;
10484 help->zs[ix][iy] = 0;
10485 help->ts[ix][iy] = 0;
10486 help->us[ix][iy] = 0;
10487 help->vs[ix][iy] = 0;
10488 help->ess[ix][iy] = 0;
10489 help->nss[ix][iy] = 0;
10490 help->shf[ix][iy] = 0;
10491 help->lsm[ix][iy] = 0;
10492 help->sst[ix][iy] = 0;
10493 help->pbl[ix][iy] = 0;
10494 help->cape[ix][iy] = 0;
10495 help->cin[ix][iy] = 0;
10496 help->t[ix][iy][ip] = 0;
10497 help->u[ix][iy][ip] = 0;
10498 help->v[ix][iy][ip] = 0;
10499 help->w[ix][iy][ip] = 0;
10500 help->h2o[ix][iy][ip] = 0;
10501 help->o3[ix][iy][ip] = 0;
10502 help->lwc[ix][iy][ip] = 0;
10503 help->rwc[ix][iy][ip] = 0;
10504 help->iwc[ix][iy][ip] = 0;
10505 help->swc[ix][iy][ip] = 0;
10506 help->cc[ix][iy][ip] = 0;
10507 float wsum = 0;
10508 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
10509 ix2++) {
10510 int ix3 = ix2;
10511 if (ix3 < 0)
10512 ix3 += met->nx;
10513 else if (ix3 >= met->nx)
10514 ix3 -= met->nx;
10515
10516 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
10517 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
10518 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
10519 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
10520 const float w =
10521 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
10522 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
10523 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
10524 help->ps[ix][iy] += w * met->ps[ix3][iy2];
10525 help->zs[ix][iy] += w * met->zs[ix3][iy2];
10526 help->ts[ix][iy] += w * met->ts[ix3][iy2];
10527 help->us[ix][iy] += w * met->us[ix3][iy2];
10528 help->vs[ix][iy] += w * met->vs[ix3][iy2];
10529 help->ess[ix][iy] += w * met->ess[ix3][iy2];
10530 help->nss[ix][iy] += w * met->nss[ix3][iy2];
10531 help->shf[ix][iy] += w * met->shf[ix3][iy2];
10532 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
10533 help->sst[ix][iy] += w * met->sst[ix3][iy2];
10534 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
10535 help->cape[ix][iy] += w * met->cape[ix3][iy2];
10536 help->cin[ix][iy] += w * met->cin[ix3][iy2];
10537 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
10538 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
10539 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
10540 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
10541 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
10542 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
10543 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
10544 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
10545 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
10546 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
10547 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
10548 wsum += w;
10549 }
10550 }
10551 help->ps[ix][iy] /= wsum;
10552 help->zs[ix][iy] /= wsum;
10553 help->ts[ix][iy] /= wsum;
10554 help->us[ix][iy] /= wsum;
10555 help->vs[ix][iy] /= wsum;
10556 help->ess[ix][iy] /= wsum;
10557 help->nss[ix][iy] /= wsum;
10558 help->shf[ix][iy] /= wsum;
10559 help->lsm[ix][iy] /= wsum;
10560 help->sst[ix][iy] /= wsum;
10561 help->pbl[ix][iy] /= wsum;
10562 help->cape[ix][iy] /= wsum;
10563 help->cin[ix][iy] /= wsum;
10564 help->t[ix][iy][ip] /= wsum;
10565 help->u[ix][iy][ip] /= wsum;
10566 help->v[ix][iy][ip] /= wsum;
10567 help->w[ix][iy][ip] /= wsum;
10568 help->h2o[ix][iy][ip] /= wsum;
10569 help->o3[ix][iy][ip] /= wsum;
10570 help->lwc[ix][iy][ip] /= wsum;
10571 help->rwc[ix][iy][ip] /= wsum;
10572 help->iwc[ix][iy][ip] /= wsum;
10573 help->swc[ix][iy][ip] /= wsum;
10574 help->cc[ix][iy][ip] /= wsum;
10575 }
10576 }
10577 }
10578
10579 /* Downsampling... */
10580 met->nx = 0;
10581 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
10582 met->lon[met->nx] = help->lon[ix];
10583 met->ny = 0;
10584 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
10585 met->lat[met->ny] = help->lat[iy];
10586 met->ps[met->nx][met->ny] = help->ps[ix][iy];
10587 met->zs[met->nx][met->ny] = help->zs[ix][iy];
10588 met->ts[met->nx][met->ny] = help->ts[ix][iy];
10589 met->us[met->nx][met->ny] = help->us[ix][iy];
10590 met->vs[met->nx][met->ny] = help->vs[ix][iy];
10591 met->ess[met->nx][met->ny] = help->ess[ix][iy];
10592 met->nss[met->nx][met->ny] = help->nss[ix][iy];
10593 met->shf[met->nx][met->ny] = help->shf[ix][iy];
10594 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
10595 met->sst[met->nx][met->ny] = help->sst[ix][iy];
10596 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
10597 met->cape[met->nx][met->ny] = help->cape[ix][iy];
10598 met->cin[met->nx][met->ny] = help->cin[ix][iy];
10599 met->np = 0;
10600 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
10601 met->p[met->np] = help->p[ip];
10602 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
10603 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
10604 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
10605 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
10606 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
10607 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
10608 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
10609 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
10610 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
10611 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
10612 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
10613 met->np++;
10614 }
10615 met->ny++;
10616 }
10617 met->nx++;
10618 }
10619
10620 /* Free... */
10621 free(help);
10622}
10623
10624/*****************************************************************************/
10625
10627 const ctl_t *ctl,
10628 const clim_t *clim,
10629 met_t *met) {
10630
10631 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
10632 th2[200], z[EP], z2[200];
10633
10634 /* Set timer... */
10635 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
10636 LOG(2, "Calculate tropopause...");
10637
10638 /* Get altitude and pressure profiles... */
10639#pragma omp parallel for default(shared)
10640 for (int iz = 0; iz < met->np; iz++)
10641 z[iz] = Z(met->p[iz]);
10642#pragma omp parallel for default(shared)
10643 for (int iz = 0; iz <= 190; iz++) {
10644 z2[iz] = 4.5 + 0.1 * iz;
10645 p2[iz] = P(z2[iz]);
10646 }
10647
10648 /* Do not calculate tropopause... */
10649 if (ctl->met_tropo == 0)
10650#pragma omp parallel for default(shared) collapse(2)
10651 for (int ix = 0; ix < met->nx; ix++)
10652 for (int iy = 0; iy < met->ny; iy++)
10653 met->pt[ix][iy] = NAN;
10654
10655 /* Use tropopause climatology... */
10656 else if (ctl->met_tropo == 1) {
10657#pragma omp parallel for default(shared) collapse(2)
10658 for (int ix = 0; ix < met->nx; ix++)
10659 for (int iy = 0; iy < met->ny; iy++)
10660 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
10661 }
10662
10663 /* Use cold point... */
10664 else if (ctl->met_tropo == 2) {
10665
10666 /* Loop over grid points... */
10667#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10668 for (int ix = 0; ix < met->nx; ix++)
10669 for (int iy = 0; iy < met->ny; iy++) {
10670
10671 /* Interpolate temperature profile... */
10672 for (int iz = 0; iz < met->np; iz++)
10673 t[iz] = met->t[ix][iy][iz];
10674 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
10675
10676 /* Find minimum... */
10677 int iz = (int) gsl_stats_min_index(t2, 1, 171);
10678 if (iz > 0 && iz < 170)
10679 met->pt[ix][iy] = (float) p2[iz];
10680 else
10681 met->pt[ix][iy] = NAN;
10682 }
10683 }
10684
10685 /* Use WMO definition... */
10686 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
10687
10688 /* Loop over grid points... */
10689#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10690 for (int ix = 0; ix < met->nx; ix++)
10691 for (int iy = 0; iy < met->ny; iy++) {
10692
10693 /* Interpolate temperature profile... */
10694 int iz;
10695 for (iz = 0; iz < met->np; iz++)
10696 t[iz] = met->t[ix][iy][iz];
10697 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
10698
10699 /* Find 1st tropopause... */
10700 met->pt[ix][iy] = NAN;
10701 for (iz = 0; iz <= 170; iz++) {
10702 int found = 1;
10703 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10704 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10705 found = 0;
10706 break;
10707 }
10708 if (found) {
10709 if (iz > 0 && iz < 170)
10710 met->pt[ix][iy] = (float) p2[iz];
10711 break;
10712 }
10713 }
10714
10715 /* Find 2nd tropopause... */
10716 if (ctl->met_tropo == 4) {
10717 met->pt[ix][iy] = NAN;
10718 for (; iz <= 170; iz++) {
10719 int found = 1;
10720 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
10721 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
10722 found = 0;
10723 break;
10724 }
10725 if (found)
10726 break;
10727 }
10728 for (; iz <= 170; iz++) {
10729 int found = 1;
10730 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10731 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10732 found = 0;
10733 break;
10734 }
10735 if (found) {
10736 if (iz > 0 && iz < 170)
10737 met->pt[ix][iy] = (float) p2[iz];
10738 break;
10739 }
10740 }
10741 }
10742 }
10743 }
10744
10745 /* Use dynamical tropopause... */
10746 else if (ctl->met_tropo == 5) {
10747
10748 /* Loop over grid points... */
10749#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
10750 for (int ix = 0; ix < met->nx; ix++)
10751 for (int iy = 0; iy < met->ny; iy++) {
10752
10753 /* Interpolate potential vorticity profile... */
10754 for (int iz = 0; iz < met->np; iz++)
10755 pv[iz] = met->pv[ix][iy][iz];
10756 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
10757
10758 /* Interpolate potential temperature profile... */
10759 for (int iz = 0; iz < met->np; iz++)
10760 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
10761 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
10762
10763 /* Find dynamical tropopause... */
10764 met->pt[ix][iy] = NAN;
10765 for (int iz = 0; iz <= 170; iz++)
10766 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
10767 || th2[iz] >= ctl->met_tropo_theta) {
10768 if (iz > 0 && iz < 170)
10769 met->pt[ix][iy] = (float) p2[iz];
10770 break;
10771 }
10772 }
10773 }
10774
10775 else
10776 ERRMSG("Cannot calculate tropopause!");
10777
10778 /* Interpolate temperature, geopotential height, and water vapor... */
10779#pragma omp parallel for default(shared) collapse(2)
10780 for (int ix = 0; ix < met->nx; ix++)
10781 for (int iy = 0; iy < met->ny; iy++) {
10782 double h2ot, tt, zt;
10784 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
10785 met->lat[iy], &tt, ci, cw, 1);
10786 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
10787 met->lat[iy], &zt, ci, cw, 0);
10788 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
10789 met->lat[iy], &h2ot, ci, cw, 0);
10790 met->tt[ix][iy] = (float) tt;
10791 met->zt[ix][iy] = (float) zt;
10792 met->h2ot[ix][iy] = (float) h2ot;
10793 }
10794}
10795
10796/*****************************************************************************/
10797
10799 const char *filename,
10800 const ctl_t *ctl,
10801 double *rt,
10802 double *rz,
10803 double *rlon,
10804 double *rlat,
10805 double *robs,
10806 int *nobs) {
10807
10808 /* Write info... */
10809 LOG(1, "Read observation data: %s", filename);
10810
10811 /* Read data... */
10812 if (ctl->obs_type == 0)
10813 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
10814 else if (ctl->obs_type == 1)
10815 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
10816 else
10817 ERRMSG("Set OBS_TYPE to 0 or 1!");
10818
10819 /* Check time... */
10820 for (int i = 1; i < *nobs; i++)
10821 if (rt[i] < rt[i - 1])
10822 ERRMSG("Time must be ascending!");
10823
10824 /* Write info... */
10825 int n = *nobs;
10826 double mini, maxi;
10827 LOG(2, "Number of observations: %d", *nobs);
10828 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
10829 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
10830 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
10831 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
10832 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
10833 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
10834 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
10835 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
10836 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
10837 LOG(2, "Observation range: %g ... %g", mini, maxi);
10838}
10839
10840/*****************************************************************************/
10841
10843 const char *filename,
10844 double *rt,
10845 double *rz,
10846 double *rlon,
10847 double *rlat,
10848 double *robs,
10849 int *nobs) {
10850
10851 /* Open observation data file... */
10852 FILE *in;
10853 if (!(in = fopen(filename, "r")))
10854 ERRMSG("Cannot open file!");
10855
10856 /* Read observations... */
10857 char line[LEN];
10858 while (fgets(line, LEN, in))
10859 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
10860 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
10861 if ((++(*nobs)) >= NOBS)
10862 ERRMSG("Too many observations!");
10863
10864 /* Close observation data file... */
10865 fclose(in);
10866}
10867
10868/*****************************************************************************/
10869
10871 const char *filename,
10872 double *rt,
10873 double *rz,
10874 double *rlon,
10875 double *rlat,
10876 double *robs,
10877 int *nobs) {
10878
10879 int ncid, varid;
10880
10881 /* Open netCDF file... */
10882 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
10883 ERRMSG("Cannot open file!");
10884
10885 /* Read the observations from the NetCDF file... */
10886 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
10887 NC_GET_DOUBLE("time", rt, 1);
10888 NC_GET_DOUBLE("alt", rz, 1);
10889 NC_GET_DOUBLE("lon", rlon, 1);
10890 NC_GET_DOUBLE("lat", rlat, 1);
10891 NC_GET_DOUBLE("obs", robs, 1);
10892
10893 /* Close file... */
10894 NC(nc_close(ncid));
10895}
10896
10897/*****************************************************************************/
10898
10900 const char *filename,
10901 int argc,
10902 char *argv[],
10903 const char *varname,
10904 const int arridx,
10905 const char *defvalue,
10906 char *value) {
10907
10908 FILE *in = NULL;
10909
10910 char fullname1[LEN], fullname2[LEN], rval[LEN];
10911
10912 int contain = 0, i;
10913
10914 /* Open file... */
10915 if (filename[strlen(filename) - 1] != '-')
10916 if (!(in = fopen(filename, "r")))
10917 ERRMSG("Cannot open file!");
10918
10919 /* Set full variable name... */
10920 if (arridx >= 0) {
10921 sprintf(fullname1, "%s[%d]", varname, arridx);
10922 sprintf(fullname2, "%s[*]", varname);
10923 } else {
10924 sprintf(fullname1, "%s", varname);
10925 sprintf(fullname2, "%s", varname);
10926 }
10927
10928 /* Read data... */
10929 if (in != NULL) {
10930 char dummy[LEN], line[LEN], rvarname[LEN];
10931 while (fgets(line, LEN, in)) {
10932 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
10933 if (strcasecmp(rvarname, fullname1) == 0 ||
10934 strcasecmp(rvarname, fullname2) == 0) {
10935 contain = 1;
10936 break;
10937 }
10938 }
10939 }
10940 for (i = 1; i < argc - 1; i++)
10941 if (strcasecmp(argv[i], fullname1) == 0 ||
10942 strcasecmp(argv[i], fullname2) == 0) {
10943 sprintf(rval, "%s", argv[i + 1]);
10944 contain = 1;
10945 break;
10946 }
10947
10948 /* Close file... */
10949 if (in != NULL)
10950 fclose(in);
10951
10952 /* Check for missing variables... */
10953 if (!contain) {
10954 if (strlen(defvalue) > 0)
10955 sprintf(rval, "%s", defvalue);
10956 else
10957 ERRMSG("Missing variable %s!\n", fullname1);
10958 }
10959
10960 /* Write info... */
10961 LOG(1, "%s = %s", fullname1, rval);
10962
10963 /* Return values... */
10964 if (value != NULL)
10965 sprintf(value, "%s", rval);
10966 return atof(rval);
10967}
10968
10969/*****************************************************************************/
10970
10971double sedi(
10972 const double p,
10973 const double T,
10974 const double rp,
10975 const double rhop) {
10976
10977 /* Convert particle radius from microns to m... */
10978 const double rp_help = rp * 1e-6;
10979
10980 /* Density of dry air [kg / m^3]... */
10981 const double rho = RHO(p, T);
10982
10983 /* Dynamic viscosity of air [kg / (m s)]... */
10984 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
10985
10986 /* Thermal velocity of an air molecule [m / s]... */
10987 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
10988
10989 /* Mean free path of an air molecule [m]... */
10990 const double lambda = 2. * eta / (rho * v);
10991
10992 /* Knudsen number for air (dimensionless)... */
10993 const double K = lambda / rp_help;
10994
10995 /* Cunningham slip-flow correction (dimensionless)... */
10996 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
10997
10998 /* Sedimentation velocity [m / s]... */
10999 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
11000}
11001
11002/*****************************************************************************/
11003
11005 const double *x,
11006 const double *y,
11007 const int n,
11008 const double *x2,
11009 double *y2,
11010 const int n2,
11011 const int method) {
11012
11013 /* Cubic spline interpolation... */
11014 if (method == 1) {
11015
11016 /* Allocate... */
11017 gsl_interp_accel *acc = gsl_interp_accel_alloc();
11018 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
11019
11020 /* Interpolate profile... */
11021 gsl_spline_init(s, x, y, (size_t) n);
11022 for (int i = 0; i < n2; i++)
11023 if (x2[i] <= x[0])
11024 y2[i] = y[0];
11025 else if (x2[i] >= x[n - 1])
11026 y2[i] = y[n - 1];
11027 else
11028 y2[i] = gsl_spline_eval(s, x2[i], acc);
11029
11030 /* Free... */
11031 gsl_spline_free(s);
11032 gsl_interp_accel_free(acc);
11033 }
11034
11035 /* Linear interpolation... */
11036 else {
11037 for (int i = 0; i < n2; i++)
11038 if (x2[i] <= x[0])
11039 y2[i] = y[0];
11040 else if (x2[i] >= x[n - 1])
11041 y2[i] = y[n - 1];
11042 else {
11043 const int idx = locate_irr(x, n, x2[i]);
11044 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
11045 }
11046 }
11047}
11048
11049/*****************************************************************************/
11050
11052 const float *data,
11053 const int n) {
11054
11055 if (n <= 0)
11056 return 0;
11057
11058 float mean = 0, var = 0;
11059
11060 for (int i = 0; i < n; ++i) {
11061 mean += data[i];
11062 var += SQR(data[i]);
11063 }
11064
11065 var = var / (float) n - SQR(mean / (float) n);
11066
11067 return (var > 0 ? sqrtf(var) : 0);
11068}
11069
11070/*****************************************************************************/
11071
11073 const double sec,
11074 const double lon,
11075 const double lat) {
11076
11077 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
11078 const double D = sec / 86400 - 0.5;
11079
11080 /* Geocentric apparent ecliptic longitude [rad]... */
11081 const double g = DEG2RAD(357.529 + 0.98560028 * D);
11082 const double q = 280.459 + 0.98564736 * D;
11083 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
11084
11085 /* Mean obliquity of the ecliptic [rad]... */
11086 const double e = DEG2RAD(23.439 - 0.00000036 * D);
11087
11088 /* Declination [rad]... */
11089 const double sindec = sin(e) * sin(L);
11090
11091 /* Right ascension [rad]... */
11092 const double ra = atan2(cos(e) * sin(L), cos(L));
11093
11094 /* Greenwich Mean Sidereal Time [h]... */
11095 const double GMST = 18.697374558 + 24.06570982441908 * D;
11096
11097 /* Local Sidereal Time [h]... */
11098 const double LST = GMST + lon / 15;
11099
11100 /* Hour angle [rad]... */
11101 const double h = LST / 12 * M_PI - ra;
11102
11103 /* Convert latitude... */
11104 const double lat_help = DEG2RAD(lat);
11105
11106 /* Return solar zenith angle [rad]... */
11107 return acos(sin(lat_help) * sindec +
11108 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
11109}
11110
11111/*****************************************************************************/
11112
11114 const int year,
11115 const int mon,
11116 const int day,
11117 const int hour,
11118 const int min,
11119 const int sec,
11120 const double remain,
11121 double *jsec) {
11122
11123 struct tm t0, t1;
11124
11125 t0.tm_year = 100;
11126 t0.tm_mon = 0;
11127 t0.tm_mday = 1;
11128 t0.tm_hour = 0;
11129 t0.tm_min = 0;
11130 t0.tm_sec = 0;
11131
11132 t1.tm_year = year - 1900;
11133 t1.tm_mon = mon - 1;
11134 t1.tm_mday = day;
11135 t1.tm_hour = hour;
11136 t1.tm_min = min;
11137 t1.tm_sec = sec;
11138
11139 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
11140}
11141
11142/*****************************************************************************/
11143
11145 const char *name,
11146 const char *group,
11147 const int output) {
11148
11149 static char names[NTIMER][100], groups[NTIMER][100];
11150
11151 static double rt_name[NTIMER], rt_group[NTIMER],
11152 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
11153
11154 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
11155
11156 /* Get time... */
11157 t1 = omp_get_wtime();
11158 dt = t1 - t0;
11159
11160 /* Add elapsed time to current timers... */
11161 if (iname >= 0) {
11162 rt_name[iname] += dt;
11163 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
11164 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
11165 ct_name[iname]++;
11166 }
11167 if (igroup >= 0)
11168 rt_group[igroup] += t1 - t0;
11169
11170 /* Report timers... */
11171 if (output) {
11172 for (int i = 0; i < nname; i++)
11173 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
11174 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
11175 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
11176 for (int i = 0; i < ngroup; i++)
11177 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
11178 double total = 0.0;
11179 for (int i = 0; i < nname; i++)
11180 total += rt_name[i];
11181 LOG(1, "TIMER_TOTAL = %.3f s", total);
11182 }
11183
11184 /* Identify IDs of next timer... */
11185 for (iname = 0; iname < nname; iname++)
11186 if (strcasecmp(name, names[iname]) == 0)
11187 break;
11188 for (igroup = 0; igroup < ngroup; igroup++)
11189 if (strcasecmp(group, groups[igroup]) == 0)
11190 break;
11191
11192 /* Check whether this is a new timer... */
11193 if (iname >= nname) {
11194 sprintf(names[iname], "%s", name);
11195 if ((++nname) >= NTIMER)
11196 ERRMSG("Too many timers!");
11197 }
11198
11199 /* Check whether this is a new group... */
11200 if (igroup >= ngroup) {
11201 sprintf(groups[igroup], "%s", group);
11202 if ((++ngroup) >= NTIMER)
11203 ERRMSG("Too many groups!");
11204 }
11205
11206 /* Save starting time... */
11207 t0 = t1;
11208}
11209
11210/*****************************************************************************/
11211
11213 const char *filename,
11214 const int offset) {
11215
11216 char tstr[10];
11217
11218 double t;
11219
11220 /* Get time from filename... */
11221 int len = (int) strlen(filename);
11222 sprintf(tstr, "%.4s", &filename[len - offset]);
11223 int year = atoi(tstr);
11224 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
11225 int mon = atoi(tstr);
11226 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
11227 int day = atoi(tstr);
11228 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
11229 int hour = atoi(tstr);
11230 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
11231 int min = atoi(tstr);
11232
11233 /* Check time... */
11234 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
11235 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
11236 ERRMSG("Cannot read time from filename!");
11237
11238 /* Convert time to Julian seconds... */
11239 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
11240
11241 /* Return time... */
11242 return t;
11243}
11244
11245/*****************************************************************************/
11246
11248 const clim_t *clim,
11249 const atm_t *atm,
11250 const int ip) {
11251
11252 /* Get tropopause pressure... */
11253 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
11254
11255 /* Get pressure range... */
11256 const double p1 = pt * 0.866877899;
11257 const double p0 = pt / 0.866877899;
11258
11259 /* Get weighting factor... */
11260 if (atm->p[ip] > p0)
11261 return 1;
11262 else if (atm->p[ip] < p1)
11263 return 0;
11264 else
11265 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
11266}
11267
11268/*****************************************************************************/
11269
11271 const char *filename,
11272 const ctl_t *ctl,
11273 const atm_t *atm,
11274 const double t) {
11275
11276 FILE *out;
11277
11278 /* Set time interval for output... */
11279 const double t0 = t - 0.5 * ctl->dt_mod;
11280 const double t1 = t + 0.5 * ctl->dt_mod;
11281
11282 /* Check if gnuplot output is requested... */
11283 if (ctl->atm_gpfile[0] != '-') {
11284
11285 /* Create gnuplot pipe... */
11286 if (!(out = popen("gnuplot", "w")))
11287 ERRMSG("Cannot create pipe to gnuplot!");
11288
11289 /* Set plot filename... */
11290 fprintf(out, "set out \"%s.png\"\n", filename);
11291
11292 /* Set time string... */
11293 double r;
11294 int year, mon, day, hour, min, sec;
11295 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11296 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
11297 year, mon, day, hour, min);
11298
11299 /* Dump gnuplot file to pipe... */
11300 FILE *in;
11301 if (!(in = fopen(ctl->atm_gpfile, "r")))
11302 ERRMSG("Cannot open file!");
11303 char line[LEN];
11304 while (fgets(line, LEN, in))
11305 fprintf(out, "%s", line);
11306 fclose(in);
11307 }
11308
11309 else {
11310
11311 /* Create file... */
11312 if (!(out = fopen(filename, "w")))
11313 ERRMSG("Cannot create file!");
11314 }
11315
11316 /* Write header... */
11317 fprintf(out,
11318 "# $1 = time [s]\n"
11319 "# $2 = altitude [km]\n"
11320 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11321 for (int iq = 0; iq < ctl->nq; iq++)
11322 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
11323 ctl->qnt_unit[iq]);
11324 fprintf(out, "\n");
11325
11326 /* Write data... */
11327 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
11328
11329 /* Check time... */
11330 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11331 continue;
11332
11333 /* Write output... */
11334 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
11335 atm->lon[ip], atm->lat[ip]);
11336 for (int iq = 0; iq < ctl->nq; iq++) {
11337 fprintf(out, " ");
11338 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11339 fprintf(out, ctl->qnt_format[iq], NAN);
11340 else
11341 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11342 }
11343 fprintf(out, "\n");
11344 }
11345
11346 /* Close file... */
11347 fclose(out);
11348}
11349
11350/*****************************************************************************/
11351
11353 const char *filename,
11354 const ctl_t *ctl,
11355 const atm_t *atm) {
11356
11357 FILE *out;
11358
11359 /* Create file... */
11360 if (!(out = fopen(filename, "w")))
11361 ERRMSG("Cannot create file!");
11362
11363 /* Write version of binary data... */
11364 int version = 100;
11365 FWRITE(&version, int,
11366 1,
11367 out);
11368
11369 /* Write data... */
11370 FWRITE(&atm->np, int,
11371 1,
11372 out);
11373 FWRITE(atm->time, double,
11374 (size_t) atm->np,
11375 out);
11376 FWRITE(atm->p, double,
11377 (size_t) atm->np,
11378 out);
11379 FWRITE(atm->lon, double,
11380 (size_t) atm->np,
11381 out);
11382 FWRITE(atm->lat, double,
11383 (size_t) atm->np,
11384 out);
11385 for (int iq = 0; iq < ctl->nq; iq++)
11386 FWRITE(atm->q[iq], double,
11387 (size_t) atm->np,
11388 out);
11389
11390 /* Write final flag... */
11391 int final = 999;
11392 FWRITE(&final, int,
11393 1,
11394 out);
11395
11396 /* Close file... */
11397 fclose(out);
11398}
11399
11400/*****************************************************************************/
11401
11403 const char *filename,
11404 const ctl_t *ctl,
11405 const atm_t *atm) {
11406
11407 int tid, pid, ncid, varid;
11408 size_t start[2], count[2];
11409
11410 /* Create file... */
11411 nc_create(filename, NC_NETCDF4, &ncid);
11412
11413 /* Define dimensions... */
11414 NC(nc_def_dim(ncid, "time", 1, &tid));
11415 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11416
11417 /* Define variables and their attributes... */
11418 int dim_ids[2] = { tid, pid };
11419 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11420 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11421 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11422 ctl->atm_nc_level, 0);
11423 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11424 ctl->atm_nc_level, 0);
11425 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11426 ctl->atm_nc_level, 0);
11427 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11428 for (int iq = 0; iq < ctl->nq; iq++)
11429 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11430 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11431 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11432
11433 /* Define global attributes... */
11434 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11435 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11436
11437 /* End definitions... */
11438 NC(nc_enddef(ncid));
11439
11440 /* Write data... */
11441 NC_PUT_DOUBLE("time", atm->time, 0);
11442 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11443 NC_PUT_DOUBLE("LON", atm->lon, 0);
11444 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11445 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11446 for (int iq = 0; iq < ctl->nq; iq++)
11447 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11448
11449 /* Close file... */
11450 NC(nc_close(ncid));
11451}
11452
11453/*****************************************************************************/
11454
11456 const char *dirname,
11457 const ctl_t *ctl,
11458 const atm_t *atm,
11459 const double t) {
11460
11461 /* Global Counter... */
11462 static size_t out_cnt = 0;
11463
11464 double r, r_start, r_stop;
11465 int year, mon, day, hour, min, sec;
11466 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
11467 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
11468 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
11469
11470 int ncid, varid, tid, pid, cid;
11471 int dim_ids[2];
11472
11473 /* time, nparc */
11474 size_t start[2];
11475 size_t count[2];
11476
11477 /* Determine start and stop times of calculation... */
11478 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11479 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
11480 &min_start, &sec_start, &r_start);
11481 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
11482 &min_stop, &sec_stop, &r_stop);
11483
11484 sprintf(filename_out,
11485 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
11486 year_start % 100, mon_start, day_start, hour_start,
11487 year_stop % 100, mon_stop, day_stop, hour_stop);
11488 LOG(1, "Write traj file: %s", filename_out);
11489
11490 /* Define hyperslap for the traj_file... */
11491 start[0] = out_cnt;
11492 start[1] = 0;
11493 count[0] = 1;
11494 count[1] = (size_t) atm->np;
11495
11496 /* Create the file at the first timestep... */
11497 if (out_cnt == 0) {
11498
11499 /* Create file... */
11500 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
11501
11502 /* Define dimensions... */
11503 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
11504 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11505 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
11506 dim_ids[0] = tid;
11507 dim_ids[1] = pid;
11508
11509 /* Define variables and their attributes... */
11510 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11511 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11512 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
11513 ctl->atm_nc_level, 0);
11514 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
11515 ctl->atm_nc_level, 0);
11516 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
11517 ctl->atm_nc_level, 0);
11518 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
11519 ctl->atm_nc_level, 0);
11520 for (int iq = 0; iq < ctl->nq; iq++)
11521 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11522 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11523 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11524
11525 /* Define global attributes... */
11526 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11527 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11528
11529 /* End definitions... */
11530 NC(nc_enddef(ncid));
11531 NC(nc_close(ncid));
11532 }
11533
11534 /* Increment global counter to change hyperslap... */
11535 out_cnt++;
11536
11537 /* Open file... */
11538 NC(nc_open(filename_out, NC_WRITE, &ncid));
11539
11540 /* Write data... */
11541 NC_PUT_DOUBLE("time", atm->time, 1);
11542 NC_PUT_DOUBLE("LAT", atm->lat, 1);
11543 NC_PUT_DOUBLE("LON", atm->lon, 1);
11544 NC_PUT_DOUBLE("PRESS", atm->p, 1);
11545 if (ctl->advect_vert_coord == 1) {
11546 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
11547 } else if (ctl->qnt_zeta >= 0) {
11548 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
11549 }
11550 for (int iq = 0; iq < ctl->nq; iq++)
11551 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
11552
11553 /* Close file... */
11554 NC(nc_close(ncid));
11555
11556 /* At the last time step create the init_fix_YYYYMMDDHH file... */
11557 if ((year == year_stop) && (mon == mon_stop)
11558 && (day == day_stop) && (hour == hour_stop)) {
11559
11560 /* Set filename... */
11561 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
11562 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
11563 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
11564 LOG(1, "Write init file: %s", filename_init);
11565
11566 /* Create file... */
11567 nc_create(filename_init, NC_NETCDF4, &ncid);
11568
11569 /* Define dimensions... */
11570 NC(nc_def_dim(ncid, "time", 1, &tid));
11571 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11572 dim_ids[0] = tid;
11573 dim_ids[1] = pid;
11574
11575 /* Define variables and their attributes... */
11576 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11577 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11578 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11579 ctl->atm_nc_level, 0);
11580 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11581 ctl->atm_nc_level, 0);
11582 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11583 ctl->atm_nc_level, 0);
11584 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11585 for (int iq = 0; iq < ctl->nq; iq++)
11586 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11587 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11588 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11589
11590 /* Define global attributes... */
11591 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11592 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11593
11594 /* End definitions... */
11595 NC(nc_enddef(ncid));
11596
11597 /* Write data... */
11598 NC_PUT_DOUBLE("time", atm->time, 0);
11599 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11600 NC_PUT_DOUBLE("LON", atm->lon, 0);
11601 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11602 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11603 for (int iq = 0; iq < ctl->nq; iq++)
11604 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11605
11606 /* Close file... */
11607 NC(nc_close(ncid));
11608 }
11609}
11610
11611/*****************************************************************************/
11612
11614 const char *filename,
11615 const ctl_t *ctl,
11616 const atm_t *atm) {
11617
11618 int ncid, obsid, varid;
11619
11620 size_t start[2], count[2];
11621
11622 /* Create file... */
11623 NC(nc_create(filename, NC_NETCDF4, &ncid));
11624
11625 /* Define dimensions... */
11626 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
11627
11628 /* Define variables and their attributes... */
11629 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
11630 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11631 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
11632 ctl->atm_nc_level, 0);
11633 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
11634 ctl->atm_nc_level, 0);
11635 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
11636 ctl->atm_nc_level, 0);
11637 for (int iq = 0; iq < ctl->nq; iq++)
11638 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
11639 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
11640 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11641
11642 /* Define global attributes... */
11643 NC_PUT_ATT_GLOBAL("featureType", "point");
11644
11645 /* End definitions... */
11646 NC(nc_enddef(ncid));
11647
11648 /* Write data... */
11649 NC_PUT_DOUBLE("time", atm->time, 0);
11650 NC_PUT_DOUBLE("press", atm->p, 0);
11651 NC_PUT_DOUBLE("lon", atm->lon, 0);
11652 NC_PUT_DOUBLE("lat", atm->lat, 0);
11653 for (int iq = 0; iq < ctl->nq; iq++)
11654 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11655
11656 /* Close file... */
11657 NC(nc_close(ncid));
11658}
11659
11660/*****************************************************************************/
11661
11663 const char *filename,
11664 const ctl_t *ctl,
11665 const atm_t *atm,
11666 const double t) {
11667
11668 static FILE *out;
11669
11670 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
11671 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
11672
11673 static int *obscount, nobs, nk;
11674
11675 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
11676
11677 const int ensemble = (ctl->nens > 0);
11678
11679 /* Set timer */
11680 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
11681
11682 /* Check quantities... */
11683 if (ctl->qnt_m < 0)
11684 ERRMSG("Need quantity mass!");
11685 if (ensemble) {
11686 if (ctl->qnt_ens < 0)
11687 ERRMSG("Missing ensemble IDs!");
11688 if (ctl->nens > NENS)
11689 ERRMSG("Too many ensembles!");
11690 }
11691
11692 /* Init... */
11693 if (t == ctl->t_start) {
11694
11695 /* Allocate.. */
11696 ALLOC(area, double,
11697 ctl->csi_ny);
11698 ALLOC(rt, double,
11699 NOBS);
11700 ALLOC(rz, double,
11701 NOBS);
11702 ALLOC(rlon, double,
11703 NOBS);
11704 ALLOC(rlat, double,
11705 NOBS);
11706 ALLOC(robs, double,
11707 NOBS);
11708
11709 /* Read observation data... */
11710 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11711
11712 /* Read kernel data... */
11713 if (ctl->csi_kernel[0] != '-')
11714 read_kernel(ctl->csi_kernel, kz, kw, &nk);
11715
11716 /* Create new file... */
11717 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
11718 if (!(out = fopen(filename, "w")))
11719 ERRMSG("Cannot create file!");
11720
11721 /* Write header... */
11722 fprintf(out,
11723 "# $1 = time [s]\n"
11724 "# $2 = ensemble ID\n"
11725 "# $3 = number of hits (cx)\n"
11726 "# $4 = number of misses (cy)\n"
11727 "# $5 = number of false alarms (cz)\n"
11728 "# $6 = number of observations (cx + cy)\n"
11729 "# $7 = number of forecasts (cx + cz)\n"
11730 "# $8 = bias (%%)\n"
11731 "# $9 = POD (%%)\n"
11732 "# $10 = FAR (%%)\n"
11733 "# $11 = CSI (%%)\n"
11734 "# $12 = hits by random chance\n"
11735 "# $13 = ETS (%%)\n"
11736 "# $14 = Pearson R\n"
11737 "# $15 = Spearman R\n"
11738 "# $16 = mean error [kg/m²]\n"
11739 "# $17 = RMSE [kg/m²]\n"
11740 "# $18 = MAE [kg/m²]\n"
11741 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
11742
11743 /* Set grid box size... */
11744 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
11745 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
11746 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
11747
11748 /* Set horizontal coordinates... */
11749 for (int iy = 0; iy < ctl->csi_ny; iy++) {
11750 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
11751 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
11752 }
11753 }
11754
11755 /* Set time interval... */
11756 const double t0 = t - 0.5 * ctl->dt_mod;
11757 const double t1 = t + 0.5 * ctl->dt_mod;
11758
11759 /* Allocate... */
11760 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
11761 ALLOC(modmean, double,
11762 (ensemble ? ctl->nens : 1) * grid_size);
11763 ALLOC(obsmean, double,
11764 grid_size);
11765 ALLOC(obscount, int,
11766 grid_size);
11767 ALLOC(obsstd, double,
11768 grid_size);
11769
11770 /* Init... */
11771 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
11772 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
11773
11774 /* Loop over observations... */
11775 for (int i = 0; i < nobs; i++) {
11776 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
11777 continue;
11778
11779 /* Calculate indices... */
11780 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
11781 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
11782 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
11783 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11784 || iz >= ctl->csi_nz)
11785 continue;
11786
11787 /* Get mean observation index... */
11788 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11789 obsmean[idx] += robs[i];
11790 obsstd[idx] += SQR(robs[i]);
11791 obscount[idx]++;
11792 }
11793
11794 /* Analyze model data... */
11795 for (int ip = 0; ip < atm->np; ip++) {
11796
11797 /* Check time... */
11798 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11799 continue;
11800
11801 /* Get ensemble ID... */
11802 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
11803 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
11804 ERRMSG("Ensemble ID out of range!");
11805
11806 /* Get indices... */
11807 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
11808 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
11809 const int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
11810 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11811 || iz >= ctl->csi_nz)
11812 continue;
11813
11814 /* Get total mass in grid cell... */
11815 const int idx =
11816 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11817 modmean[idx] +=
11818 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11819 }
11820 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11821 /* Analyze all grid cells... */
11822 for (int ix = 0; ix < ctl->csi_nx; ix++)
11823 for (int iy = 0; iy < ctl->csi_ny; iy++)
11824 for (int iz = 0; iz < ctl->csi_nz; iz++) {
11825
11826 /* Calculate mean observation index... */
11827 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11828 if (e == 0)
11829 if (obscount[idx]) {
11830 obsmean[idx] /= obscount[idx];
11831 obsstd[idx] =
11832 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
11833 }
11834
11835 /* Calculate model mean per ensemble... */
11836 const int midx = e * grid_size + idx;
11837 if (modmean[midx] > 0)
11838 modmean[midx] /= (1e6 * area[iy]);
11839
11840 /* Check number of observations... */
11841 if (obscount[idx]) {
11842
11843 /* Calculate CSI... */
11844 ct[e]++;
11845 if (obsmean[idx] >= ctl->csi_obsmin
11846 && modmean[midx] >= ctl->csi_modmin)
11847 cx[e]++;
11848 else if (obsmean[idx] >= ctl->csi_obsmin)
11849 cy[e]++;
11850 else if (modmean[midx] >= ctl->csi_modmin)
11851 cz[e]++;
11852
11853 /* Save data for other verification statistics... */
11854 if (obsmean[idx] >= ctl->csi_obsmin
11855 || modmean[midx] >= ctl->csi_modmin) {
11856 x[n[e]] = modmean[midx];
11857 y[n[e]] = obsmean[idx];
11858 if (modmean[midx] >= ctl->csi_modmin)
11859 obsstdn[n[e]] = obsstd[idx];
11860 if ((++n[e]) >= NCSI)
11861 ERRMSG("Too many points for statistics!");
11862 }
11863 }
11864 }
11865 /* Write output... */
11866 if (fmod(t, ctl->csi_dt_out) == 0) {
11867
11868 if (n[e] == 0)
11869 continue;
11870
11871 /* Calculate verification statistics
11872 (https://www.cawcr.gov.au/projects/verification/) ... */
11873 static double work[2 * NCSI], work2[2 * NCSI];
11874 const int n_obs = cx[e] + cy[e];
11875 const int n_for = cx[e] + cz[e];
11876 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
11877 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
11878 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
11879 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
11880 const double csi =
11881 (cx[e] + cy[e] + cz[e] >
11882 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
11883 const double ets =
11884 (cx[e] + cy[e] + cz[e] - cx_rd >
11885 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
11886 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
11887 const double rho_s =
11888 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
11889 for (int i = 0; i < n[e]; i++) {
11890 work[i] = x[i] - y[i];
11891 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
11892 }
11893 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
11894 const double rmse =
11895 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
11896 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
11897 const double loglikelihood =
11898 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
11899
11900 /* Write... */
11901 fprintf(out,
11902 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
11903 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
11904 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
11905 loglikelihood, n[e]);
11906
11907 /* Set counters to zero... */
11908 for (int i = 0; i < n[e]; i++)
11909 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
11910 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
11911 }
11912 }
11913 /* Free... */
11914 free(modmean);
11915 free(obsmean);
11916 free(obscount);
11917 free(obsstd);
11918
11919 /* Finalize... */
11920 if (t == ctl->t_stop) {
11921
11922 /* Close output file... */
11923 fclose(out);
11924
11925 /* Free... */
11926 free(area);
11927 free(rt);
11928 free(rz);
11929 free(rlon);
11930 free(rlat);
11931 free(robs);
11932 }
11933}
11934
11935/*****************************************************************************/
11936
11938 const char *filename,
11939 const ctl_t *ctl,
11940 const atm_t *atm,
11941 const double t) {
11942
11943 static FILE *out;
11944
11945 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
11946 x[3], zm[NENS];
11947
11948 static int n[NENS];
11949
11950 /* Set timer... */
11951 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
11952
11953 /* Check quantities... */
11954 if (ctl->qnt_ens < 0)
11955 ERRMSG("Missing ensemble IDs!");
11956
11957 /* Set time interval... */
11958 const double t0 = t - 0.5 * ctl->dt_mod;
11959 const double t1 = t + 0.5 * ctl->dt_mod;
11960
11961 /* Init... */
11962 for (int i = 0; i < NENS; i++) {
11963 for (int iq = 0; iq < ctl->nq; iq++)
11964 qm[iq][i] = qs[iq][i] = 0;
11965 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
11966 n[i] = 0;
11967 }
11968
11969 /* Loop over air parcels... */
11970 for (int ip = 0; ip < atm->np; ip++) {
11971
11972 /* Check time... */
11973 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11974 continue;
11975
11976 /* Check ensemble ID... */
11977 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
11978 ERRMSG("Ensemble ID is out of range!");
11979
11980 /* Get means... */
11981 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
11982 for (int iq = 0; iq < ctl->nq; iq++) {
11983 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
11984 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
11985 }
11986 xm[ctl->qnt_ens][0] += x[0];
11987 xm[ctl->qnt_ens][1] += x[1];
11988 xm[ctl->qnt_ens][2] += x[2];
11989 zm[ctl->qnt_ens] += Z(atm->p[ip]);
11990 n[ctl->qnt_ens]++;
11991 }
11992
11993 /* Create file... */
11994 LOG(1, "Write ensemble data: %s", filename);
11995 if (!(out = fopen(filename, "w")))
11996 ERRMSG("Cannot create file!");
11997
11998 /* Write header... */
11999 fprintf(out,
12000 "# $1 = time [s]\n"
12001 "# $2 = altitude [km]\n"
12002 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12003 for (int iq = 0; iq < ctl->nq; iq++)
12004 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
12005 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12006 for (int iq = 0; iq < ctl->nq; iq++)
12007 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
12008 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12009 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
12010
12011 /* Write data... */
12012 for (int i = 0; i < NENS; i++)
12013 if (n[i] > 0) {
12014 cart2geo(xm[i], &dummy, &lon, &lat);
12015 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
12016 for (int iq = 0; iq < ctl->nq; iq++) {
12017 fprintf(out, " ");
12018 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
12019 }
12020 for (int iq = 0; iq < ctl->nq; iq++) {
12021 fprintf(out, " ");
12022 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
12023 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
12024 }
12025 fprintf(out, " %d\n", n[i]);
12026 }
12027
12028 /* Close file... */
12029 fclose(out);
12030}
12031
12032/*****************************************************************************/
12033
12035 const char *filename,
12036 const ctl_t *ctl,
12037 met_t *met0,
12038 met_t *met1,
12039 const atm_t *atm,
12040 const double t) {
12041
12042 static double kz[EP], kw[EP];
12043
12044 static int nk;
12045
12046 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
12047
12048 int *ixs, *iys, *izs, *np;
12049
12050 /* Set timer... */
12051 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
12052
12053 /* Write info... */
12054 LOG(1, "Write grid data: %s", filename);
12055
12056 /* Init... */
12057 if (t == ctl->t_start) {
12058
12059 /* Read kernel data... */
12060 if (ctl->grid_kernel[0] != '-')
12061 read_kernel(ctl->grid_kernel, kz, kw, &nk);
12062 }
12063
12064 /* Allocate... */
12065 ALLOC(cd, double,
12066 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12067 for (int iq = 0; iq < ctl->nq; iq++) {
12068 ALLOC(mean[iq], double,
12069 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12070 ALLOC(sigma[iq], double,
12071 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12072 }
12073 ALLOC(vmr_impl, double,
12074 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12075 ALLOC(z, double,
12076 ctl->grid_nz);
12077 ALLOC(lon, double,
12078 ctl->grid_nx);
12079 ALLOC(lat, double,
12080 ctl->grid_ny);
12081 ALLOC(area, double,
12082 ctl->grid_ny);
12083 ALLOC(press, double,
12084 ctl->grid_nz);
12085 ALLOC(np, int,
12086 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12087 ALLOC(ixs, int,
12088 atm->np);
12089 ALLOC(iys, int,
12090 atm->np);
12091 ALLOC(izs, int,
12092 atm->np);
12093
12094 /* Set grid box size... */
12095 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
12096 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
12097 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
12098
12099 /* Set vertical coordinates... */
12100#pragma omp parallel for default(shared)
12101 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12102 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
12103 press[iz] = P(z[iz]);
12104 }
12105
12106 /* Set horizontal coordinates... */
12107 for (int ix = 0; ix < ctl->grid_nx; ix++)
12108 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
12109#pragma omp parallel for default(shared)
12110 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12111 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
12112 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
12113 }
12114
12115 /* Set time interval for output... */
12116 const double t0 = t - 0.5 * ctl->dt_mod;
12117 const double t1 = t + 0.5 * ctl->dt_mod;
12118
12119 /* Get grid box indices... */
12120#pragma omp parallel for default(shared)
12121 for (int ip = 0; ip < atm->np; ip++) {
12122 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
12123 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
12124 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
12125 if (atm->time[ip] < t0 || atm->time[ip] > t1
12126 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
12127 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
12128 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
12129 izs[ip] = -1;
12130 }
12131
12132 /* Average data... */
12133 for (int ip = 0; ip < atm->np; ip++)
12134 if (izs[ip] >= 0) {
12135 const int idx =
12136 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
12137 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
12138 np[idx]++;
12139 for (int iq = 0; iq < ctl->nq; iq++) {
12140 mean[iq][idx] += kernel * atm->q[iq][ip];
12141 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
12142 }
12143 }
12144
12145 /* Calculate column density and volume mixing ratio... */
12146#pragma omp parallel for default(shared)
12147 for (int ix = 0; ix < ctl->grid_nx; ix++)
12148 for (int iy = 0; iy < ctl->grid_ny; iy++)
12149 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12150
12151 /* Get grid index... */
12152 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12153
12154 /* Calculate column density... */
12155 cd[idx] = NAN;
12156 if (ctl->qnt_m >= 0)
12157 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
12158
12159 /* Calculate volume mixing ratio (implicit)... */
12160 vmr_impl[idx] = NAN;
12161 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
12162 && met1 != NULL) {
12163 vmr_impl[idx] = 0;
12164 if (mean[ctl->qnt_m][idx] > 0) {
12165
12166 /* Get temperature... */
12167 double temp;
12169 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
12170 lon[ix], lat[iy], &temp, ci, cw, 1);
12171
12172 /* Calculate volume mixing ratio... */
12173 vmr_impl[idx] =
12174 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
12175 }
12176 }
12177
12178 /* Calculate mean... */
12179 if (np[idx] > 0)
12180 for (int iq = 0; iq < ctl->nq; iq++) {
12181 mean[iq][idx] /= np[idx];
12182 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
12183 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
12184 } else
12185 for (int iq = 0; iq < ctl->nq; iq++) {
12186 mean[iq][idx] = NAN;
12187 sigma[iq][idx] = NAN;
12188 }
12189 }
12190
12191 /* Write ASCII data... */
12192 if (ctl->grid_type == 0)
12193 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
12194 t, z, lon, lat, area, dz, np);
12195
12196 /* Write netCDF data... */
12197 else if (ctl->grid_type == 1)
12198 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
12199 t, z, lon, lat, area, dz, np);
12200
12201 /* Error message... */
12202 else
12203 ERRMSG("Grid data format GRID_TYPE unknown!");
12204
12205 /* Free... */
12206 free(cd);
12207 for (int iq = 0; iq < ctl->nq; iq++) {
12208 free(mean[iq]);
12209 free(sigma[iq]);
12210 }
12211 free(vmr_impl);
12212 free(z);
12213 free(lon);
12214 free(lat);
12215 free(area);
12216 free(press);
12217 free(np);
12218 free(ixs);
12219 free(iys);
12220 free(izs);
12221}
12222
12223/*****************************************************************************/
12224
12226 const char *filename,
12227 const ctl_t *ctl,
12228 const double *cd,
12229 double *mean[NQ],
12230 double *sigma[NQ],
12231 const double *vmr_impl,
12232 const double t,
12233 const double *z,
12234 const double *lon,
12235 const double *lat,
12236 const double *area,
12237 const double dz,
12238 const int *np) {
12239
12240 FILE *out;
12241
12242 /* Check if gnuplot output is requested... */
12243 if (ctl->grid_gpfile[0] != '-') {
12244
12245 /* Create gnuplot pipe... */
12246 if (!(out = popen("gnuplot", "w")))
12247 ERRMSG("Cannot create pipe to gnuplot!");
12248
12249 /* Set plot filename... */
12250 fprintf(out, "set out \"%s.png\"\n", filename);
12251
12252 /* Set time string... */
12253 double r;
12254 int year, mon, day, hour, min, sec;
12255 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12256 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12257 year, mon, day, hour, min);
12258
12259 /* Dump gnuplot file to pipe... */
12260 FILE *in;
12261 char line[LEN];
12262 if (!(in = fopen(ctl->grid_gpfile, "r")))
12263 ERRMSG("Cannot open file!");
12264 while (fgets(line, LEN, in))
12265 fprintf(out, "%s", line);
12266 fclose(in);
12267 }
12268
12269 else {
12270
12271 /* Create file... */
12272 if (!(out = fopen(filename, "w")))
12273 ERRMSG("Cannot create file!");
12274 }
12275
12276 /* Write header... */
12277 fprintf(out,
12278 "# $1 = time [s]\n"
12279 "# $2 = altitude [km]\n"
12280 "# $3 = longitude [deg]\n"
12281 "# $4 = latitude [deg]\n"
12282 "# $5 = surface area [km^2]\n"
12283 "# $6 = layer depth [km]\n"
12284 "# $7 = column density (implicit) [kg/m^2]\n"
12285 "# $8 = volume mixing ratio (implicit) [ppv]\n"
12286 "# $9 = number of particles [1]\n");
12287 for (int iq = 0; iq < ctl->nq; iq++)
12288 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
12289 ctl->qnt_unit[iq]);
12290 if (ctl->grid_stddev)
12291 for (int iq = 0; iq < ctl->nq; iq++)
12292 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
12293 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12294 fprintf(out, "\n");
12295
12296 /* Write data... */
12297 for (int ix = 0; ix < ctl->grid_nx; ix++) {
12298 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
12299 fprintf(out, "\n");
12300 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12301 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
12302 fprintf(out, "\n");
12303 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12304 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12305 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
12306 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
12307 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
12308 for (int iq = 0; iq < ctl->nq; iq++) {
12309 fprintf(out, " ");
12310 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
12311 }
12312 if (ctl->grid_stddev)
12313 for (int iq = 0; iq < ctl->nq; iq++) {
12314 fprintf(out, " ");
12315 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
12316 }
12317 fprintf(out, "\n");
12318 }
12319 }
12320 }
12321 }
12322
12323 /* Close file... */
12324 fclose(out);
12325}
12326
12327/*****************************************************************************/
12328
12330 const char *filename,
12331 const ctl_t *ctl,
12332 const double *cd,
12333 double *mean[NQ],
12334 double *sigma[NQ],
12335 const double *vmr_impl,
12336 const double t,
12337 const double *z,
12338 const double *lon,
12339 const double *lat,
12340 const double *area,
12341 const double dz,
12342 const int *np) {
12343
12344 char longname[2 * LEN], varname[2 * LEN];
12345
12346 double *help;
12347
12348 int *help2, ncid, dimid[10], varid;
12349
12350 size_t start[2], count[2];
12351
12352 /* Allocate... */
12353 ALLOC(help, double,
12354 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12355 ALLOC(help2, int,
12356 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12357
12358 /* Create file... */
12359 NC(nc_create(filename, NC_NETCDF4, &ncid));
12360
12361 /* Define dimensions... */
12362 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
12363 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
12364 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
12365 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
12366 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
12367
12368 /* Define variables and their attributes... */
12369 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
12370 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12371 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
12372 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
12373 0);
12374 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
12375 0);
12376 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
12377 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
12378
12379 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
12380 ctl->grid_nc_level, 0);
12381 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
12382 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
12383 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
12384 for (int iq = 0; iq < ctl->nq; iq++) {
12385 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12386 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
12387 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12388 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12389 if (ctl->grid_stddev) {
12390 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12391 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
12392 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12393 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12394 }
12395 }
12396 /* End definitions... */
12397 NC(nc_enddef(ncid));
12398
12399 /* Write data... */
12400 NC_PUT_DOUBLE("time", &t, 0);
12401 NC_PUT_DOUBLE("lon", lon, 0);
12402 NC_PUT_DOUBLE("lat", lat, 0);
12403 NC_PUT_DOUBLE("z", z, 0);
12404 NC_PUT_DOUBLE("area", area, 0);
12405 NC_PUT_DOUBLE("dz", &dz, 0);
12406
12407 for (int ix = 0; ix < ctl->grid_nx; ix++)
12408 for (int iy = 0; iy < ctl->grid_ny; iy++)
12409 for (int iz = 0; iz < ctl->grid_nz; iz++)
12410 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12411 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12412 NC_PUT_DOUBLE("cd", help, 0);
12413
12414 for (int ix = 0; ix < ctl->grid_nx; ix++)
12415 for (int iy = 0; iy < ctl->grid_ny; iy++)
12416 for (int iz = 0; iz < ctl->grid_nz; iz++)
12417 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12418 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12419 NC_PUT_DOUBLE("vmr_impl", help, 0);
12420
12421 for (int ix = 0; ix < ctl->grid_nx; ix++)
12422 for (int iy = 0; iy < ctl->grid_ny; iy++)
12423 for (int iz = 0; iz < ctl->grid_nz; iz++)
12424 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12425 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12426 NC_PUT_INT("np", help2, 0);
12427
12428 for (int iq = 0; iq < ctl->nq; iq++) {
12429 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12430 for (int ix = 0; ix < ctl->grid_nx; ix++)
12431 for (int iy = 0; iy < ctl->grid_ny; iy++)
12432 for (int iz = 0; iz < ctl->grid_nz; iz++)
12433 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12434 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12435 NC_PUT_DOUBLE(varname, help, 0);
12436 }
12437
12438 if (ctl->grid_stddev)
12439 for (int iq = 0; iq < ctl->nq; iq++) {
12440 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12441 for (int ix = 0; ix < ctl->grid_nx; ix++)
12442 for (int iy = 0; iy < ctl->grid_ny; iy++)
12443 for (int iz = 0; iz < ctl->grid_nz; iz++)
12444 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12445 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12446 NC_PUT_DOUBLE(varname, help, 0);
12447 }
12448
12449 /* Close file... */
12450 NC(nc_close(ncid));
12451
12452 /* Free... */
12453 free(help);
12454 free(help2);
12455}
12456
12457/*****************************************************************************/
12458
12460 const char *filename,
12461 const ctl_t *ctl,
12462 met_t *met) {
12463
12464 /* Create file... */
12465 FILE *out;
12466 if (!(out = fopen(filename, "w")))
12467 ERRMSG("Cannot create file!");
12468
12469 /* Write type of binary data... */
12470 FWRITE(&ctl->met_type, int,
12471 1,
12472 out);
12473
12474 /* Write version of binary data... */
12475 int version = 103;
12476 FWRITE(&version, int,
12477 1,
12478 out);
12479
12480 /* Write grid data... */
12481 FWRITE(&met->time, double,
12482 1,
12483 out);
12484 FWRITE(&met->nx, int,
12485 1,
12486 out);
12487 FWRITE(&met->ny, int,
12488 1,
12489 out);
12490 FWRITE(&met->np, int,
12491 1,
12492 out);
12493 FWRITE(met->lon, double,
12494 (size_t) met->nx,
12495 out);
12496 FWRITE(met->lat, double,
12497 (size_t) met->ny,
12498 out);
12499 FWRITE(met->p, double,
12500 (size_t) met->np,
12501 out);
12502
12503 /* Write surface data... */
12504 write_met_bin_2d(out, met, met->ps, "PS");
12505 write_met_bin_2d(out, met, met->ts, "TS");
12506 write_met_bin_2d(out, met, met->zs, "ZS");
12507 write_met_bin_2d(out, met, met->us, "US");
12508 write_met_bin_2d(out, met, met->vs, "VS");
12509 write_met_bin_2d(out, met, met->ess, "ESS");
12510 write_met_bin_2d(out, met, met->nss, "NSS");
12511 write_met_bin_2d(out, met, met->shf, "SHF");
12512 write_met_bin_2d(out, met, met->lsm, "LSM");
12513 write_met_bin_2d(out, met, met->sst, "SST");
12514 write_met_bin_2d(out, met, met->pbl, "PBL");
12515 write_met_bin_2d(out, met, met->pt, "PT");
12516 write_met_bin_2d(out, met, met->tt, "TT");
12517 write_met_bin_2d(out, met, met->zt, "ZT");
12518 write_met_bin_2d(out, met, met->h2ot, "H2OT");
12519 write_met_bin_2d(out, met, met->pct, "PCT");
12520 write_met_bin_2d(out, met, met->pcb, "PCB");
12521 write_met_bin_2d(out, met, met->cl, "CL");
12522 write_met_bin_2d(out, met, met->plcl, "PLCL");
12523 write_met_bin_2d(out, met, met->plfc, "PLFC");
12524 write_met_bin_2d(out, met, met->pel, "PEL");
12525 write_met_bin_2d(out, met, met->cape, "CAPE");
12526 write_met_bin_2d(out, met, met->cin, "CIN");
12527 write_met_bin_2d(out, met, met->o3c, "O3C");
12528
12529 /* Write level data... */
12530 write_met_bin_3d(out, ctl, met, met->z, "Z",
12531 ctl->met_comp_prec[0], ctl->met_comp_tol[0]);
12532 write_met_bin_3d(out, ctl, met, met->t, "T",
12533 ctl->met_comp_prec[1], ctl->met_comp_tol[1]);
12534 write_met_bin_3d(out, ctl, met, met->u, "U",
12535 ctl->met_comp_prec[2], ctl->met_comp_tol[2]);
12536 write_met_bin_3d(out, ctl, met, met->v, "V",
12537 ctl->met_comp_prec[3], ctl->met_comp_tol[3]);
12538 write_met_bin_3d(out, ctl, met, met->w, "W",
12539 ctl->met_comp_prec[4], ctl->met_comp_tol[4]);
12540 write_met_bin_3d(out, ctl, met, met->pv, "PV",
12541 ctl->met_comp_prec[5], ctl->met_comp_tol[5]);
12542 write_met_bin_3d(out, ctl, met, met->h2o, "H2O",
12543 ctl->met_comp_prec[6], ctl->met_comp_tol[6]);
12544 write_met_bin_3d(out, ctl, met, met->o3, "O3",
12545 ctl->met_comp_prec[7], ctl->met_comp_tol[7]);
12546 write_met_bin_3d(out, ctl, met, met->lwc, "LWC",
12547 ctl->met_comp_prec[8], ctl->met_comp_tol[8]);
12548 write_met_bin_3d(out, ctl, met, met->rwc, "RWC",
12549 ctl->met_comp_prec[9], ctl->met_comp_tol[9]);
12550 write_met_bin_3d(out, ctl, met, met->iwc, "IWC",
12551 ctl->met_comp_prec[10], ctl->met_comp_tol[10]);
12552 write_met_bin_3d(out, ctl, met, met->swc, "SWC",
12553 ctl->met_comp_prec[11], ctl->met_comp_tol[11]);
12554 write_met_bin_3d(out, ctl, met, met->cc, "CC",
12555 ctl->met_comp_prec[12], ctl->met_comp_tol[12]);
12556 if (METVAR != 13)
12557 ERRMSG("Number of meteo variables doesn't match!");
12558
12559 /* Write final flag... */
12560 int final = 999;
12561 FWRITE(&final, int,
12562 1,
12563 out);
12564
12565 /* Close file... */
12566 fclose(out);
12567}
12568
12569/*****************************************************************************/
12570
12572 FILE *out,
12573 met_t *met,
12574 float var[EX][EY],
12575 const char *varname) {
12576
12577 float *help;
12578
12579 /* Allocate... */
12580 ALLOC(help, float,
12581 EX * EY);
12582
12583 /* Copy data... */
12584 for (int ix = 0; ix < met->nx; ix++)
12585 for (int iy = 0; iy < met->ny; iy++)
12586 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
12587
12588 /* Write uncompressed data... */
12589 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
12590 FWRITE(help, float,
12591 (size_t) (met->nx * met->ny),
12592 out);
12593
12594 /* Free... */
12595 free(help);
12596}
12597
12598/*****************************************************************************/
12599
12601 FILE *out,
12602 const ctl_t *ctl,
12603 met_t *met,
12604 float var[EX][EY][EP],
12605 const char *varname,
12606 const int precision,
12607 const double tolerance) {
12608
12609 float *help;
12610
12611 /* Allocate... */
12612 ALLOC(help, float,
12613 EX * EY * EP);
12614
12615 /* Copy data... */
12616#pragma omp parallel for default(shared) collapse(2)
12617 for (int ix = 0; ix < met->nx; ix++)
12618 for (int iy = 0; iy < met->ny; iy++)
12619 for (int ip = 0; ip < met->np; ip++)
12620 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
12621
12622 /* Write uncompressed data... */
12623 if (ctl->met_type == 1) {
12624 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
12625 FWRITE(help, float,
12626 (size_t) (met->nx * met->ny * met->np),
12627 out);
12628 }
12629
12630 /* Write packed data... */
12631 else if (ctl->met_type == 2)
12632 compress_pck(varname, help, (size_t) (met->ny * met->nx),
12633 (size_t) met->np, 0, out);
12634
12635 /* Write ZFP data... */
12636#ifdef ZFP
12637 else if (ctl->met_type == 3) {
12638 FWRITE(&precision, int,
12639 1,
12640 out);
12641 FWRITE(&tolerance, double,
12642 1,
12643 out);
12644 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
12645 tolerance, 0, out);
12646 }
12647#endif
12648
12649 /* Write zstd data... */
12650#ifdef ZSTD
12651 else if (ctl->met_type == 4)
12652 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
12653 ctl->met_zstd_level, out);
12654#endif
12655
12656 /* Write cmultiscale data... */
12657#ifdef CMS
12658 else if (ctl->met_type == 5) {
12659 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
12660 (size_t) met->np, 0, out);
12661 }
12662#endif
12663
12664 /* Write SZ3 data... */
12665#ifdef SZ3
12666 else if (ctl->met_type == 7) {
12667 FWRITE(&precision, int,
12668 1,
12669 out);
12670 FWRITE(&tolerance, double,
12671 1,
12672 out);
12673 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
12674 tolerance, 0, out);
12675 }
12676#endif
12677
12678 /* Unknown method... */
12679 else {
12680 ERRMSG("MET_TYPE not supported!");
12681 LOG(3, "%d %g", precision, tolerance);
12682 }
12683
12684 /* Free... */
12685 free(help);
12686}
12687
12688/*****************************************************************************/
12689
12691 const char *filename,
12692 const ctl_t *ctl,
12693 met_t *met) {
12694
12695 /* Create file... */
12696 int ncid, varid;
12697 size_t start[4], count[4];
12698 nc_create(filename, NC_NETCDF4, &ncid);
12699
12700 /* Define dimensions... */
12701 int tid, lonid, latid, levid;
12702 NC(nc_def_dim(ncid, "time", 1, &tid));
12703 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
12704 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
12705 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
12706
12707 /* Define grid... */
12708 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
12709 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12710 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
12711 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
12712 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
12713
12714 /* Define surface variables... */
12715 int dimid2[2] = { latid, lonid };
12716 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
12717 ctl->met_nc_level, 0);
12718 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
12719 ctl->met_nc_level, 0);
12720 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
12721 ctl->met_nc_level, 0);
12722 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
12723 "m s**-1", ctl->met_nc_level, 0);
12724 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
12725 "m s**-1", ctl->met_nc_level, 0);
12726 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
12727 "Instantaneous eastward turbulent surface stress", "N m**-2",
12728 ctl->met_nc_level, 0);
12729 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
12730 "Instantaneous northward turbulent surface stress", "N m**-2",
12731 ctl->met_nc_level, 0);
12732 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
12733 "Instantaneous surface sensible heat flux", "W m**-1",
12734 ctl->met_nc_level, 0);
12735 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
12736 ctl->met_nc_level, 0);
12737 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
12738 ctl->met_nc_level, 0);
12739 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
12740 ctl->met_nc_level, 0);
12741 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
12742 ctl->met_nc_level, 0);
12743 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
12744 ctl->met_nc_level, 0);
12745 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
12746 ctl->met_nc_level, 0);
12747 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
12748 ctl->met_nc_level, 0);
12749 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
12750 ctl->met_nc_level, 0);
12751 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
12752 ctl->met_nc_level, 0);
12753 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water",
12754 "kg m**2", ctl->met_nc_level, 0);
12755 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
12756 "Pressure at lifted condensation level (LCL)", "Pa",
12757 ctl->met_nc_level, 0);
12758 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
12759 "Pressure at level of free convection (LFC)", "Pa",
12760 ctl->met_nc_level, 0);
12761 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2,
12762 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
12763 0);
12764 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
12765 "Convective available potential energy", "J kg**-1",
12766 ctl->met_nc_level, 0);
12767 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition",
12768 "J kg**-1", ctl->met_nc_level, 0);
12769 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
12770 ctl->met_nc_level, 0);
12771
12772 /* Define level data... */
12773 int dimid3[3] = { levid, latid, lonid };
12774 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
12775 ctl->met_nc_level, ctl->met_nc_quant);
12776 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
12777 ctl->met_nc_level, ctl->met_nc_quant);
12778 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
12779 ctl->met_nc_level, ctl->met_nc_quant);
12780 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
12781 ctl->met_nc_level, ctl->met_nc_quant);
12782 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
12783 ctl->met_nc_level, ctl->met_nc_quant);
12784 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
12785 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12786 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
12787 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12788 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
12789 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12790 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
12791 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12792 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
12793 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12794 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
12795 ctl->met_nc_level, ctl->met_nc_quant);
12796
12797 /* End definitions... */
12798 NC(nc_enddef(ncid));
12799
12800 /* Write grid data... */
12801 NC_PUT_DOUBLE("time", &met->time, 0);
12802 NC_PUT_DOUBLE("lon", met->lon, 0);
12803 NC_PUT_DOUBLE("lat", met->lat, 0);
12804 double phelp[EP];
12805 for (int ip = 0; ip < met->np; ip++)
12806 phelp[ip] = 100. * met->p[ip];
12807 NC_PUT_DOUBLE("lev", phelp, 0);
12808
12809 /* Write surface data... */
12810 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
12811 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
12812 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
12813 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
12814 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
12815 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
12816 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
12817 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
12818 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
12819 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
12820 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
12821 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
12822 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
12823 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
12824 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
12825 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
12826 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
12827 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
12828 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
12829 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
12830 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
12831 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
12832 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
12833 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
12834
12835 /* Write level data... */
12836 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
12837 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
12838 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
12839 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
12840 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
12841 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
12842 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
12843 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
12844 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
12845 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
12846 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
12847
12848 /* Close file... */
12849 NC(nc_close(ncid));
12850}
12851
12852/*****************************************************************************/
12853
12855 const int ncid,
12856 const char *varname,
12857 met_t *met,
12858 float var[EX][EY],
12859 const float scl) {
12860
12861 int varid;
12862 size_t start[4], count[4];
12863
12864 /* Allocate... */
12865 float *help;
12866 ALLOC(help, float,
12867 EX * EY);
12868
12869 /* Copy data... */
12870 for (int ix = 0; ix < met->nx; ix++)
12871 for (int iy = 0; iy < met->ny; iy++)
12872 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
12873
12874 /* Write data... */
12875 NC_PUT_FLOAT(varname, help, 0);
12876
12877 /* Free... */
12878 free(help);
12879}
12880
12881/*****************************************************************************/
12882
12884 const int ncid,
12885 const char *varname,
12886 met_t *met,
12887 float var[EX][EY][EP],
12888 const float scl) {
12889
12890 int varid;
12891 size_t start[4], count[4];
12892
12893 /* Allocate... */
12894 float *help;
12895 ALLOC(help, float,
12896 EX * EY * EP);
12897
12898 /* Copy data... */
12899 for (int ix = 0; ix < met->nx; ix++)
12900 for (int iy = 0; iy < met->ny; iy++)
12901 for (int ip = 0; ip < met->np; ip++)
12902 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
12903
12904 /* Write data... */
12905 NC_PUT_FLOAT(varname, help, 0);
12906
12907 /* Free... */
12908 free(help);
12909}
12910
12911/*****************************************************************************/
12912
12914 const char *filename,
12915 const ctl_t *ctl,
12916 met_t *met0,
12917 met_t *met1,
12918 const atm_t *atm,
12919 const double t) {
12920
12921 static FILE *out;
12922
12923 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
12924 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
12925
12926 static int nobs, *obscount, ip, okay;
12927
12928 /* Set timer... */
12929 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
12930
12931 /* Init... */
12932 if (t == ctl->t_start) {
12933
12934 /* Check quantity index for mass... */
12935 if (ctl->qnt_m < 0)
12936 ERRMSG("Need quantity mass!");
12937
12938 /* Check molar mass... */
12939 if (ctl->molmass <= 0)
12940 ERRMSG("Specify molar mass!");
12941
12942 /* Allocate... */
12943 ALLOC(lon, double,
12944 ctl->prof_nx);
12945 ALLOC(lat, double,
12946 ctl->prof_ny);
12947 ALLOC(area, double,
12948 ctl->prof_ny);
12949 ALLOC(z, double,
12950 ctl->prof_nz);
12951 ALLOC(press, double,
12952 ctl->prof_nz);
12953 ALLOC(rt, double,
12954 NOBS);
12955 ALLOC(rz, double,
12956 NOBS);
12957 ALLOC(rlon, double,
12958 NOBS);
12959 ALLOC(rlat, double,
12960 NOBS);
12961 ALLOC(robs, double,
12962 NOBS);
12963
12964 /* Read observation data... */
12965 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12966
12967 /* Create new output file... */
12968 LOG(1, "Write profile data: %s", filename);
12969 if (!(out = fopen(filename, "w")))
12970 ERRMSG("Cannot create file!");
12971
12972 /* Write header... */
12973 fprintf(out,
12974 "# $1 = time [s]\n"
12975 "# $2 = altitude [km]\n"
12976 "# $3 = longitude [deg]\n"
12977 "# $4 = latitude [deg]\n"
12978 "# $5 = pressure [hPa]\n"
12979 "# $6 = temperature [K]\n"
12980 "# $7 = volume mixing ratio [ppv]\n"
12981 "# $8 = H2O volume mixing ratio [ppv]\n"
12982 "# $9 = O3 volume mixing ratio [ppv]\n"
12983 "# $10 = observed BT index [K]\n"
12984 "# $11 = number of observations\n");
12985
12986 /* Set grid box size... */
12987 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
12988 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
12989 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
12990
12991 /* Set vertical coordinates... */
12992 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12993 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
12994 press[iz] = P(z[iz]);
12995 }
12996
12997 /* Set horizontal coordinates... */
12998 for (int ix = 0; ix < ctl->prof_nx; ix++)
12999 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
13000 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13001 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
13002 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
13003 }
13004 }
13005
13006 /* Set time interval... */
13007 const double t0 = t - 0.5 * ctl->dt_mod;
13008 const double t1 = t + 0.5 * ctl->dt_mod;
13009
13010 /* Allocate... */
13011 ALLOC(mass, double,
13012 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
13013 ALLOC(obsmean, double,
13014 ctl->prof_nx * ctl->prof_ny);
13015 ALLOC(obscount, int,
13016 ctl->prof_nx * ctl->prof_ny);
13017
13018 /* Loop over observations... */
13019 for (int i = 0; i < nobs; i++) {
13020
13021 /* Check time... */
13022 if (rt[i] < t0)
13023 continue;
13024 else if (rt[i] >= t1)
13025 break;
13026
13027 /* Check observation data... */
13028 if (!isfinite(robs[i]))
13029 continue;
13030
13031 /* Calculate indices... */
13032 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
13033 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
13034
13035 /* Check indices... */
13036 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
13037 continue;
13038
13039 /* Get mean observation index... */
13040 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
13041 obsmean[idx] += robs[i];
13042 obscount[idx]++;
13043 }
13044
13045 /* Analyze model data... */
13046 for (ip = 0; ip < atm->np; ip++) {
13047
13048 /* Check time... */
13049 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13050 continue;
13051
13052 /* Get indices... */
13053 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
13054 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
13055 const int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
13056
13057 /* Check indices... */
13058 if (ix < 0 || ix >= ctl->prof_nx ||
13059 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
13060 continue;
13061
13062 /* Get total mass in grid cell... */
13063 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13064 mass[idx] += atm->q[ctl->qnt_m][ip];
13065 }
13066
13067 /* Extract profiles... */
13068 for (int ix = 0; ix < ctl->prof_nx; ix++)
13069 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13070 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
13071 if (obscount[idx2] > 0) {
13072
13073 /* Check profile... */
13074 okay = 0;
13075 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13076 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13077 if (mass[idx3] > 0) {
13078 okay = 1;
13079 break;
13080 }
13081 }
13082 if (!okay)
13083 continue;
13084
13085 /* Write output... */
13086 fprintf(out, "\n");
13087
13088 /* Loop over altitudes... */
13089 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13090
13091 /* Get temperature, water vapor, and ozone... */
13093 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
13094 lon[ix], lat[iy], &temp, ci, cw, 1);
13095 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
13096 lon[ix], lat[iy], &h2o, ci, cw, 0);
13097 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
13098 lon[ix], lat[iy], &o3, ci, cw, 0);
13099
13100 /* Calculate volume mixing ratio... */
13101 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13102 vmr = MA / ctl->molmass * mass[idx3]
13103 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
13104
13105 /* Write output... */
13106 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
13107 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
13108 obsmean[idx2] / obscount[idx2], obscount[idx2]);
13109 }
13110 }
13111 }
13112
13113 /* Free... */
13114 free(mass);
13115 free(obsmean);
13116 free(obscount);
13117
13118 /* Finalize... */
13119 if (t == ctl->t_stop) {
13120
13121 /* Close output file... */
13122 fclose(out);
13123
13124 /* Free... */
13125 free(lon);
13126 free(lat);
13127 free(area);
13128 free(z);
13129 free(press);
13130 free(rt);
13131 free(rz);
13132 free(rlon);
13133 free(rlat);
13134 free(robs);
13135 }
13136}
13137
13138/*****************************************************************************/
13139
13141 const char *filename,
13142 const ctl_t *ctl,
13143 met_t *met0,
13144 met_t *met1,
13145 const atm_t *atm,
13146 const double t) {
13147
13148 static FILE *out;
13149
13150 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
13151 kw[EP];
13152
13153 static int nobs, nk;
13154
13155 /* Set timer... */
13156 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
13157
13158 /* Init... */
13159 if (t == ctl->t_start) {
13160
13161 /* Allocate... */
13162 ALLOC(rt, double,
13163 NOBS);
13164 ALLOC(rz, double,
13165 NOBS);
13166 ALLOC(rlon, double,
13167 NOBS);
13168 ALLOC(rlat, double,
13169 NOBS);
13170 ALLOC(robs, double,
13171 NOBS);
13172
13173 /* Read observation data... */
13174 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13175
13176 /* Read kernel data... */
13177 if (ctl->sample_kernel[0] != '-')
13178 read_kernel(ctl->sample_kernel, kz, kw, &nk);
13179
13180 /* Create output file... */
13181 LOG(1, "Write sample data: %s", filename);
13182 if (!(out = fopen(filename, "w")))
13183 ERRMSG("Cannot create file!");
13184
13185 /* Write header... */
13186 fprintf(out,
13187 "# $1 = time [s]\n"
13188 "# $2 = altitude [km]\n"
13189 "# $3 = longitude [deg]\n"
13190 "# $4 = latitude [deg]\n"
13191 "# $5 = surface area [km^2]\n"
13192 "# $6 = layer depth [km]\n"
13193 "# $7 = number of particles [1]\n"
13194 "# $8 = column density [kg/m^2]\n"
13195 "# $9 = volume mixing ratio [ppv]\n"
13196 "# $10 = observed BT index [K]\n\n");
13197
13198 /* Set latitude range, squared radius, and area... */
13199 dlat = DY2DEG(ctl->sample_dx);
13200 rmax2 = SQR(ctl->sample_dx);
13201 area = M_PI * rmax2;
13202 }
13203
13204 /* Set time interval for output... */
13205 const double t0 = t - 0.5 * ctl->dt_mod;
13206 const double t1 = t + 0.5 * ctl->dt_mod;
13207
13208 /* Loop over observations... */
13209 for (int i = 0; i < nobs; i++) {
13210
13211 /* Check time... */
13212 if (rt[i] < t0)
13213 continue;
13214 else if (rt[i] >= t1)
13215 break;
13216
13217 /* Calculate Cartesian coordinates... */
13218 double x0[3];
13219 geo2cart(0, rlon[i], rlat[i], x0);
13220
13221 /* Set pressure range... */
13222 const double rp = P(rz[i]);
13223 const double ptop = P(rz[i] + ctl->sample_dz);
13224 const double pbot = P(rz[i] - ctl->sample_dz);
13225
13226 /* Init... */
13227 double mass = 0;
13228 int np = 0;
13229
13230 /* Loop over air parcels... */
13231 //#pragma omp parallel for default(shared) reduction(+:mass,np)
13232 for (int ip = 0; ip < atm->np; ip++) {
13233
13234 /* Check time... */
13235 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13236 continue;
13237
13238 /* Check latitude... */
13239 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
13240 continue;
13241
13242 /* Check horizontal distance... */
13243 double x1[3];
13244 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13245 if (DIST2(x0, x1) > rmax2)
13246 continue;
13247
13248 /* Check pressure... */
13249 if (ctl->sample_dz > 0)
13250 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
13251 continue;
13252
13253 /* Add mass... */
13254 if (ctl->qnt_m >= 0)
13255 mass +=
13256 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13257 np++;
13258 }
13259
13260 /* Calculate column density... */
13261 const double cd = mass / (1e6 * area);
13262
13263 /* Calculate volume mixing ratio... */
13264 double vmr = 0;
13265 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
13266 if (mass > 0) {
13267
13268 /* Get temperature... */
13269 double temp;
13271 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
13272 rlon[i], rlat[i], &temp, ci, cw, 1);
13273
13274 /* Calculate volume mixing ratio... */
13275 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
13276 }
13277 } else
13278 vmr = NAN;
13279
13280 /* Write output... */
13281 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
13282 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
13283 }
13284
13285 /* Finalize...... */
13286 if (t == ctl->t_stop) {
13287
13288 /* Close output file... */
13289 fclose(out);
13290
13291 /* Free... */
13292 free(rt);
13293 free(rz);
13294 free(rlon);
13295 free(rlat);
13296 free(robs);
13297 }
13298}
13299
13300/*****************************************************************************/
13301
13303 const char *filename,
13304 const ctl_t *ctl,
13305 atm_t *atm,
13306 const double t) {
13307
13308 static FILE *out;
13309
13310 static double rmax2, x0[3], x1[3];
13311
13312 /* Set timer... */
13313 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
13314
13315 /* Init... */
13316 if (t == ctl->t_start) {
13317
13318 /* Write info... */
13319 LOG(1, "Write station data: %s", filename);
13320
13321 /* Create new file... */
13322 if (!(out = fopen(filename, "w")))
13323 ERRMSG("Cannot create file!");
13324
13325 /* Write header... */
13326 fprintf(out,
13327 "# $1 = time [s]\n"
13328 "# $2 = altitude [km]\n"
13329 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13330 for (int iq = 0; iq < ctl->nq; iq++)
13331 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
13332 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13333 fprintf(out, "\n");
13334
13335 /* Set geolocation and search radius... */
13336 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
13337 rmax2 = SQR(ctl->stat_r);
13338 }
13339
13340 /* Set time interval for output... */
13341 const double t0 = t - 0.5 * ctl->dt_mod;
13342 const double t1 = t + 0.5 * ctl->dt_mod;
13343
13344 /* Loop over air parcels... */
13345 for (int ip = 0; ip < atm->np; ip++) {
13346
13347 /* Check time... */
13348 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13349 continue;
13350
13351 /* Check time range for station output... */
13352 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
13353 continue;
13354
13355 /* Check station flag... */
13356 if (ctl->qnt_stat >= 0)
13357 if ((int) atm->q[ctl->qnt_stat][ip])
13358 continue;
13359
13360 /* Get Cartesian coordinates... */
13361 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13362
13363 /* Check horizontal distance... */
13364 if (DIST2(x0, x1) > rmax2)
13365 continue;
13366
13367 /* Set station flag... */
13368 if (ctl->qnt_stat >= 0)
13369 atm->q[ctl->qnt_stat][ip] = 1;
13370
13371 /* Write data... */
13372 fprintf(out, "%.2f %g %g %g",
13373 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
13374 for (int iq = 0; iq < ctl->nq; iq++) {
13375 fprintf(out, " ");
13376 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
13377 }
13378 fprintf(out, "\n");
13379 }
13380
13381 /* Close file... */
13382 if (t == ctl->t_stop)
13383 fclose(out);
13384}
13385
13386/*****************************************************************************/
13387
13389 const char *filename,
13390 const ctl_t *ctl,
13391 const atm_t *atm,
13392 const double t) {
13393
13394 FILE *out;
13395
13396 /* Set timer... */
13397 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
13398
13399 /* Write info... */
13400 LOG(1, "Write VTK data: %s", filename);
13401
13402 /* Set time interval for output... */
13403 const double t0 = t - 0.5 * ctl->dt_mod;
13404 const double t1 = t + 0.5 * ctl->dt_mod;
13405
13406 /* Create file... */
13407 if (!(out = fopen(filename, "w")))
13408 ERRMSG("Cannot create file!");
13409
13410 /* Count data points... */
13411 int np = 0;
13412 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13413 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13414 continue;
13415 np++;
13416 }
13417
13418 /* Write header... */
13419 fprintf(out,
13420 "# vtk DataFile Version 3.0\n"
13421 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
13422
13423 /* Write point coordinates... */
13424 fprintf(out, "POINTS %d float\n", np);
13425 if (ctl->vtk_sphere) {
13426 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13427 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13428 continue;
13429 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
13430 + ctl->vtk_offset) / RE;
13431 const double coslat = cos(DEG2RAD(atm->lat[ip]));
13432 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
13433 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
13434 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
13435 fprintf(out, "%g %g %g\n", x, y, z);
13436 }
13437 } else
13438 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13439 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13440 continue;
13441 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
13442 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
13443 }
13444
13445 /* Write point data... */
13446 fprintf(out, "POINT_DATA %d\n", np);
13447 for (int iq = 0; iq < ctl->nq; iq++) {
13448 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
13449 ctl->qnt_name[iq]);
13450 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13451 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13452 continue;
13453 fprintf(out, "%g\n", atm->q[iq][ip]);
13454 }
13455 }
13456
13457 /* Close file... */
13458 fclose(out);
13459}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:8070
void mptrac_alloc(ctl_t **ctl, cache_t **cache, clim_t **clim, met_t **met0, met_t **met1, atm_t **atm, dd_t **dd)
Allocates and initializes memory resources for MPTRAC.
Definition: mptrac.c:5108
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:6726
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:8030
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:11455
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, dd_t *dd, float dest[EX][EY], const float scl, const int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:8700
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:12854
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:10453
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:12600
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:10798
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:2925
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:4825
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:4142
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:7158
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:7869
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:3528
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:10971
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:2324
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, dd_t *dd, float dest[EX][EY][EP], const float scl)
Reads a 3-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:8962
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:7125
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:10061
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:7926
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:10626
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:10842
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:3373
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:2886
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:2024
void read_met_nc_levels(const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads and processes meteorological level data from NetCDF files with domain decomposition.
Definition: mptrac.c:8503
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:9696
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:7277
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:10198
void mptrac_run_timestep(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t **met0, met_t **met1, atm_t *atm, double t, dd_t *dd)
Executes a single timestep of the MPTRAC model simulation.
Definition: mptrac.c:6466
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:4872
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:11937
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:4249
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:4320
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:7249
void read_met_ml2pl(const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname)
Interpolates meteorological data to specified pressure levels.
Definition: mptrac.c:9654
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:10870
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:7619
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:2822
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:3966
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:2612
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:12225
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:6614
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:11113
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:5316
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:2382
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:1876
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:4973
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:6921
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:11004
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:3211
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:7331
void read_met_nc_grid_dd_naive(dd_t *dd, const ctl_t *ctl, met_t *met, const int ncid)
Read meteorological grid data from a NetCDF file and set up subdomain decomposition with halos.
Definition: mptrac.c:9821
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:4693
int read_met_nc(const char *filename, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads meteorological data from a NetCDF file and processes it.
Definition: mptrac.c:9781
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:11144
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:11270
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:2266
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:3415
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:7430
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:3115
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:10899
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:3088
void mptrac_get_met(ctl_t *ctl, clim_t *clim, const double t, met_t **met0, met_t **met1, dd_t *dd)
Retrieves meteorological data for the specified time.
Definition: mptrac.c:5194
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:4787
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:11051
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:2444
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:7648
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:2852
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:11212
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:12913
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:5406
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:11247
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:12690
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:4557
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:5335
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:6670
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:6830
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:10424
void read_met_nc_surface(const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads and processes surface meteorological data from NetCDF files with domain decomposition.
Definition: mptrac.c:8365
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:4588
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:1933
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:13302
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:11072
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:1846
void intpol_met_4d_zeta(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:2094
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:2411
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:4506
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:2905
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:12571
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:10318
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:7009
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:2000
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:3567
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:4722
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:2535
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:7471
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:11402
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:3769
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:7065
int mptrac_read_met(const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met, dd_t *dd)
Reads meteorological data from a file, supporting multiple formats and MPI broadcasting.
Definition: mptrac.c:6357
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:13388
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:4903
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:5466
void mptrac_free(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, dd_t *dd)
Frees memory resources allocated for MPTRAC.
Definition: mptrac.c:5161
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:10259
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:3884
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:12329
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:6945
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:3644
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:12883
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:4036
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:4422
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:1915
void read_met_nc_grid(const char *filename, const int ncid, const ctl_t *ctl, met_t *met, dd_t *dd)
Reads meteorological grid data from NetCDF files with domain decomposition.
Definition: mptrac.c:8198
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:2568
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:6967
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:2067
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:13140
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:12034
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:3821
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:12459
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:11352
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:7754
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:6786
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:2594
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:11662
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:11613
MPTRAC library declarations.
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1386
int dd_init(ctl_t *ctl, dd_t *dd, atm_t *atm)
Initializes domain decomposition for parallel processing.
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:298
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:264
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1858
#define DD_NPOLE
Constant indicating the North pole [-].
Definition: mptrac.h:378
void read_met_grib_surface(codes_handle **handles, const int num_messages, const ctl_t *ctl, met_t *met)
Reads surface meteorological data from a grib file and stores it in the meteorological data structure...
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:458
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1413
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:239
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:199
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:234
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:244
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:303
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:323
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:818
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1518
#define H0
Scale height [km].
Definition: mptrac.h:219
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1366
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1153
void dd_sort(const ctl_t *ctl, met_t *met0, atm_t *atm, dd_t *dd, int *nparticles, int *rank)
Sort particles according to box index and target rank for neighbours.
#define DD_SPOLE
Constant indicating the South pole [-].
Definition: mptrac.h:383
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:991
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1167
#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:755
#define DOTP(a, b)
Calculate the dot product of two vectors.
Definition: mptrac.h:699
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:259
#define KARMAN
Karman's constant.
Definition: mptrac.h:229
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:833
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:1138
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2043
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1327
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:293
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:1683
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:864
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:328
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:333
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:439
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:1880
#define codes_handle
Placeholder when ECCODES is not available.
Definition: mptrac.h:190
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1443
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:224
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:214
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:348
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:313
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:798
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:614
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:550
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:288
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:209
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1491
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1783
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:269
int dd_is_periodic_longitude(met_t *met, int nx_glob)
Check whether the longitude grid is periodic (global coverage).
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:1662
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1759
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1833
void dd_get_rect_neighbour(const ctl_t ctl, dd_t *dd)
Determines rectangular neighbouring ranks for MPI processes.
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1911
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1812
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:651
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:2010
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:1930
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1595
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:937
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:416
void read_met_grib_levels(codes_handle **handles, const int num_messages, const ctl_t *ctl, met_t *met)
Reads meteorological variables at different vertical levels from a grib file.
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1639
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:363
#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:732
int dd_calc_subdomain_from_coords(double lon, double lat, met_t *met, ctl_t *ctl, int mpi_size, int nx_glob, int ny_glob)
Assigns rectangular subdomains to atmospheric data particles.
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:567
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:249
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1696
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1535
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:308
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2087
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:2123
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:847
void dd_communicate_particles(particle_t *particles, int *nparticles, MPI_Datatype MPI_Particle, int *neighbours, int nneighbours, ctl_t ctl)
Communicates particles between MPI processes.
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1565
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1304
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:338
void module_dd(ctl_t *ctl, atm_t *atm, cache_t *cache, dd_t *dd, met_t **met)
Manages domain decomposition and particle communication in parallel processing.
void dd_sort_help(double *a, dd_t *dd, const int np)
Reorder an array according to a permutation vector.
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:1973
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1196
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1734
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:483
void dd_assign_rect_subdomains_atm(atm_t *atm, ctl_t *ctl, dd_t *dd, int init)
Assign atmospheric particles to rectangular subdomains.
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:318
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1226
#define MPI_Datatype
Placeholder when MPI is not available.
Definition: mptrac.h:145
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:283
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1467
#define DD_NPART
Maximum number of particles to send and recieve in domain decomposition.
Definition: mptrac.h:368
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1620
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:343
void read_met_grib_grid(codes_handle **handles, int count_handles, met_t *met)
Reads global meteorological information from a grib file.
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.
void dd_register_MPI_type_particle(MPI_Datatype *MPI_Particle)
Registers a custom MPI datatype for particle structures.
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1280
#define ECC(cmd)
Execute an ECCODES command and check for errors.
Definition: mptrac.h:713
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:1010
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:683
#define NC_INQ_DIM(dimname, ptr, min, max, check)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1256
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:529
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:204
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:353
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:632
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1037
#define DD_NNMAX
Maximum number of neighbours to communicate with in domain decomposition.
Definition: mptrac.h:373
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:780
Air parcel data.
Definition: mptrac.h:3292
double time[NP]
Time [s].
Definition: mptrac.h:3298
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3307
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3304
int np
Number of air parcels.
Definition: mptrac.h:3295
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3310
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3301
Cache data structure.
Definition: mptrac.h:3347
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3368
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3356
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3359
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3353
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3365
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3362
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3350
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3379
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3385
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3394
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3415
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3391
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3409
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3412
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3406
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3400
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3421
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3424
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3403
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3418
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3397
int np
Number of pressure levels.
Definition: mptrac.h:3382
int no3c
Number of total ozone columns.
Definition: mptrac.h:3388
Climatological data.
Definition: mptrac.h:3487
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3529
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3505
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3517
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3508
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3490
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3535
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3523
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3526
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3520
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3499
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3514
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3493
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3511
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3502
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3496
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3532
Climatological data in the form of time series.
Definition: mptrac.h:3435
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3444
double time[CTS]
Time [s].
Definition: mptrac.h:3441
int ntime
Number of timesteps.
Definition: mptrac.h:3438
Climatological data in the form of zonal means.
Definition: mptrac.h:3455
double time[CT]
Time [s].
Definition: mptrac.h:3467
int np
Number of pressure levels.
Definition: mptrac.h:3464
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3473
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3476
int ntime
Number of timesteps.
Definition: mptrac.h:3458
int nlat
Number of latitudes.
Definition: mptrac.h:3461
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3470
Control parameters.
Definition: mptrac.h:2264
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3153
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2376
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3114
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3081
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2532
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:3002
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2610
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2409
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3090
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2864
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2355
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2556
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3280
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:3042
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2927
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2951
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2283
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2295
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2565
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2304
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2388
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3084
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2397
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2903
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2852
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3105
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2364
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3231
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2912
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2763
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2924
double stat_r
Search radius around station [km].
Definition: mptrac.h:3237
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2996
int met_zstd_level
ZSTD compression level (from -5 to 22).
Definition: mptrac.h:2619
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3108
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3261
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2948
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2731
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2385
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2966
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2816
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2544
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2653
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2463
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3180
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3156
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2574
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2770
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2550
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2683
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2750
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2427
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2499
char species[LEN]
Species.
Definition: mptrac.h:2861
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3099
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3111
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2798
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2728
double met_comp_tol[METVAR]
Compression tolerance for SZ3 or ZFP.
Definition: mptrac.h:2625
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2379
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2807
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3141
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3159
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3055
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2825
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3171
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2310
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2454
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2656
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2406
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3162
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2433
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2747
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3216
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2493
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2593
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2885
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2969
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2719
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3132
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2644
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2792
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2298
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2331
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2475
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2840
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3243
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3075
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2789
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3177
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3102
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2337
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2975
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3147
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2460
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2957
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2858
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2445
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2716
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2689
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2307
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2780
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3183
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2767
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2846
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2313
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3186
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3078
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2725
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3087
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2686
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2960
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2804
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2668
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2671
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3129
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2647
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3189
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2370
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2831
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2741
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3195
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2292
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2738
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2301
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2756
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2915
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2502
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2430
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3096
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3240
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2978
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3268
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2888
int qnt_eta
Quantity array index for eta vertical coordinate.
Definition: mptrac.h:2487
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2873
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:3014
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2921
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2451
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3060
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2707
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2987
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3072
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:3023
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2328
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2319
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2529
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3249
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2580
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2822
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3219
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2421
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3126
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2607
int met_comp_prec[METVAR]
Compression precision for SZ3 or ZFP.
Definition: mptrac.h:2622
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2349
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2469
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2674
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2837
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2734
int met_dx
Stride for longitudes.
Definition: mptrac.h:2677
int qnt_destination
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2571
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2936
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2596
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2481
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2882
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2990
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2583
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2783
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2517
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2490
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2511
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2352
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3258
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2367
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2448
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2834
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2753
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2424
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2280
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2535
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2704
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2972
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2373
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3204
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2472
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2361
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3225
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2870
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3069
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3144
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2662
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2316
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2638
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3165
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2559
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2553
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2274
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:3039
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2939
int nens
Number of ensembles.
Definition: mptrac.h:3117
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2340
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2400
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2773
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3192
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2710
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2358
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3048
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2984
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2478
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2813
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3120
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2993
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:2600
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3093
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2496
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3234
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2538
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3011
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3168
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2562
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2523
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2695
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2810
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2590
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2849
int dd_nbr_neighbours
Domain decomposition number of neighbours to communicate with.
Definition: mptrac.h:3277
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2641
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2945
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2412
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2484
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2828
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2918
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2418
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2843
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2930
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2894
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2526
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2514
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3150
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2879
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2325
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3123
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3213
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3051
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2722
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2942
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:3045
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2906
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3210
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2628
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:3029
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2692
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3198
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2954
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2394
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2442
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2457
int qnt_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2568
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2713
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3207
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2415
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:3032
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3201
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2665
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2616
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2981
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2547
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3066
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:3020
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2963
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2897
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2659
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2631
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3138
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3246
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:3026
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2343
int met_np
Number of target pressure levels.
Definition: mptrac.h:2698
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2289
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2613
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2909
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2439
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3255
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2900
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2650
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3008
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2786
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2819
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2505
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev,...
Definition: mptrac.h:2777
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2436
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2541
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2334
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2933
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3063
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2876
int met_cms_heur
cmultiscale coarsening heuristics (0=default, 1=mean diff, 2=median diff, 3=max diff).
Definition: mptrac.h:2635
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:3017
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2466
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2322
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:3005
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2999
int met_dy
Stride for latitudes.
Definition: mptrac.h:2680
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2520
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2801
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2855
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3271
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2286
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2744
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2382
double t_start
Start time of simulation [s].
Definition: mptrac.h:2577
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2277
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2701
int nq
Number of quantities.
Definition: mptrac.h:2271
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2867
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3222
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3252
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3228
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2795
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3174
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3274
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2346
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:2604
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2391
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2403
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3135
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2508
Domain decomposition data structure.
Definition: mptrac.h:3720
size_t halo_bnd_count[4]
Hyperslab of boundary halos count.
Definition: mptrac.h:3766
int halo_offset_end
Hyperslab of boundary halos count.
Definition: mptrac.h:3772
int rank
Rank of node.
Definition: mptrac.h:3727
int neighbours[DD_NNMAX]
Rank of neighbouring nodes.
Definition: mptrac.h:3733
double subdomain_lon_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3748
size_t halo_bnd_start[4]
Hyperslab of boundary halos start.
Definition: mptrac.h:3763
double subdomain_lat_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3751
int init
Shows if domain decomposition was initialized.
Definition: mptrac.h:3779
double subdomain_lon_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3745
int halo_offset_start
Hyperslab of boundary halos count.
Definition: mptrac.h:3769
size_t subdomain_count[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3760
size_t subdomain_start[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3757
int size
Size of node.
Definition: mptrac.h:3730
double subdomain_lat_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3754
Meteo data structure.
Definition: mptrac.h:3546
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3624
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3612
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3684
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3654
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3711
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3675
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3648
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3669
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3630
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3573
int nx
Number of longitudes.
Definition: mptrac.h:3552
int ny
Number of latitudes.
Definition: mptrac.h:3555
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3606
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3585
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3681
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3594
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3705
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3702
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3591
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3678
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3693
int np
Number of pressure levels.
Definition: mptrac.h:3558
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3660
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3588
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3663
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3600
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3699
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3633
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3645
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3651
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3639
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3564
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3618
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3621
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3615
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3597
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3657
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3666
int npl
Number of model levels.
Definition: mptrac.h:3561
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3609
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3687
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3627
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3672
double eta[EP]
Model level eta values.
Definition: mptrac.h:3582
double time
Time [s].
Definition: mptrac.h:3549
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3636
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3603
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3696
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3642
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3576
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3567
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3690
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3579
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3708
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3570
Particle data.
Definition: mptrac.h:3321
double p
Pressure [hPa].
Definition: mptrac.h:3327
double lat
Latitude [deg].
Definition: mptrac.h:3333
double time
Time [s].
Definition: mptrac.h:3324
double lon
Longitude [deg].
Definition: mptrac.h:3330
double q[NQ]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3336