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.), csza_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 csza = cos_sza(t, lon, lat);
109 const double denom = (csza >= csza_thresh) ? csza : csza_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.), csza_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 csza =
134 cos_sza(clim->oh.time[it], lon, clim->oh.lat[iy]);
135 const double denom = (csza >= csza_thresh) ? csza : csza_thresh;
136 sum += exp(-ctl->oh_chem_beta / denom);
137 n++;
138 }
139
140 /* Apply scaling factor to OH data... */
141 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
142 }
143}
144
145/*****************************************************************************/
146
148 const double rate[CP][CSZA][CO3],
149 const clim_photo_t *photo,
150 const double p,
151 const double sza,
152 const double o3c) {
153
154 /* Check pressure range... */
155 double p_help = p;
156 if (p < photo->p[photo->np - 1])
157 p_help = photo->p[photo->np - 1];
158 else if (p > photo->p[0])
159 p_help = photo->p[0];
160
161 /* Check sza range... */
162 double sza_help = sza;
163 if (sza < photo->sza[0])
164 sza_help = photo->sza[0];
165 else if (sza > photo->sza[photo->nsza - 1])
166 sza_help = photo->sza[photo->nsza - 1];
167
168 /* Check ozone column range... */
169 double o3c_help = o3c;
170 if (o3c < photo->o3c[0])
171 o3c_help = photo->o3c[0];
172 else if (o3c > photo->o3c[photo->no3c - 1])
173 o3c_help = photo->o3c[photo->no3c - 1];
174
175 /* Get indices... */
176 const int ip = locate_irr(photo->p, photo->np, p_help);
177 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
178 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
179
180 /* Interpolate photolysis rate... */
181 const double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
182 photo->p[ip + 1], rate[ip + 1][isza][io3c],
183 p_help);
184 const double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
185 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1],
186 p_help);
187 const double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
188 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c],
189 p_help);
190 const double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
191 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
192 p_help);
193 const double aux0 =
194 LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
195 const double aux1 =
196 LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
197 const double aux =
198 LIN(photo->sza[isza], aux0, photo->sza[isza + 1], aux1, sza_help);
199 return MAX(aux, 0.0);
200}
201
202/*****************************************************************************/
203
205 const clim_t *clim,
206 const double t,
207 const double lat) {
208
209 /* Get seconds since begin of year... */
210 double sec = FMOD(t, 365.25 * 86400.);
211 while (sec < 0)
212 sec += 365.25 * 86400.;
213
214 /* Get indices... */
215 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
216 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
217
218 /* Interpolate tropopause pressure... */
219 const double p0 = LIN(clim->tropo_lat[ilat],
220 clim->tropo[isec][ilat],
221 clim->tropo_lat[ilat + 1],
222 clim->tropo[isec][ilat + 1], lat);
223 const double p1 = LIN(clim->tropo_lat[ilat],
224 clim->tropo[isec + 1][ilat],
225 clim->tropo_lat[ilat + 1],
226 clim->tropo[isec + 1][ilat + 1], lat);
227 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
228}
229
230/*****************************************************************************/
231
233 clim_t *clim) {
234
235 /* Write info... */
236 LOG(1, "Initialize tropopause data...");
237
238 /* Set time [s]... */
239 clim->tropo_ntime = 12;
240 double tropo_time[12] = {
241 1209600.00, 3888000.00, 6393600.00,
242 9072000.00, 11664000.00, 14342400.00,
243 16934400.00, 19612800.00, 22291200.00,
244 24883200.00, 27561600.00, 30153600.00
245 };
246 memcpy(clim->tropo_time, tropo_time, sizeof(clim->tropo_time));
247
248 /* Set latitudes [deg]... */
249 clim->tropo_nlat = 73;
250 const double tropo_lat[73] = {
251 -90, -87.5, -85, -82.5, -80, -77.5, -75, -72.5, -70, -67.5,
252 -65, -62.5, -60, -57.5, -55, -52.5, -50, -47.5, -45, -42.5,
253 -40, -37.5, -35, -32.5, -30, -27.5, -25, -22.5, -20, -17.5,
254 -15, -12.5, -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10, 12.5,
255 15, 17.5, 20, 22.5, 25, 27.5, 30, 32.5, 35, 37.5, 40, 42.5,
256 45, 47.5, 50, 52.5, 55, 57.5, 60, 62.5, 65, 67.5, 70, 72.5,
257 75, 77.5, 80, 82.5, 85, 87.5, 90
258 };
259 memcpy(clim->tropo_lat, tropo_lat, sizeof(clim->tropo_lat));
260
261 /* Set tropopause pressure [hPa] (NCEP/NCAR Reanalysis 1)... */
262 const double tropo[12][73] = {
263 {324.1, 325.6, 325, 324.3, 322.5, 319.7, 314, 307.2, 301.8, 299.6,
264 297.1, 292.2, 285.6, 276.1, 264, 248.9, 231.9, 213.5, 194.4,
265 175.3, 157, 140.4, 126.7, 116.3, 109.5, 105.4, 103, 101.4, 100.4,
266 99.69, 99.19, 98.84, 98.56, 98.39, 98.39, 98.42, 98.44, 98.54,
267 98.68, 98.81, 98.89, 98.96, 99.12, 99.65, 101.4, 105.4, 113.5, 128,
268 152.1, 184.7, 214, 234.1, 247.3, 255.8, 262.6, 267.7, 271.7, 275,
269 277.2, 279, 280.1, 280.4, 280.6, 280.1, 279.3, 278.3, 276.8, 275.8,
270 275.3, 275.6, 275.4, 274.1, 273.5},
271 {337.3, 338.7, 337.8, 336.4, 333, 328.8, 321.1, 312.6, 306.6, 303.7,
272 300.2, 293.8, 285.4, 273.8, 259.6, 242.7, 224.4, 205.2, 186, 167.5,
273 150.3, 135, 122.8, 113.9, 108.2, 104.7, 102.5, 101.1, 100.2, 99.42,
274 98.88, 98.52, 98.25, 98.09, 98.07, 98.1, 98.12, 98.2, 98.25, 98.27,
275 98.26, 98.27, 98.36, 98.79, 100.2, 104.2, 113.7, 131.2, 159.5, 193,
276 220.4, 238.1, 250.2, 258.1, 264.7, 269.7, 273.7, 277.3, 280.2, 282.8,
277 284.9, 286.5, 288.1, 288.8, 289, 288.5, 287.2, 286.3, 286.1, 287.2,
278 287.5, 286.2, 285.8},
279 {335, 336, 335.7, 335.1, 332.3, 328.1, 320.6, 311.8, 305.1, 301.9,
280 297.6, 290, 280.4, 268.3, 254.6, 239.6, 223.9, 207.9, 192.2, 176.9,
281 161.7, 146.4, 132.2, 120.6, 112.3, 107.2, 104.3, 102.4, 101.3,
282 100.4, 99.86, 99.47, 99.16, 98.97, 98.94, 98.97, 99, 99.09, 99.2,
283 99.31, 99.35, 99.41, 99.51, 99.86, 101.1, 104.9, 114.3, 131, 156.8,
284 186.3, 209.3, 224.6, 236.8, 246.3, 254.9, 262.3, 268.8, 274.8,
285 279.9, 284.6, 288.6, 291.6, 294.9, 297.5, 299.8, 301.8, 303.1,
286 304.3, 304.9, 306, 306.6, 306.2, 306},
287 {306.2, 306.7, 305.7, 307.1, 307.3, 306.4, 301.8, 296.2, 292.4,
288 290.3, 287.1, 280.9, 273.4, 264.3, 254.1, 242.8, 231, 219, 207.2,
289 195.5, 183.3, 169.7, 154.7, 138.7, 124.1, 113.6, 107.8, 104.7,
290 102.8, 101.7, 100.9, 100.4, 100, 99.79, 99.7, 99.66, 99.68, 99.79,
291 99.94, 100.2, 100.5, 100.9, 101.4, 102.1, 103.4, 107, 115.2, 129.1,
292 148.7, 171, 190.8, 205.6, 218.4, 229.4, 239.6, 248.6, 256.5,
293 263.7, 270.3, 276.6, 282.6, 288.1, 294.5, 300.4, 306.3, 311.4,
294 315.1, 318.3, 320.3, 322.2, 322.8, 321.5, 321.1},
295 {266.5, 264.9, 260.8, 261, 262, 263, 261.3, 259.7, 259.2, 259.8,
296 260.1, 258.6, 256.7, 253.6, 249.5, 243.9, 237.4, 230, 222.1, 213.9,
297 205, 194.4, 180.4, 161.8, 140.7, 122.9, 112.1, 106.7, 104.1, 102.7,
298 101.8, 101.4, 101.1, 101, 101, 101, 101.1, 101.2, 101.5, 101.9,
299 102.4, 103, 103.8, 104.9, 106.8, 110.1, 115.6, 124, 135.2, 148.9,
300 165.2, 181.3, 198, 211.8, 223.5, 233.8, 242.9, 251.5, 259, 266.2,
301 273.1, 279.2, 286.2, 292.8, 299.6, 306, 311.1, 315.5, 318.8, 322.6,
302 325.3, 325.8, 325.8},
303 {220.1, 218.1, 210.8, 207.2, 207.6, 210.5, 211.4, 213.5, 217.3,
304 222.4, 227.9, 232.8, 237.4, 240.8, 242.8, 243, 241.5, 238.6, 234.2,
305 228.5, 221, 210.7, 195.1, 172.9, 147.8, 127.6, 115.6, 109.9, 107.1,
306 105.7, 105, 104.8, 104.8, 104.9, 105, 105.1, 105.3, 105.5, 105.8,
307 106.4, 107, 107.6, 108.1, 108.8, 110, 111.8, 114.2, 117.4, 121.6,
308 127.9, 137.3, 151.2, 169.5, 189, 205.8, 218.9, 229.1, 237.8, 245,
309 251.5, 257.1, 262.3, 268.2, 274, 280.4, 286.7, 292.4, 297.9, 302.9,
310 308.5, 312.2, 313.1, 313.3},
311 {187.4, 184.5, 173.3, 166.1, 165.4, 167.8, 169.6, 173.6, 179.6,
312 187.9, 198.9, 210, 220.5, 229.2, 235.7, 239.9, 241.8, 241.6, 239.6,
313 235.8, 229.4, 218.6, 200.9, 175.9, 149.4, 129.4, 118.3, 113.1,
314 110.8, 109.7, 109.3, 109.4, 109.7, 110, 110.2, 110.4, 110.5, 110.7,
315 111, 111.4, 111.8, 112.1, 112.3, 112.7, 113.2, 113.9, 115, 116.4,
316 117.9, 120.4, 124.1, 130.9, 142.2, 159.6, 179.6, 198.5, 212.9,
317 224.2, 232.7, 239.1, 243.8, 247.7, 252.4, 257.3, 263.2, 269.5,
318 275.4, 281.1, 286.3, 292, 296.3, 298.2, 298.8},
319 {166, 166.4, 155.7, 148.3, 147.1, 149, 152.1, 157, 163.6, 172.4,
320 185.3, 199.2, 212.6, 224, 233.2, 239.6, 243.3, 244.6, 243.6, 240.3,
321 233.9, 222.6, 203.7, 177, 149.5, 129.7, 119, 114, 111.7, 110.7,
322 110.3, 110.3, 110.6, 110.9, 111.1, 111.3, 111.5, 111.6, 111.9,
323 112.2, 112.5, 112.6, 112.8, 113, 113.4, 114, 115.1, 116.5, 118.3,
324 120.9, 124.4, 130.2, 139.4, 154.6, 173.8, 193.1, 208.1, 220.4,
325 230.1, 238.2, 244.7, 249.5, 254.5, 259.3, 264.5, 269.4, 273.7,
326 278.2, 282.6, 287.4, 290.9, 292.5, 293},
327 {171.9, 172.8, 166.2, 162.3, 161.4, 162.5, 165.2, 169.6, 175.3,
328 183.1, 193.8, 205.9, 218.3, 229.6, 238.5, 244.3, 246.9, 246.7,
329 243.8, 238.4, 230.2, 217.9, 199.6, 174.9, 148.9, 129.8, 119.5,
330 114.8, 112.3, 110.9, 110.3, 110.1, 110.2, 110.3, 110.4, 110.5,
331 110.6, 110.8, 111, 111.4, 111.8, 112, 112.2, 112.4, 112.9, 113.6,
332 114.7, 116.3, 118.4, 121.9, 127.1, 136.1, 149.8, 168.4, 186.9,
333 203.3, 217, 229.1, 238.7, 247, 254, 259.3, 264.3, 268.3, 272.5,
334 276.6, 280.4, 284.4, 288.4, 293.3, 297.2, 298.7, 299.1},
335 {191.6, 192.2, 189, 188.1, 190.2, 193.7, 197.8, 202.9, 208.5,
336 215.6, 224.2, 233.1, 241.2, 247.3, 250.8, 251.3, 248.9, 244.2,
337 237.3, 228.4, 217.2, 202.9, 184.5, 162.5, 140.7, 124.8, 116.2,
338 111.8, 109.4, 107.9, 107, 106.7, 106.6, 106.6, 106.7, 106.7,
339 106.8, 107, 107.4, 108, 108.7, 109.3, 109.8, 110.4, 111.2,
340 112.4, 114.2, 116.9, 121.1, 127.9, 139.3, 155.2, 173.6, 190.7,
341 206.1, 220.1, 232.3, 243, 251.8, 259.2, 265.7, 270.6, 275.3,
342 279.3, 283.3, 286.9, 289.7, 292.8, 296.1, 300.5, 303.9, 304.8,
343 305.1},
344 {241.5, 239.6, 236.8, 237.4, 239.4, 242.3, 244.2, 246.4, 249.2,
345 253.6, 258.6, 262.7, 264.8, 264.2, 260.6, 254.1, 245.5, 235.3,
346 223.9, 211.7, 198.3, 183.1, 165.6, 147.1, 130.5, 118.7, 111.9,
347 108.1, 105.8, 104.3, 103.4, 102.8, 102.5, 102.4, 102.5, 102.5,
348 102.5, 102.7, 103.1, 103.8, 104.6, 105.4, 106.1, 107, 108.2,
349 109.9, 112.8, 117.5, 126, 140.4, 161, 181.9, 201.2, 216.8, 230.4,
350 241.8, 251.4, 259.9, 266.9, 272.8, 277.4, 280.4, 282.9, 284.6,
351 286.1, 287.4, 288.3, 289.5, 290.9, 294.2, 296.9, 297.5, 297.6},
352 {301.2, 300.3, 296.6, 295.4, 295, 294.3, 291.2, 287.4, 284.9, 284.7,
353 284.1, 281.5, 277.1, 270.4, 261.7, 250.6, 237.6, 223.1, 207.9, 192,
354 175.8, 158.8, 142.1, 127.6, 116.8, 109.9, 106, 103.6, 102.1, 101.1,
355 100.4, 99.96, 99.6, 99.37, 99.32, 99.32, 99.31, 99.46, 99.77, 100.2,
356 100.7, 101.3, 101.8, 102.7, 104.1, 106.8, 111.9, 121, 136.7, 160,
357 186.9, 209.9, 228.1, 241.2, 251.5, 259.5, 265.7, 270.9, 274.8, 278,
358 280.3, 281.8, 283, 283.3, 283.7, 283.8, 283, 282.2, 281.2, 281.4,
359 281.7, 281.1, 281.2}
360 };
361 memcpy(clim->tropo, tropo, sizeof(clim->tropo));
362
363 /* Get range... */
364 double tropomin = 1e99, tropomax = -1e99;
365 for (int it = 0; it < clim->tropo_ntime; it++)
366 for (int iy = 0; iy < clim->tropo_nlat; iy++) {
367 tropomin = MIN(tropomin, clim->tropo[it][iy]);
368 tropomax = MAX(tropomax, clim->tropo[it][iy]);
369 }
370
371 /* Write info... */
372 LOG(2, "Number of time steps: %d", clim->tropo_ntime);
373 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
374 clim->tropo_time[0], clim->tropo_time[1],
375 clim->tropo_time[clim->tropo_ntime - 1]);
376 LOG(2, "Number of latitudes: %d", clim->tropo_nlat);
377 LOG(2, "Latitudes: %g, %g ... %g deg",
378 clim->tropo_lat[0], clim->tropo_lat[1],
379 clim->tropo_lat[clim->tropo_nlat - 1]);
380 LOG(2, "Tropopause altitude range: %g ... %g hPa", Z(tropomax),
381 Z(tropomin));
382 LOG(2, "Tropopause pressure range: %g ... %g hPa", tropomin, tropomax);
383}
384
385/*****************************************************************************/
386
387double clim_ts(
388 const clim_ts_t *ts,
389 const double t) {
390
391 /* Interpolate... */
392 if (t <= ts->time[0])
393 return ts->vmr[0];
394 else if (t >= ts->time[ts->ntime - 1])
395 return ts->vmr[ts->ntime - 1];
396 else {
397 const int idx = locate_irr(ts->time, ts->ntime, t);
398 return LIN(ts->time[idx], ts->vmr[idx],
399 ts->time[idx + 1], ts->vmr[idx + 1], t);
400 }
401}
402
403/*****************************************************************************/
404
405double clim_zm(
406 const clim_zm_t *zm,
407 const double t,
408 const double lat,
409 const double p) {
410
411 /* Get seconds since begin of year... */
412 double sec = FMOD(t, 365.25 * 86400.);
413 while (sec < 0)
414 sec += 365.25 * 86400.;
415
416 /* Check pressure range... */
417 double p_help = p;
418 if (p < zm->p[zm->np - 1])
419 p_help = zm->p[zm->np - 1];
420 else if (p > zm->p[0])
421 p_help = zm->p[0];
422
423 /* Check latitude range... */
424 double lat_help = lat;
425 if (lat < zm->lat[0])
426 lat_help = zm->lat[0];
427 else if (lat > zm->lat[zm->nlat - 1])
428 lat_help = zm->lat[zm->nlat - 1];
429
430 /* Get indices... */
431 const int isec = locate_irr(zm->time, zm->ntime, sec);
432 const int ilat = locate_reg(zm->lat, zm->nlat, lat_help);
433 const int ip = locate_irr(zm->p, zm->np, p_help);
434
435 /* Interpolate climatology data... */
436 const double aux00 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat],
437 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat],
438 p_help);
439 const double aux01 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat + 1],
440 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat + 1],
441 p_help);
442 const double aux10 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat],
443 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat],
444 p_help);
445 const double aux11 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat + 1],
446 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat + 1],
447 p_help);
448 const double aux0 =
449 LIN(zm->lat[ilat], aux00, zm->lat[ilat + 1], aux01, lat_help);
450 const double aux1 =
451 LIN(zm->lat[ilat], aux10, zm->lat[ilat + 1], aux11, lat_help);
452 const double aux = LIN(zm->time[isec], aux0, zm->time[isec + 1], aux1, sec);
453 return MAX(aux, 0.0);
454}
455
456/*****************************************************************************/
457
458#ifdef CMS
459void compress_cms(
460 const ctl_t *ctl,
461 const char *varname,
462 float *array,
463 const size_t nx,
464 const size_t ny,
465 const size_t np,
466 const double *plev,
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 = ctl->met_cms_nd0x;
481 const int Nd0_y = ctl->met_cms_nd0y;
482 const int max_level_grid = ctl->met_cms_maxlev;
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 const double bias = gsl_stats_mean(tmp_diff, 1, nxy);
635 const double stddev = gsl_stats_sd_m(tmp_diff, 1, nxy, bias);
636 const double rmse = sqrt(SQR(bias) + SQR(stddev));
637 const double nrmse = rmse / gsl_stats_sd(tmp_org, 1, nxy);
638 LOG(2,
639 "cmultiscale: var= %s / lev= %lu / plev= %g / ratio= %g / rho= %g"
640 " / mean= %g / sd= %g / min= %g / max= %g / NRMSE= %g", varname,
641 ip, plev[ip], cms_compression_rate(cms_ptr[ip], cms_sol[ip]),
642 gsl_stats_correlation(tmp_cms, 1, tmp_org, 1, nxy), bias, stddev,
643 gsl_stats_min(tmp_diff, 1, nxy), gsl_stats_max(tmp_diff, 1, nxy),
644 nrmse);
645
646 /* Calculate mean compression ratio... */
647 cr += cms_compression_rate(cms_ptr[ip], cms_sol[ip]) / (double) np;
648
649 /* Save binary data... */
650 if (ctl->met_cms_zstd == 1)
651 cms_save_zstd_sol(cms_sol[ip], inout, 3);
652 else
653 cms_save_sol(cms_sol[ip], inout);
654
655 /* Free... */
656 cms_delete_sol(cms_sol[ip]);
657 cms_delete_module(cms_ptr[ip]);
658 free(tmp_cms);
659 free(tmp_org);
660 free(tmp_diff);
661 }
662 }
663
664 /* Write info... */
665 LOG(2, "Write 3-D variable: %s"
666 " (CMS, RATIO= %g, T_COARS= %g s, T_EVAL= %g s)",
667 varname, cr, t_coars, t_eval);
668 }
669
670 /* Free... */
671 cms_delete_param(cms_param);
672}
673#endif
674
675/*****************************************************************************/
676
678 const char *varname,
679 float *array,
680 const size_t nxy,
681 const size_t nz,
682 const int decompress,
683 FILE *inout) {
684
685 double min[EP], max[EP], off[EP], scl[EP];
686
687 unsigned short *sarray;
688
689 /* Allocate... */
690 ALLOC(sarray, unsigned short,
691 nxy * nz);
692
693 /* Read compressed stream and decompress array... */
694 if (decompress) {
695
696 /* Write info... */
697 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
698 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
699
700 /* Read data... */
701 FREAD(&scl, double,
702 nz,
703 inout);
704 FREAD(&off, double,
705 nz,
706 inout);
707 FREAD(sarray, unsigned short,
708 nxy * nz,
709 inout);
710
711 /* Convert to float... */
712#pragma omp parallel for default(shared)
713 for (size_t ixy = 0; ixy < nxy; ixy++)
714 for (size_t iz = 0; iz < nz; iz++)
715 array[ixy * nz + iz]
716 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
717 }
718
719 /* Compress array and output compressed stream... */
720 else {
721
722 /* Write info... */
723 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
724 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
725
726 /* Get range... */
727 for (size_t iz = 0; iz < nz; iz++) {
728 min[iz] = array[iz];
729 max[iz] = array[iz];
730 }
731 for (size_t ixy = 1; ixy < nxy; ixy++)
732 for (size_t iz = 0; iz < nz; iz++) {
733 if (array[ixy * nz + iz] < min[iz])
734 min[iz] = array[ixy * nz + iz];
735 if (array[ixy * nz + iz] > max[iz])
736 max[iz] = array[ixy * nz + iz];
737 }
738
739 /* Get offset and scaling factor... */
740 for (size_t iz = 0; iz < nz; iz++) {
741 scl[iz] = (max[iz] - min[iz]) / 65533.;
742 off[iz] = min[iz];
743 }
744
745 /* Convert to short... */
746#pragma omp parallel for default(shared)
747 for (size_t ixy = 0; ixy < nxy; ixy++)
748 for (size_t iz = 0; iz < nz; iz++)
749 if (scl[iz] != 0)
750 sarray[ixy * nz + iz] = (unsigned short)
751 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
752 else
753 sarray[ixy * nz + iz] = 0;
754
755 /* Write data... */
756 FWRITE(&scl, double,
757 nz,
758 inout);
759 FWRITE(&off, double,
760 nz,
761 inout);
762 FWRITE(sarray, unsigned short,
763 nxy * nz,
764 inout);
765 }
766
767 /* Free... */
768 free(sarray);
769}
770
771/*****************************************************************************/
772
773#ifdef SZ3
774void compress_sz3(
775 const char *varname,
776 float *array,
777 int nx,
778 int ny,
779 int nz,
780 int precision,
781 double tolerance,
782 int decompress,
783 FILE *inout) {
784 if ((precision > 0) == (tolerance > 0.0))
785 ERRMSG("Exactly one of precision or tolerance must be set for SZ3!");
786
787 size_t r1 = (size_t) nx, r2 = (size_t) ny, r3 = (size_t) nz,
788 outSize = 0, total_elems = r1 * r2 * r3;
789
790 unsigned char *bytes = NULL;
791
792 /* Read compressed stream and decompress array... */
793 if (decompress) {
794
795 size_t sz3size;
796 FREAD(&sz3size, size_t,
797 1,
798 inout);
799 ALLOC(bytes, char,
800 sz3size);
801 FREAD(bytes, unsigned char,
802 sz3size,
803 inout);
804
805 void *outData = SZ_decompress(SZ_FLOAT, bytes, sz3size, 0, 0, r3, r2, r1);
806 if (!outData)
807 ERRMSG("Decompression failed!");
808
809 memcpy(array, outData, total_elems * sizeof(float));
810
811 free(outData);
812 free(bytes);
813
814 LOG(2, "Read 3-D variable: %s (SZ3, PREC=%d, TOL=%g, RATIO=%g)",
815 varname, precision, tolerance,
816 (double) (total_elems * sizeof(float)) / (double) sz3size);
817 }
818
819 /* Compress array and output compressed stream... */
820 else {
821
822 const int errBoundMode = (precision > 0) ? REL : ABS;
823 const double absBound = (errBoundMode == ABS) ? tolerance : 0.0;
824 const double relBound =
825 (errBoundMode == REL) ? pow(2.0, -(double) precision) : 0.0;
826
827 bytes = SZ_compress_args(SZ_FLOAT, array, &outSize,
828 errBoundMode, absBound, relBound, 0.0,
829 0, 0, r3, r2, r1);
830 if (!bytes || outSize == 0)
831 ERRMSG("Compression failed!");
832
833 FWRITE(&outSize, size_t,
834 1,
835 inout);
836 FWRITE(bytes, unsigned char,
837 outSize,
838 inout);
839
840 free(bytes);
841
842 LOG(2, "Write 3-D variable: %s (SZ3, PREC=%d, TOL=%g, RATIO=%g)",
843 varname, precision, tolerance,
844 (double) (total_elems * sizeof(float)) / (double) outSize);
845 }
846}
847#endif
848
849/*****************************************************************************/
850
851#ifdef ZFP
852void compress_zfp(
853 const char *varname,
854 float *array,
855 const int nx,
856 const int ny,
857 const int nz,
858 const int precision,
859 const double tolerance,
860 const int decompress,
861 FILE *inout) {
862
863 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
864 const size_t snx = (size_t) nx;
865 const size_t sny = (size_t) ny;
866 const size_t snz = (size_t) nz;
867 const zfp_type type = zfp_type_float;
868 zfp_field *field = zfp_field_3d(array, type, snx, sny, snz);
869
870 /* Allocate meta data for a compressed stream... */
871 zfp_stream *zfp = zfp_stream_open(NULL);
872 if (!field || !zfp)
873 ERRMSG("Failed to allocate zfp structures!");
874
875 /* Set compression mode... */
876 int actual_prec = 0;
877 double actual_tol = 0;
878 if ((precision > 0 && tolerance > 0) || (precision <= 0 && tolerance <= 0)) {
879 ERRMSG("Exactly one of precision or tolerance must be set for zfp!");
880 } else if (precision > 0)
881 actual_prec =
882 (int) zfp_stream_set_precision(zfp, (unsigned int) precision);
883 else if (tolerance > 0)
884 actual_tol = zfp_stream_set_accuracy(zfp, tolerance);
885
886 /* Allocate buffer for compressed data... */
887 const size_t bufsize = zfp_stream_maximum_size(zfp, field);
888 void *buffer;
889 ALLOC(buffer, char,
890 bufsize);
891
892 /* Associate bit stream with allocated buffer... */
893 bitstream *stream = stream_open(buffer, bufsize);
894 zfp_stream_set_bit_stream(zfp, stream);
895 zfp_stream_rewind(zfp);
896
897 /* Read compressed stream and decompress array... */
898 size_t zfpsize;
899 if (decompress) {
900 FREAD(&zfpsize, size_t,
901 1,
902 inout);
903 if (zfpsize > bufsize)
904 ERRMSG("Compressed data size exceeds allocated buffer!");
905 FREAD(buffer, unsigned char,
906 zfpsize,
907 inout);
908 if (!zfp_decompress(zfp, field)) {
909 ERRMSG("Decompression failed!");
910 }
911 const double cr =
912 ((double) (snx * sny * snz * sizeof(float))) / (double) zfpsize;
913 const double bpv = (8.0 * (double) zfpsize) / (double) (snx * sny * snz);
914 LOG(2,
915 "Read 3-D variable: %s (ZFP, PREC= %d, TOL= %g, RATIO= %g, BPV= %g)",
916 varname, actual_prec, actual_tol, cr, bpv);
917 }
918
919 /* Compress array and output compressed stream... */
920 else {
921 zfpsize = zfp_compress(zfp, field);
922 if (!zfpsize) {
923 ERRMSG("Compression failed!");
924 } else {
925 FWRITE(&zfpsize, size_t,
926 1,
927 inout);
928 FWRITE(buffer, unsigned char,
929 zfpsize,
930 inout);
931 }
932 const double cr =
933 ((double) (snx * sny * snz * sizeof(float))) / (double) zfpsize;
934 const double bpv = (8.0 * (double) zfpsize) / (double) (snx * sny * snz);
935 LOG(2,
936 "Write 3-D variable: %s (ZFP, PREC= %d, TOL= %g, RATIO= %g, BPV= %g)",
937 varname, actual_prec, actual_tol, cr, bpv);
938 }
939
940 /* Free... */
941 zfp_field_free(field);
942 stream_close(stream);
943 zfp_stream_close(zfp);
944 free(buffer);
945}
946#endif
947
948/*****************************************************************************/
949
950#ifdef ZSTD
951void compress_zstd(
952 const char *varname,
953 float *array,
954 const size_t n,
955 const int decompress,
956 const int level,
957 FILE *inout) {
958
959 /* Get buffer sizes... */
960 const size_t uncomprLen = n * sizeof(float);
961 size_t compsize, comprLen = ZSTD_compressBound(uncomprLen);
962
963 /* Allocate... */
964 char *compr = calloc(comprLen, 1);
965 if (!compr)
966 ERRMSG("Memory allocation failed!");
967 char *uncompr = (char *) array;
968
969 /* Read compressed stream and decompress array... */
970 if (decompress) {
971 FREAD(&comprLen, size_t,
972 1,
973 inout);
974 FREAD(compr, unsigned char,
975 comprLen,
976 inout);
977 compsize = ZSTD_decompress(uncompr, uncomprLen, compr, comprLen);
978 if (ZSTD_isError(compsize) || compsize != uncomprLen)
979 ERRMSG("Decompression failed or size mismatch!");
980 LOG(2, "Read 3-D variable: %s (ZSTD, RATIO= %g)",
981 varname, ((double) uncomprLen) / (double) comprLen);
982 }
983
984 /* Compress array and output compressed stream... */
985 else {
986 compsize = ZSTD_compress(compr, comprLen, uncompr, uncomprLen, level);
987 if (ZSTD_isError(compsize)) {
988 ERRMSG("Compression failed!");
989 } else {
990 FWRITE(&compsize, size_t,
991 1,
992 inout);
993 FWRITE(compr, unsigned char,
994 compsize,
995 inout);
996 }
997 LOG(2, "Write 3-D variable: %s (ZSTD, RATIO= %g)",
998 varname, ((double) uncomprLen) / (double) compsize);
999 }
1000
1001 /* Free... */
1002 free(compr);
1003}
1004#endif
1005
1006/*****************************************************************************/
1007
1008double cos_sza(
1009 const double sec,
1010 const double lon,
1011 const double lat) {
1012
1013 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
1014 const double D = sec / 86400 - 0.5;
1015
1016 /* Geocentric apparent ecliptic longitude [rad]... */
1017 const double g = DEG2RAD(357.529 + 0.98560028 * D);
1018 const double q = 280.459 + 0.98564736 * D;
1019 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
1020
1021 /* Mean obliquity of the ecliptic [rad]... */
1022 const double e = DEG2RAD(23.439 - 0.00000036 * D);
1023
1024 /* Declination [rad]... */
1025 const double sindec = sin(e) * sin(L);
1026
1027 /* Right ascension [rad]... */
1028 const double ra = atan2(cos(e) * sin(L), cos(L));
1029
1030 /* Greenwich Mean Sidereal Time [h]... */
1031 const double GMST = 18.697374558 + 24.06570982441908 * D;
1032
1033 /* Local Sidereal Time [h]... */
1034 const double LST = GMST + lon / 15;
1035
1036 /* Hour angle [rad]... */
1037 const double h = LST / 12 * M_PI - ra;
1038
1039 /* Convert latitude... */
1040 const double lat_help = DEG2RAD(lat);
1041
1042 /* Return cosine of solar zenith angle... */
1043 return sin(lat_help) * sindec + cos(lat_help) * sqrt(1 -
1044 SQR(sindec)) * cos(h);
1045}
1046
1047/*****************************************************************************/
1048
1050 const int year,
1051 const int mon,
1052 const int day,
1053 int *doy) {
1054
1055 const int
1056 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1057 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1058
1059 /* Get day of year... */
1060 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
1061 *doy = d0l[mon - 1] + day - 1;
1062 else
1063 *doy = d0[mon - 1] + day - 1;
1064}
1065
1066/*****************************************************************************/
1067
1068#ifdef DD
1070 atm_t *atm,
1071 ctl_t *ctl,
1072 dd_t *dd,
1073 int init) {
1074
1075 SELECT_TIMER("DD_ASSIGN_RECT_SUBDOMAINS", "DD", NVTX_GPU);
1076
1077 if (init) {
1078#ifdef _OPENACC
1079#pragma acc enter data create(dd)
1080#pragma acc update device(dd->rank, dd->subdomain_lon_min, dd->subdomain_lon_max, dd->subdomain_lat_min, dd->subdomain_lat_max)
1081#pragma acc data present(atm, ctl, dd)
1082#pragma acc parallel loop independent gang vector
1083#endif
1084 for (int ip = 0; ip < atm->np; ip++) {
1085
1086 double lont = atm->lon[ip];
1087
1088 if (lont < 0)
1089 lont += 360;
1090
1091 if (lont >= dd->subdomain_lon_min && lont < dd->subdomain_lon_max
1092 && atm->lat[ip] >= dd->subdomain_lat_min
1093 && atm->lat[ip] < dd->subdomain_lat_max) {
1094 atm->q[ctl->qnt_subdomain][ip] = dd->rank;
1095 atm->q[ctl->qnt_destination][ip] = dd->rank;
1096 } else {
1097 WARN
1098 ("DD: Particle is outside the domain (lon: %f, lat: %f, subdomain: %d, subdomain bounds: [%f, %f], [%f, %f])",
1099 atm->lon[ip], atm->lat[ip], dd->rank, dd->subdomain_lon_min,
1101 dd->subdomain_lat_max);
1102 atm->q[ctl->qnt_subdomain][ip] = -1;
1103 atm->q[ctl->qnt_destination][ip] = -1;
1104 }
1105 }
1106#ifdef _OPENACC
1107#pragma acc exit data delete(dd)
1108#endif
1109 } else {
1110
1111 /* Classify air parcels into subdomain... */
1112#ifdef _OPENACC
1113#pragma acc enter data create(dd)
1114#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)
1115#pragma acc data present(atm, ctl, dd)
1116#pragma acc parallel loop independent gang vector
1117#endif
1118 for (int ip = 0; ip < atm->np; ip++) {
1119
1120 /* Skip empty places in the particle array... */
1121 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
1122 continue;
1123
1124 double lont = atm->lon[ip];
1125 double latt = atm->lat[ip];
1126
1127 double lon_max = dd->subdomain_lon_max;
1128 double lon_min = dd->subdomain_lon_min;
1129 double lat_max = dd->subdomain_lat_max;
1130 double lat_min = dd->subdomain_lat_min;
1131
1132 if (lont < 0)
1133 lont += 360;
1134
1135 int left = (dd->rank <= ctl->dd_subdomains_meridional - 1);
1136 int right = (dd->rank >= dd->size - ctl->dd_subdomains_meridional);
1137
1138 int bound = 0;
1139 if (left)
1140 bound = (lont - lon_max > 90) ? 1 : 0;
1141 if (right)
1142 bound = (lon_min - lont > 90) ? 1 : 0;
1143
1144 if (!bound) {
1145 if ((lont >= lon_max) && (latt >= lat_max)) {
1146 // Upper right...
1147 atm->q[ctl->qnt_destination][ip] = dd->neighbours[5];
1148 LOG(4,
1149 "DD: Particle crossing to upper right: from rank %d to rank %d (lon: %f, lat: %f)",
1150 dd->rank, dd->neighbours[5], atm->lon[ip], atm->lat[ip]);
1151 } else if ((lont >= lon_max) && (latt <= lat_min)) {
1152 // Lower right...
1153 atm->q[ctl->qnt_destination][ip] = dd->neighbours[4];
1154 LOG(4,
1155 "DD: Particle crossing to lower right: from rank %d to rank %d (lon: %f, lat: %f)",
1156 dd->rank, dd->neighbours[4], atm->lon[ip], atm->lat[ip]);
1157 } else if ((lont <= lon_min) && (latt >= lat_max)) {
1158 // Upper left...
1159 atm->q[ctl->qnt_destination][ip] = dd->neighbours[2];
1160 LOG(4,
1161 "DD: Particle crossing to upper left: from rank %d to rank %d (lon: %f, lat: %f)",
1162 dd->rank, dd->neighbours[2], atm->lon[ip], atm->lat[ip]);
1163 } else if ((lont <= lon_min) && (latt <= lat_min)) {
1164 // Lower left...
1165 atm->q[ctl->qnt_destination][ip] = dd->neighbours[1];
1166 LOG(4,
1167 "DD: Particle crossing to lower left: from rank %d to rank %d (lon: %f, lat: %f)",
1168 dd->rank, dd->neighbours[1], atm->lon[ip], atm->lat[ip]);
1169 } else if (lont >= lon_max) {
1170 // Right...
1171 atm->q[ctl->qnt_destination][ip] = dd->neighbours[3];
1172 LOG(4,
1173 "DD: Particle crossing to right: from rank %d to rank %d (lon: %f, lat: %f)",
1174 dd->rank, dd->neighbours[3], atm->lon[ip], atm->lat[ip]);
1175 } else if (lont <= lon_min) {
1176 // Left...
1177 atm->q[ctl->qnt_destination][ip] = dd->neighbours[0];
1178 LOG(4,
1179 "DD: Particle crossing to left: from rank %d to rank %d (lon: %f, lat: %f)",
1180 dd->rank, dd->neighbours[0], atm->lon[ip], atm->lat[ip]);
1181 } else if (latt <= lat_min) {
1182 // Down...
1183 atm->q[ctl->qnt_destination][ip] = dd->neighbours[7];
1184 LOG(4,
1185 "DD: Particle crossing downward: from rank %d to rank %d (lon: %f, lat: %f)",
1186 dd->rank, dd->neighbours[7], atm->lon[ip], atm->lat[ip]);
1187 } else if (latt >= lat_max) {
1188 // Up...
1189 atm->q[ctl->qnt_destination][ip] = dd->neighbours[6];
1190 LOG(4,
1191 "DD: Particle crossing upward: from rank %d to rank %d (lon: %f, lat: %f)",
1192 dd->rank, dd->neighbours[6], atm->lon[ip], atm->lat[ip]);
1193 } else {
1194 // Within...
1195 atm->q[ctl->qnt_destination][ip] = dd->rank;
1196 }
1197 } else {
1198 if ((lont >= lon_max) && (latt >= lat_max)) {
1199 // Upper right...
1200 atm->q[ctl->qnt_destination][ip] = dd->neighbours[2];
1201 LOG(4,
1202 "DD: Particle crossing to upper left (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1203 dd->rank, dd->neighbours[2], atm->lon[ip], atm->lat[ip]);
1204 } else if ((lont >= lon_max) && (latt <= lat_min)) {
1205 // Lower right...
1206 atm->q[ctl->qnt_destination][ip] = dd->neighbours[1];
1207 LOG(4,
1208 "DD: Particle crossing to lower left (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1209 dd->rank, dd->neighbours[1], atm->lon[ip], atm->lat[ip]);
1210 } else if ((lont <= lon_min) && (latt >= lat_max)) {
1211 // Upper left...
1212 atm->q[ctl->qnt_destination][ip] = dd->neighbours[5];
1213 LOG(4,
1214 "DD: Particle crossing to upper right (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1215 dd->rank, dd->neighbours[5], atm->lon[ip], atm->lat[ip]);
1216 } else if ((lont <= lon_min) && (latt <= lat_min)) {
1217 // Lower left...
1218 atm->q[ctl->qnt_destination][ip] = dd->neighbours[4];
1219 LOG(4,
1220 "DD: Particle crossing to lower right (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1221 dd->rank, dd->neighbours[4], atm->lon[ip], atm->lat[ip]);
1222 } else if (lont >= lon_max) {
1223 // Right...
1224 atm->q[ctl->qnt_destination][ip] = dd->neighbours[0];
1225 LOG(4,
1226 "DD: Particle crossing to left (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1227 dd->rank, dd->neighbours[0], atm->lon[ip], atm->lat[ip]);
1228 } else if (lont <= lon_min) {
1229 // Left...
1230 atm->q[ctl->qnt_destination][ip] = dd->neighbours[3];
1231 LOG(4,
1232 "DD: Particle crossing to right (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1233 dd->rank, dd->neighbours[3], atm->lon[ip], atm->lat[ip]);
1234 } else if (latt <= lat_min) {
1235 // Down...
1236 atm->q[ctl->qnt_destination][ip] = dd->neighbours[7];
1237 LOG(4,
1238 "DD: Particle crossing downward (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1239 dd->rank, dd->neighbours[7], atm->lon[ip], atm->lat[ip]);
1240 } else if (latt >= lat_max) {
1241 // Up...
1242 atm->q[ctl->qnt_destination][ip] = dd->neighbours[6];
1243 LOG(4,
1244 "DD: Particle crossing upward (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1245 dd->rank, dd->neighbours[6], atm->lon[ip], atm->lat[ip]);
1246 } else {
1247 // Within...
1248 atm->q[ctl->qnt_destination][ip] = dd->rank;
1249 }
1250 }
1251
1252 /* Handle particles assigned to poles by wrapping coordinates and calculating proper subdomain */
1253 /*
1254 if ((int)atm->q[ctl->qnt_destination][ip] < 0) {
1255 int calculated_rank = dd_calc_subdomain_from_coords(atm->lon[ip], atm->lat[ip], met, ctl, dd->size, help_nx_glob, help_ny_glob);
1256
1257 if ((int)atm->q[ctl->qnt_destination][ip] == DD_NPOLE) {
1258 LOG(3, "DD: Particle was assigned to NORTH POLE - redirecting to subdomain %d (lon: %f, lat: %f)",
1259 calculated_rank, atm->lon[ip], atm->lat[ip]);
1260 } else if ((int)atm->q[ctl->qnt_destination][ip] == DD_SPOLE) {
1261 LOG(3, "DD: Particle was assigned to SOUTH POLE - redirecting to subdomain %d (lon: %f, lat: %f)",
1262 calculated_rank, atm->lon[ip], atm->lat[ip]);
1263 } else {
1264 LOG(2, "DD: Particle had invalid destination %d - redirecting to subdomain %d (lon: %f, lat: %f)",
1265 (int)atm->q[ctl->qnt_destination][ip], calculated_rank, atm->lon[ip], atm->lat[ip]);
1266 } */
1267
1268 /* Assign particle to the calculated subdomain */
1269 /*atm->q[ctl->qnt_destination][ip] = calculated_rank;
1270 } */
1271 }
1272#ifdef _OPENACC
1273#pragma acc exit data delete(dd)
1274#endif
1275 }
1276}
1277#endif
1278
1279/*****************************************************************************/
1280
1281#ifdef DD
1282void dd_atm2particles(
1283 atm_t *atm,
1284 particle_t *particles,
1285 ctl_t *ctl,
1286 int *nparticles,
1287 cache_t *cache,
1288 int rank) {
1289
1290 SELECT_TIMER("DD_ATM2PARTICLES", "DD", NVTX_READ);
1291
1292 /* Select the particles that will be send... */
1293#ifdef _OPENACC
1294 int npart = *nparticles;
1295#pragma acc enter data create( nparticles, particles[:DD_NPART])
1296#pragma acc update device( nparticles)
1297#pragma acc parallel loop present( atm, ctl, particles, cache, nparticles)
1298#endif
1299 for (int ip = atm->np; ip < atm->np + *nparticles; ip++)
1300 if (((int) (atm->q[ctl->qnt_destination][ip]) != rank)
1301 && ((int) (atm->q[ctl->qnt_destination][ip]) >= 0)
1302 && ((int) atm->q[ctl->qnt_subdomain][ip] >= 0)) {
1303
1304 particles[ip - atm->np].time = atm->time[ip];
1305 particles[ip - atm->np].lon = atm->lon[ip];
1306 particles[ip - atm->np].lat = atm->lat[ip];
1307 particles[ip - atm->np].p = atm->p[ip];
1308
1309 for (int iq = 0; iq < ctl->nq; iq++)
1310 particles[ip - atm->np].q[iq] = atm->q[iq][ip];
1311
1312 LOG(3,
1313 "DD: Particle being prepared for transfer: subdomain %d -> destination %d (lon: %f, lat: %f)",
1314 (int) atm->q[ctl->qnt_subdomain][ip],
1315 (int) atm->q[ctl->qnt_destination][ip], atm->lon[ip], atm->lat[ip]);
1316 atm->q[ctl->qnt_subdomain][ip] = -1;
1317 cache->dt[ip] = 0;
1318 }
1319#ifdef _OPENACC
1320#pragma acc update host( particles[:npart])
1321#pragma acc exit data delete( nparticles, particles)
1322#endif
1323}
1324#endif
1325
1326/*****************************************************************************/
1327
1328#ifdef DD
1330 double lon,
1331 double lat,
1332 met_t *met,
1333 ctl_t *ctl,
1334 int mpi_size,
1335 int nx_glob,
1336 int ny_glob) {
1337
1338 /* Wrap longitude to [0, 360) */
1339 double wrapped_lon = lon;
1340 while (wrapped_lon < 0)
1341 wrapped_lon += 360;
1342 while (wrapped_lon >= 360)
1343 wrapped_lon -= 360;
1344
1345 /* Handle polar coordinates by wrapping latitude and adjusting longitude */
1346 double wrapped_lat = lat;
1347 if (lat > 90) {
1348 /* North pole overflow: wrap latitude and flip longitude */
1349 wrapped_lat = 180 - lat;
1350 wrapped_lon = fmod(wrapped_lon + 180, 360);
1351 } else if (lat < -90) {
1352 /* South pole overflow: wrap latitude and flip longitude */
1353 wrapped_lat = -180 - lat;
1354 wrapped_lon = fmod(wrapped_lon + 180, 360);
1355 }
1356
1357 /* Get global domain ranges */
1358 /* Handle both periodic (global) and non-periodic (regional) longitude grids */
1359 double lon_range = 360.0;
1360 //if (dd_is_periodic_longitude(met, nx_glob)) {
1361 /* For global grids with periodic boundaries, use full 360 degrees */
1362 //lon_range = 360.0;
1363 //LOG(3, "Detected periodic longitude boundaries, using lon_range = 360.0");
1364 //} else {
1365 /* For regional grids, use the actual data range */
1366 //lon_range = met->lon[nx_glob - 1] - met->lon[0];
1367 //LOG(3, "Detected non-periodic longitude boundaries, using lon_range = %g", lon_range);
1368 //}
1369
1370 LOG(2, "nx_glob: %d", nx_glob);
1371
1372 double lat_range = met->lat[ny_glob - 1] - met->lat[0];
1373 double global_lon_min = met->lon[0];
1374 double global_lat_min = met->lat[0];
1375
1376 /* Calculate subdomain indices */
1377 int lon_idx =
1378 (int) ((wrapped_lon -
1379 global_lon_min) * ctl->dd_subdomains_zonal / lon_range);
1380 int lat_idx =
1381 (int) ((wrapped_lat -
1382 global_lat_min) * ctl->dd_subdomains_meridional / lat_range);
1383
1384 // print wrapped coords, ranges, mins and idxs for debugging
1385 printf
1386 ("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",
1387 lon, lat, wrapped_lon, wrapped_lat, lon_range, lat_range, global_lon_min,
1388 global_lat_min, lon_idx, lat_idx);
1389
1390 /* Clamp to valid ranges */
1391 lon_idx =
1392 (lon_idx <
1393 0) ? 0 : ((lon_idx >=
1395 1 : lon_idx);
1396 lat_idx =
1397 (lat_idx <
1398 0) ? 0 : ((lat_idx >=
1399 ctl->dd_subdomains_meridional) ? ctl->
1400 dd_subdomains_meridional - 1 : lat_idx);
1401
1402 /* Calculate rank from indices */
1403 int target_rank = lon_idx * ctl->dd_subdomains_meridional + lat_idx;
1404
1405 /* Ensure rank is within valid range */
1406 if (target_rank >= mpi_size)
1407 target_rank = mpi_size - 1;
1408 if (target_rank < 0)
1409 target_rank = 0;
1410
1411 return target_rank;
1412}
1413#endif
1414
1415/*****************************************************************************/
1416
1417#ifdef DD
1419 particle_t *particles,
1420 int *nparticles,
1421 MPI_Datatype MPI_Particle,
1422 int *neighbours,
1423 int nneighbours,
1424 ctl_t ctl) {
1425
1426 /* Initialize the buffers... */
1427 int *nbs;
1428 int *nbr;
1429 ALLOC(nbs, int,
1430 nneighbours);
1431 ALLOC(nbr, int,
1432 nneighbours);
1433 particle_t *send_buffers[DD_NNMAX] = { NULL };
1434 particle_t *recieve_buffers[DD_NNMAX] = { NULL };
1435
1436 /* Get MPI rank... */
1437 int rank;
1438 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
1439
1440 /* Infos for MPI async... */
1441 MPI_Request *requests_snd_nbr =
1442 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1443 MPI_Request *requests_rcv_nbr =
1444 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1445 MPI_Request *requests_snd_part =
1446 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1447 MPI_Request *requests_rcv_part =
1448 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1449 MPI_Status *states =
1450 (MPI_Status *) calloc((size_t) nneighbours, sizeof(MPI_Status));
1451
1452 /* Initialize with MPI_REQUEST_NULL */
1453 for (int i = 0; i < nneighbours; i++) {
1454 requests_snd_nbr[i] = MPI_REQUEST_NULL;
1455 requests_rcv_nbr[i] = MPI_REQUEST_NULL;
1456 requests_snd_part[i] = MPI_REQUEST_NULL;
1457 requests_rcv_part[i] = MPI_REQUEST_NULL;
1458 }
1459
1460 /* Sending... */
1461 for (int idest = 0; idest < nneighbours; idest++) {
1462
1463 /* Ignore poles... */
1464 if (neighbours[idest] < 0)
1465 continue;
1466
1467 SELECT_TIMER("DD_COUNT_NUMBER", "DD", NVTX_CPU);
1468 /* Count number of particles in particle array that will be send... */
1469 int help_sum = 0;
1470 for (int ip = 0; ip < *nparticles; ip++)
1471 if ((int) particles[ip].q[ctl.qnt_destination] == neighbours[idest])
1472 help_sum++;
1473 nbs[idest] = help_sum;
1474
1475 if (help_sum > 0) {
1476 LOG(3, "DD: Rank %d sending %d particles to neighbour %d (rank %d)",
1477 rank, help_sum, idest, neighbours[idest]);
1478 }
1479
1480 SELECT_TIMER("DD_SEND_NUMBER", "DD", NVTX_CPU);
1481 /* Send buffer sizes... */
1482 MPI_Isend(&nbs[idest], 1, MPI_INT,
1483 neighbours[idest], 0, MPI_COMM_WORLD, &requests_snd_nbr[idest]);
1484
1485 /* Don't send empty signals... */
1486 if (nbs[idest] == 0)
1487 continue;
1488
1489 SELECT_TIMER("DD_PREP_BUFFER", "DD", NVTX_CPU);
1490 /* Allocate buffer for sending... */
1491 ALLOC(send_buffers[idest], particle_t, nbs[idest]);
1492
1493 /* Fill the send buffer in a sorted way... */
1494 int ibs = 0;
1495 for (int ip = 0; ip < *nparticles; ip++) {
1496 if ((int) particles[ip].q[ctl.qnt_destination] == neighbours[idest]) {
1497 memcpy(&send_buffers[idest][ibs], &particles[ip], sizeof(particle_t));
1498 ibs++;
1499 }
1500
1501 if (ibs == nbs[idest])
1502 break;
1503 }
1504
1505 SELECT_TIMER("DD_SEND_PARTICLES", "DD", NVTX_CPU);
1506
1507 /* Send the buffer... */
1508 MPI_Isend(send_buffers[idest], nbs[idest], MPI_Particle,
1509 neighbours[idest], 1, MPI_COMM_WORLD,
1510 &requests_snd_part[idest]);
1511 }
1512
1513 SELECT_TIMER("DD_RECIEVE_NUMBERS", "DD", NVTX_CPU);
1514
1515 /* Recieving... */
1516 for (int isourc = 0; isourc < nneighbours; isourc++) {
1517
1518 /* Ignore poles... */
1519 if (neighbours[isourc] < 0) {
1520 requests_rcv_nbr[isourc] = MPI_REQUEST_NULL;
1521 continue;
1522 }
1523
1524 /* Recieve buffer sizes... */
1525 MPI_Irecv(&nbr[isourc], 1, MPI_INT, neighbours[isourc], 0, MPI_COMM_WORLD,
1526 &requests_rcv_nbr[isourc]);
1527 }
1528
1529 /* Wait for all particle numbers to be recieved... */
1530 MPI_Waitall(nneighbours, requests_rcv_nbr, states);
1531
1532 SELECT_TIMER("DD_RECIEVE_PARTICLES", "DD", NVTX_CPU);
1533 for (int isourc = 0; isourc < nneighbours; isourc++) {
1534
1535 /* Ignore poles, and neighbours without signal... */
1536 if ((neighbours[isourc] < 0) || (nbr[isourc] == 0)) {
1537 requests_rcv_part[isourc] = MPI_REQUEST_NULL;
1538 continue;
1539 }
1540
1541 /* Allocate buffer for recieving... */
1542 ALLOC(recieve_buffers[isourc], particle_t, nbr[isourc]);
1543
1544 /* Receive... */
1545 MPI_Irecv(recieve_buffers[isourc], nbr[isourc], MPI_Particle,
1546 neighbours[isourc], 1, MPI_COMM_WORLD,
1547 &requests_rcv_part[isourc]);
1548 }
1549
1550 /* Wait for all particles to be recieved... */
1551 MPI_Waitall(nneighbours, requests_rcv_part, states);
1552
1553 SELECT_TIMER("DD_EMPTY_BUFFER", "DD", NVTX_CPU);
1554
1555 /* Start position for different buffer ranges... */
1556 int api = 0;
1557
1558 /* Putting buffer into particle array... */
1559 for (int isourc = 0; isourc < nneighbours; isourc++) {
1560
1561 /* Ignore poles... */
1562 if (neighbours[isourc] < 0)
1563 continue;
1564
1565 if (nbr[isourc] > 0) {
1566 LOG(3, "DD: Rank %d receiving %d particles from neighbour %d (rank %d)",
1567 rank, nbr[isourc], isourc, neighbours[isourc]);
1568 }
1569
1570 /* Getting particles from buffer... */
1571 for (int ip = 0; ip < nbr[isourc]; ip++) {
1572 memcpy(&particles[ip + api], &recieve_buffers[isourc][ip],
1573 sizeof(particle_t));
1574 particles[ip + api].q[ctl.qnt_destination] = rank;
1575 particles[ip + api].q[ctl.qnt_subdomain] = rank;
1576 }
1577 api += nbr[isourc];
1578 }
1579
1580 /* Set number of recieved particles... */
1581 *nparticles = api;
1582
1583 SELECT_TIMER("DD_FREE_BUFFER", "DD", NVTX_CPU);
1584
1585 /* Wait for all communication to be finished... */
1586 MPI_Waitall(nneighbours, requests_snd_part, states);
1587 MPI_Waitall(nneighbours, requests_snd_nbr, states);
1588
1589 /* Free buffers and buffersizes... */
1590 for (int i = 0; i < nneighbours; i++) {
1591
1592 if ((send_buffers[i] != NULL) && (nbs[i] != 0)) {
1593 free(send_buffers[i]);
1594 send_buffers[i] = NULL;
1595 }
1596
1597 if ((recieve_buffers[i] != NULL) && (nbr[i] != 0)) {
1598 free(recieve_buffers[i]);
1599 recieve_buffers[i] = NULL;
1600 }
1601 }
1602
1603 free(nbs);
1604 free(nbr);
1605}
1606#endif
1607
1608/*****************************************************************************/
1609
1610#ifdef DD
1612 const ctl_t ctl,
1613 dd_t *dd) {
1614 SELECT_TIMER("DD_GET_RECT_NEIGHBOUR", "DD", NVTX_GPU);
1615
1616 const int rank = dd->rank;
1617 const int size = dd->size;
1618 const int m = ctl.dd_subdomains_meridional;
1619 int *nb = dd->neighbours;
1620
1621 nb[0] = (size + rank - m) % size; // left
1622 nb[3] = (rank + m) % size; // right
1623 nb[1] = ((rank + 1) % m == 0) ? DD_SPOLE : (size + rank - m + 1) % size; // lower left
1624 nb[2] = (rank % m == 0) ? DD_NPOLE : (size + rank - m - 1) % size; // upper left
1625 nb[4] = ((rank + 1) % m == 0) ? DD_SPOLE : (rank + m + 1) % size; // lower right
1626 nb[5] = (rank % m == 0) ? DD_NPOLE : (rank + m - 1) % size; // upper right
1627 nb[6] = (rank % m == 0) ? DD_NPOLE : rank - 1; // upper
1628 nb[7] = ((rank + 1) % m == 0) ? DD_SPOLE : rank + 1; // lower
1629}
1630#endif
1631
1632/*****************************************************************************/
1633
1634#ifdef DD
1636 met_t *met,
1637 int nx_glob) {
1638
1639 /* Check if we have at least 2 longitude points... */
1640 if (nx_glob < 2)
1641 return 0;
1642
1643 /* Calculate the longitude spacing */
1644 double lon_spacing = met->lon[1] - met->lon[0];
1645
1646 /* Check if the total range plus one spacing equals 360 degrees
1647 This is the same logic as used in read_met_periodic() */
1648 double total_range = met->lon[nx_glob - 1] - met->lon[0] + lon_spacing;
1649
1650 /* Return 1 if periodic (global), 0 if not periodic (regional) */
1651 return (fabs(total_range - 360.0) < 0.01);
1652}
1653#endif
1654
1655/*****************************************************************************/
1656
1657#ifdef DD
1658int dd_init(
1659 ctl_t *ctl,
1660 dd_t *dd,
1661 atm_t *atm) {
1662
1663 /* Check if enough tasks are requested... */
1664 if (dd->size != ctl->dd_subdomains_meridional * ctl->dd_subdomains_zonal)
1665 ERRMSG("The number of tasks and subdomains is not identical.");
1666
1667#ifdef DD
1668 /* Register the MPI_Particle data type... */
1669 dd_register_MPI_type_particle(&dd->MPI_Particle);
1670#endif
1671
1672 /* Define grid neighbours ... */
1673 dd_get_rect_neighbour(*ctl, dd);
1674
1675 /* Check if particles are in subdomain... */
1676 dd_assign_rect_subdomains_atm(atm, ctl, dd, 1);
1677
1678 /* Set flag of initialization. */
1679 return 1;
1680}
1681#endif
1682
1683/*****************************************************************************/
1684
1685#ifdef DD
1686void dd_particles2atm(
1687 atm_t *atm,
1688 particle_t *particles,
1689 ctl_t *ctl,
1690 int *nparticles,
1691 cache_t *cache) {
1692
1693 SELECT_TIMER("DD_PARTICLES2ATM", "DD", NVTX_CPU);
1694
1695#ifdef _OPENACC
1696 int npart = *nparticles;
1697#pragma acc enter data create(nparticles, particles[:DD_NPART])
1698#pragma acc update device(particles[:npart], nparticles)
1699#pragma acc data present(atm, ctl, cache, particles, nparticles)
1700#pragma acc parallel loop
1701#endif
1702 for (int ip = atm->np; ip < atm->np + *nparticles; ip++) {
1703 atm->time[ip] = particles[ip - atm->np].time;
1704 atm->lon[ip] = particles[ip - atm->np].lon;
1705 atm->lat[ip] = particles[ip - atm->np].lat;
1706 atm->p[ip] = particles[ip - atm->np].p;
1707 for (int iq = 0; iq < ctl->nq; iq++)
1708 atm->q[iq][ip] = particles[ip - atm->np].q[iq];
1709 cache->dt[ip] = ctl->dt_mod;
1710 }
1711#ifdef _OPENACC
1712#pragma acc exit data delete(nparticles, particles)
1713#endif
1714
1715 /* Reset size... */
1716 atm->np += *nparticles;
1717#ifdef _OPENACC
1718#pragma acc update device(atm->np)
1719#endif
1720 if (atm->np > NP)
1721 ERRMSG("Number of particles to high. Increase NP!");
1722}
1723#endif
1724
1725/*****************************************************************************/
1726
1727#ifdef DD
1729 MPI_Datatype *MPI_Particle) {
1730 MPI_Datatype types[5] = { MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE,
1731 MPI_DOUBLE, MPI_DOUBLE
1732 };
1733 int blocklengths[5] = { 1, 1, 1, 1, NQ };
1734 MPI_Aint displacements[5] = { offsetof(particle_t, time),
1735 offsetof(particle_t, p),
1736 offsetof(particle_t, lon),
1737 offsetof(particle_t, lat),
1738 offsetof(particle_t, q)
1739 };
1740 MPI_Type_create_struct(5, blocklengths, displacements, types, MPI_Particle);
1741 MPI_Type_commit(MPI_Particle);
1742}
1743#endif
1744
1745/*****************************************************************************/
1746
1747#ifdef DD
1748void dd_sort(
1749 const ctl_t *ctl,
1750 met_t *met0,
1751 atm_t *atm,
1752 dd_t *dd,
1753 int *nparticles,
1754 int *rank) {
1755
1756 /* Set timer... */
1757 SELECT_TIMER("DD_SORT", "DD", NVTX_GPU);
1758
1759 /* Allocate... */
1760 const int np = atm->np;
1761 double amax = (met0->nx * met0->ny + met0->ny) * met0->np + met0->np;
1762#ifdef _OPENACC
1763#pragma acc enter data create(amax, rank)
1764#pragma acc update device(rank, amax)
1765#pragma acc data present(ctl,met0,atm,dd,amax,rank)
1766#endif
1767
1768 /* Get box index... */
1769#ifdef _OPENACC
1770#pragma acc parallel loop independent gang vector
1771#else
1772#pragma omp parallel for default(shared)
1773#endif
1774 for (int ip = 0; ip < np; ip++) {
1775 if ((int) atm->q[ctl->qnt_subdomain][ip] != -1) {
1776 if ((int) atm->q[ctl->qnt_destination][ip] == *rank)
1777 dd->a[ip] =
1778 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) *
1779 met0->ny + locate_irr(met0->lat, met0->ny, atm->lat[ip]))
1780 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
1781 else
1782 dd->a[ip] = amax + 1;
1783 } else {
1784 dd->a[ip] = amax + 2;
1785 }
1786 dd->p[ip] = ip;
1787 }
1788
1789 /* Sorting... */
1790#ifdef THRUST
1791#ifdef _OPENACC
1792#pragma acc host_data use_device(dd->a,dd->p)
1793#endif
1794 thrustSortWrapper(dd->a, np, dd->p);
1795#else
1796#ifdef _OPENACC
1797 ERRMSG("GSL sort fallback not available on GPU, use THRUST!");
1798#endif
1799 gsl_sort_index((size_t *) (dd->p), (dd->a), 1, (size_t) np);
1800#endif
1801
1802 /* Sort data... */
1803 dd_sort_help(atm->time, dd, np);
1804 dd_sort_help(atm->p, dd, np);
1805 dd_sort_help(atm->lon, dd, np);
1806 dd_sort_help(atm->lat, dd, np);
1807 for (int iq = 0; iq < ctl->nq; iq++)
1808 dd_sort_help(atm->q[iq], dd, np);
1809
1810 /* Reset the size... */
1811 int npt = 0;
1812#ifdef _OPENACC
1813#pragma acc parallel loop reduction(+:npt) present(atm, rank, ctl)
1814#endif
1815 for (int ip = 0; ip < np; ip++)
1816 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
1817 && ((int) atm->q[ctl->qnt_destination][ip] == *rank))
1818 npt++;
1819
1820 /* Count number of particles to send... */
1821 int nparticlest = 0;
1822#ifdef _OPENACC
1823#pragma acc parallel loop reduction(+:nparticlest) present(atm, rank, ctl)
1824#endif
1825 for (int ip = npt; ip < np; ip++)
1826 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
1827 && ((int) atm->q[ctl->qnt_destination][ip] != *rank))
1828 nparticlest++;
1829
1830 /* Reset sizes... */
1831 *nparticles = nparticlest;
1832
1833 /* Count particles with -1 subdomain (these will be effectively lost) */
1834 int nlost = 0;
1835 for (int ip = 0; ip < np; ip++)
1836 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
1837 nlost++;
1838
1839 if (nlost > 0) {
1840 WARN
1841 ("DD: Rank %d: %d particles have subdomain index -1 and will be lost (kept: %d, to_send: %d, total_before: %d)",
1842 *rank, nlost, npt, nparticlest, np);
1843 }
1844
1845 atm->np = npt;
1846#ifdef _OPENACC
1847#pragma acc update device(atm->np)
1848#endif
1849
1850 if (*nparticles > DD_NPART)
1851 ERRMSG
1852 ("Number of particles to send and recieve to small. Increase DD_NPART!");
1853
1854 /* Free... */
1855#ifdef _OPENACC
1856#pragma acc exit data delete(amax, rank)
1857#endif
1858}
1859#endif
1860
1861/*****************************************************************************/
1862
1863#ifdef DD
1864void dd_sort_help(
1865 double *a,
1866 dd_t *dd,
1867 const int np) {
1868
1869 /* Reordering of array... */
1870#ifdef _OPENACC
1871#pragma acc data present(dd,a)
1872#pragma acc parallel loop independent gang vector
1873#else
1874#pragma omp parallel for default(shared)
1875#endif
1876 for (int ip = 0; ip < np; ip++)
1877 dd->help[ip] = a[dd->p[ip]];
1878#ifdef _OPENACC
1879#pragma acc parallel loop independent gang vector
1880#else
1881#pragma omp parallel for default(shared)
1882#endif
1883 for (int ip = 0; ip < np; ip++)
1884 a[ip] = dd->help[ip];
1885}
1886#endif
1887
1888/*****************************************************************************/
1889
1891 const int year,
1892 const int doy,
1893 int *mon,
1894 int *day) {
1895
1896 const int
1897 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1898 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1899
1900 int i;
1901
1902 /* Get month and day... */
1903 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
1904 for (i = 11; i > 0; i--)
1905 if (d0l[i] <= doy)
1906 break;
1907 *mon = i + 1;
1908 *day = doy - d0l[i] + 1;
1909 } else {
1910 for (i = 11; i > 0; i--)
1911 if (d0[i] <= doy)
1912 break;
1913 *mon = i + 1;
1914 *day = doy - d0[i] + 1;
1915 }
1916}
1917
1918/*****************************************************************************/
1919
1921 double *fcReal,
1922 double *fcImag,
1923 const int n) {
1924
1925 double data[2 * EX];
1926
1927 /* Check size... */
1928 if (n > EX)
1929 ERRMSG("Too many data points!");
1930
1931 /* Allocate... */
1932 gsl_fft_complex_wavetable *wavetable =
1933 gsl_fft_complex_wavetable_alloc((size_t) n);
1934 gsl_fft_complex_workspace *workspace =
1935 gsl_fft_complex_workspace_alloc((size_t) n);
1936
1937 /* Set data (real, complex)... */
1938 for (int i = 0; i < n; i++) {
1939 data[2 * i] = fcReal[i];
1940 data[2 * i + 1] = fcImag[i];
1941 }
1942
1943 /* Calculate FFT... */
1944 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
1945
1946 /* Copy data... */
1947 for (int i = 0; i < n; i++) {
1948 fcReal[i] = data[2 * i];
1949 fcImag[i] = data[2 * i + 1];
1950 }
1951
1952 /* Free... */
1953 gsl_fft_complex_wavetable_free(wavetable);
1954 gsl_fft_complex_workspace_free(workspace);
1955}
1956
1957/*****************************************************************************/
1958
1960 const double z,
1961 const double lon,
1962 const double lat,
1963 double *x) {
1964
1965 const double radius = z + RE;
1966 const double latrad = DEG2RAD(lat);
1967 const double lonrad = DEG2RAD(lon);
1968 const double coslat = cos(latrad);
1969
1970 x[0] = radius * coslat * cos(lonrad);
1971 x[1] = radius * coslat * sin(lonrad);
1972 x[2] = radius * sin(latrad);
1973}
1974
1975/*****************************************************************************/
1976
1978 const ctl_t *ctl,
1979 const double t,
1980 const int direct,
1981 const char *metbase,
1982 const double dt_met,
1983 char *filename) {
1984
1985 char repl[LEN];
1986
1987 double t6, r;
1988
1989 int year, mon, day, hour, min, sec;
1990
1991 /* Round time to fixed intervals... */
1992 if (direct == -1)
1993 t6 = floor(t / dt_met) * dt_met;
1994 else
1995 t6 = ceil(t / dt_met) * dt_met;
1996
1997 /* Decode time... */
1998 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1999
2000 /* Set filename of MPTRAC meteo files... */
2001 if (ctl->met_clams == 0) {
2002 if (ctl->met_type == 0)
2003 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
2004 else if (ctl->met_type == 1)
2005 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
2006 else if (ctl->met_type == 2)
2007 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
2008 else if (ctl->met_type == 3)
2009 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
2010 else if (ctl->met_type == 4)
2011 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
2012 else if (ctl->met_type == 5)
2013 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
2014 else if (ctl->met_type == 7)
2015 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
2016 sprintf(repl, "%d", year);
2017 get_met_replace(filename, "YYYY", repl);
2018 sprintf(repl, "%02d", mon);
2019 get_met_replace(filename, "MM", repl);
2020 sprintf(repl, "%02d", day);
2021 get_met_replace(filename, "DD", repl);
2022 sprintf(repl, "%02d", hour);
2023 get_met_replace(filename, "HH", repl);
2024 }
2025
2026 /* Set filename of CLaMS meteo files... */
2027 else {
2028 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
2029 sprintf(repl, "%d", year);
2030 get_met_replace(filename, "YYYY", repl);
2031 sprintf(repl, "%02d", year % 100);
2032 get_met_replace(filename, "YY", repl);
2033 sprintf(repl, "%02d", mon);
2034 get_met_replace(filename, "MM", repl);
2035 sprintf(repl, "%02d", day);
2036 get_met_replace(filename, "DD", repl);
2037 sprintf(repl, "%02d", hour);
2038 get_met_replace(filename, "HH", repl);
2039 }
2040}
2041
2042/*****************************************************************************/
2043
2045 char *orig,
2046 char *search,
2047 char *repl) {
2048
2049 char buffer[LEN];
2050
2051 /* Iterate... */
2052 for (int i = 0; i < 3; i++) {
2053
2054 /* Replace sub-string... */
2055 char *ch;
2056 if (!(ch = strstr(orig, search)))
2057 return;
2058 strncpy(buffer, orig, (size_t) (ch - orig));
2059 buffer[ch - orig] = 0;
2060 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
2061 orig[0] = 0;
2062 strcpy(orig, buffer);
2063 }
2064}
2065
2066/*****************************************************************************/
2067
2069 const int met_tropo,
2070 ctl_t *ctl,
2071 clim_t *clim,
2072 met_t *met,
2073 const double *lons,
2074 const int nx,
2075 const double *lats,
2076 const int ny,
2077 double *pt,
2078 double *zt,
2079 double *tt,
2080 double *qt,
2081 double *o3t,
2082 double *ps,
2083 double *zs) {
2084
2086
2087 ctl->met_tropo = met_tropo;
2088 read_met_tropo(ctl, clim, met);
2089#pragma omp parallel for default(shared) private(ci,cw)
2090 for (int ix = 0; ix < nx; ix++)
2091 for (int iy = 0; iy < ny; iy++) {
2092 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
2093 &pt[iy * nx + ix], ci, cw, 1);
2094 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
2095 &ps[iy * nx + ix], ci, cw, 0);
2096 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
2097 &zs[iy * nx + ix], ci, cw, 0);
2098 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
2099 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
2100 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
2101 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
2102 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
2103 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
2104 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
2105 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
2106 }
2107}
2108
2109/*****************************************************************************/
2110
2112 const double *lons,
2113 const int nlon,
2114 const double *lats,
2115 const int nlat,
2116 const double lon,
2117 const double lat,
2118 double *lon2,
2119 double *lat2) {
2120
2121 /* Check longitude... */
2122 *lon2 = FMOD(lon, 360.);
2123 if (*lon2 < lons[0])
2124 *lon2 += 360;
2125 else if (*lon2 > lons[nlon - 1])
2126 *lon2 -= 360;
2127
2128 /* Check latitude... */
2129 *lat2 = lat;
2130 if (lats[0] < lats[nlat - 1])
2131 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
2132 else
2133 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
2134}
2135
2136/*****************************************************************************/
2137
2139 const met_t *met0,
2140 float heights0[EX][EY][EP],
2141 float array0[EX][EY][EP],
2142 const met_t *met1,
2143 float heights1[EX][EY][EP],
2144 float array1[EX][EY][EP],
2145 const double ts,
2146 const double height,
2147 const double lon,
2148 const double lat,
2149 double *var,
2150 int *ci,
2151 double *cw,
2152 const int init) {
2153
2154 if (init) {
2155
2156 /* Check longitude and latitude... */
2157 double lon2, lat2;
2158 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
2159 &lon2, &lat2);
2160
2161 /* Get horizontal indizes... */
2162 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
2163 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
2164
2165 /* Locate the vertical indizes for each edge of the column... */
2166 int ind[2][4];
2167 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
2168 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
2169
2170 /* Find minimum and maximum indizes... */
2171 ci[2] = ind[0][0];
2172 int k_max = ind[0][0];
2173 for (int i = 0; i < 2; i++)
2174 for (int j = 0; j < 4; j++) {
2175 if (ci[2] > ind[i][j])
2176 ci[2] = ind[i][j];
2177 if (k_max < ind[i][j])
2178 k_max = ind[i][j];
2179 }
2180
2181 /* Get weighting factors for time, longitude and latitude... */
2182 cw[3] = (ts - met0->time) / (met1->time - met0->time);
2183 cw[0] = (lon2 - met0->lon[ci[0]]) /
2184 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
2185 cw[1] = (lat2 - met0->lat[ci[1]]) /
2186 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
2187
2188 /* Interpolate in time at the lowest level... */
2189 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
2190 - heights0[ci[0]][ci[1]][ci[2]])
2191 + heights0[ci[0]][ci[1]][ci[2]];
2192 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
2193 - heights0[ci[0]][ci[1] + 1][ci[2]])
2194 + heights0[ci[0]][ci[1] + 1][ci[2]];
2195 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
2196 - heights0[ci[0] + 1][ci[1]][ci[2]])
2197 + heights0[ci[0] + 1][ci[1]][ci[2]];
2198 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
2199 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
2200 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
2201
2202 /* Interpolate in latitude direction... */
2203 double height0 = cw[1] * (height01 - height00) + height00;
2204 double height1 = cw[1] * (height11 - height10) + height10;
2205
2206 /* Interpolate in longitude direction... */
2207 double height_bot = cw[0] * (height1 - height0) + height0;
2208
2209 /* Interpolate in time at the upper level... */
2210 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2211 - heights0[ci[0]][ci[1]][ci[2] + 1])
2212 + heights0[ci[0]][ci[1]][ci[2] + 1];
2213 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2214 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2215 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2216 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2217 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2218 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2219 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2220 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2221 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2222
2223 /* Interpolate in latitude direction... */
2224 height0 = cw[1] * (height01 - height00) + height00;
2225 height1 = cw[1] * (height11 - height10) + height10;
2226
2227 /* Interpolate in longitude direction... */
2228 double height_top = cw[0] * (height1 - height0) + height0;
2229
2230 /* Search at higher levels if height is not in box... */
2231 while (((heights0[0][0][0] > heights0[0][0][1]) &&
2232 ((height_bot <= height) || (height_top > height))
2233 && (height_bot >= height) && (ci[2] < k_max))
2234 ||
2235 ((heights0[0][0][0] < heights0[0][0][1]) &&
2236 ((height_bot >= height) || (height_top < height))
2237 && (height_bot <= height) && (ci[2] < k_max))
2238 ) {
2239
2240 ci[2]++;
2241 height_bot = height_top;
2242
2243 /* Interpolate in time at the next level... */
2244 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2245 - heights0[ci[0]][ci[1]][ci[2] + 1])
2246 + heights0[ci[0]][ci[1]][ci[2] + 1];
2247 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2248 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2249 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2250 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2251 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2252 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2253 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2254 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2255 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2256
2257 /* Interpolate in latitude direction... */
2258 height0 = cw[1] * (height01 - height00) + height00;
2259 height1 = cw[1] * (height11 - height10) + height10;
2260
2261 /* Interpolate in longitude direction... */
2262 height_top = cw[0] * (height1 - height0) + height0;
2263 }
2264
2265 /* Get vertical weighting factors... */
2266 cw[2] = (height - height_bot)
2267 / (height_top - height_bot);
2268 }
2269
2270 /* Calculate the needed array values... */
2271 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
2272 - array0[ci[0]][ci[1]][ci[2]])
2273 + array0[ci[0]][ci[1]][ci[2]];
2274 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
2275 - array0[ci[0] + 1][ci[1]][ci[2]])
2276 + array0[ci[0] + 1][ci[1]][ci[2]];
2277 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
2278 - array0[ci[0]][ci[1] + 1][ci[2]])
2279 + array0[ci[0]][ci[1] + 1][ci[2]];
2280 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
2281 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
2282 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
2283 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
2284 - array0[ci[0]][ci[1]][ci[2] + 1])
2285 + array0[ci[0]][ci[1]][ci[2] + 1];
2286 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2287 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2288 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2289 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2290 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2291 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2292 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2293 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2294 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2295
2296 const double array00 = cw[0] * (array100 - array000) + array000;
2297 const double array10 = cw[0] * (array110 - array010) + array010;
2298 const double array01 = cw[0] * (array101 - array001) + array001;
2299 const double array11 = cw[0] * (array111 - array011) + array011;
2300
2301 const double aux0 = cw[1] * (array10 - array00) + array00;
2302 const double aux1 = cw[1] * (array11 - array01) + array01;
2303
2304 /* Interpolate vertically... */
2305 *var = cw[2] * (aux1 - aux0) + aux0;
2306}
2307
2308/*****************************************************************************/
2309
2311 const met_t *met,
2312 float array[EX][EY][EP],
2313 const double p,
2314 const double lon,
2315 const double lat,
2316 double *var,
2317 int *ci,
2318 double *cw,
2319 const int init) {
2320
2321 /* Initialize interpolation... */
2322 if (init) {
2323
2324 /* Check longitude and latitude... */
2325 double lon2, lat2;
2326 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2327 &lon2, &lat2);
2328
2329 /* Get interpolation indices... */
2330 ci[0] = locate_irr(met->p, met->np, p);
2331 ci[1] = locate_reg(met->lon, met->nx, lon2);
2332 ci[2] = locate_irr(met->lat, met->ny, lat2);
2333
2334 /* Get interpolation weights... */
2335 cw[0] = (met->p[ci[0] + 1] - p)
2336 / (met->p[ci[0] + 1] - met->p[ci[0]]);
2337 cw[1] = (met->lon[ci[1] + 1] - lon2)
2338 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2339 cw[2] = (met->lat[ci[2] + 1] - lat2)
2340 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2341 }
2342
2343 /* Interpolate vertically... */
2344 const double aux00 =
2345 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
2346 + array[ci[1]][ci[2]][ci[0] + 1];
2347 const double aux01 =
2348 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
2349 array[ci[1]][ci[2] + 1][ci[0] + 1])
2350 + array[ci[1]][ci[2] + 1][ci[0] + 1];
2351 const double aux10 =
2352 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
2353 array[ci[1] + 1][ci[2]][ci[0] + 1])
2354 + array[ci[1] + 1][ci[2]][ci[0] + 1];
2355 const double aux11 =
2356 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
2357 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
2358 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
2359
2360 /* Interpolate horizontally... */
2361 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2362 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2363 *var = cw[1] * (aux0 - aux1) + aux1;
2364}
2365
2366/*****************************************************************************/
2367
2369 const met_t *met,
2370 float array[EX][EY],
2371 const double lon,
2372 const double lat,
2373 double *var,
2374 int *ci,
2375 double *cw,
2376 const int init) {
2377
2378 /* Initialize interpolation... */
2379 if (init) {
2380
2381 /* Check longitude and latitude... */
2382 double lon2, lat2;
2383 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2384 &lon2, &lat2);
2385
2386 /* Get interpolation indices... */
2387 ci[1] = locate_reg(met->lon, met->nx, lon2);
2388 ci[2] = locate_irr(met->lat, met->ny, lat2);
2389
2390 /* Get interpolation weights... */
2391 cw[1] = (met->lon[ci[1] + 1] - lon2)
2392 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2393 cw[2] = (met->lat[ci[2] + 1] - lat2)
2394 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2395 }
2396
2397 /* Set variables... */
2398 const double aux00 = array[ci[1]][ci[2]];
2399 const double aux01 = array[ci[1]][ci[2] + 1];
2400 const double aux10 = array[ci[1] + 1][ci[2]];
2401 const double aux11 = array[ci[1] + 1][ci[2] + 1];
2402
2403 /* Interpolate horizontally... */
2404 if (isfinite(aux00) && isfinite(aux01)
2405 && isfinite(aux10) && isfinite(aux11)) {
2406 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2407 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2408 *var = cw[1] * (aux0 - aux1) + aux1;
2409 } else {
2410 if (cw[2] < 0.5) {
2411 if (cw[1] < 0.5)
2412 *var = aux11;
2413 else
2414 *var = aux01;
2415 } else {
2416 if (cw[1] < 0.5)
2417 *var = aux10;
2418 else
2419 *var = aux00;
2420 }
2421 }
2422}
2423
2424/*****************************************************************************/
2425
2427 const met_t *met0,
2428 float array0[EX][EY][EP],
2429 const met_t *met1,
2430 float array1[EX][EY][EP],
2431 const double ts,
2432 const double p,
2433 const double lon,
2434 const double lat,
2435 double *var,
2436 int *ci,
2437 double *cw,
2438 const int init) {
2439
2440 double var0, var1;
2441
2442 /* Spatial interpolation... */
2443 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
2444 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
2445
2446 /* Get weighting factor... */
2447 const double wt = (met1->time - ts) / (met1->time - met0->time);
2448
2449 /* Interpolate... */
2450 *var = wt * (var0 - var1) + var1;
2451}
2452
2453/*****************************************************************************/
2454
2456 const met_t *met0,
2457 float array0[EX][EY],
2458 const met_t *met1,
2459 float array1[EX][EY],
2460 const double ts,
2461 const double lon,
2462 const double lat,
2463 double *var,
2464 int *ci,
2465 double *cw,
2466 const int init) {
2467
2468 double var0, var1;
2469
2470 /* Spatial interpolation... */
2471 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
2472 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
2473
2474 /* Get weighting factor... */
2475 const double wt = (met1->time - ts) / (met1->time - met0->time);
2476
2477 /* Interpolate... */
2478 if (isfinite(var0) && isfinite(var1))
2479 *var = wt * (var0 - var1) + var1;
2480 else if (wt < 0.5)
2481 *var = var1;
2482 else
2483 *var = var0;
2484}
2485
2486/*****************************************************************************/
2487
2489 const double time0,
2490 float array0[EX][EY],
2491 const double time1,
2492 float array1[EX][EY],
2493 const double lons[EX],
2494 const double lats[EY],
2495 const int nlon,
2496 const int nlat,
2497 const double time,
2498 const double lon,
2499 const double lat,
2500 const int method,
2501 double *var,
2502 double *sigma) {
2503
2504 double mean = 0;
2505
2506 int n = 0;
2507
2508 /* Check longitude and latitude... */
2509 double lon2, lat2;
2510 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
2511
2512 /* Get indices... */
2513 const int ix = locate_reg(lons, (int) nlon, lon2);
2514 const int iy = locate_irr(lats, (int) nlat, lat2);
2515
2516 /* Calculate standard deviation... */
2517 *sigma = 0;
2518 for (int dx = 0; dx < 2; dx++)
2519 for (int dy = 0; dy < 2; dy++) {
2520 if (isfinite(array0[ix + dx][iy + dy])) {
2521 mean += array0[ix + dx][iy + dy];
2522 *sigma += SQR(array0[ix + dx][iy + dy]);
2523 n++;
2524 }
2525 if (isfinite(array1[ix + dx][iy + dy])) {
2526 mean += array1[ix + dx][iy + dy];
2527 *sigma += SQR(array1[ix + dx][iy + dy]);
2528 n++;
2529 }
2530 }
2531 if (n > 0)
2532 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
2533
2534 /* Linear interpolation... */
2535 if (method == 1 && isfinite(array0[ix][iy])
2536 && isfinite(array0[ix][iy + 1])
2537 && isfinite(array0[ix + 1][iy])
2538 && isfinite(array0[ix + 1][iy + 1])
2539 && isfinite(array1[ix][iy])
2540 && isfinite(array1[ix][iy + 1])
2541 && isfinite(array1[ix + 1][iy])
2542 && isfinite(array1[ix + 1][iy + 1])) {
2543
2544 const double aux00 = LIN(lons[ix], array0[ix][iy],
2545 lons[ix + 1], array0[ix + 1][iy], lon2);
2546 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
2547 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2548 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2549
2550 const double aux10 = LIN(lons[ix], array1[ix][iy],
2551 lons[ix + 1], array1[ix + 1][iy], lon2);
2552 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
2553 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2554 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2555
2556 *var = LIN(time0, aux0, time1, aux1, time);
2557 }
2558
2559 /* Nearest neighbor interpolation... */
2560 else {
2561 const double aux00 = NN(lons[ix], array0[ix][iy],
2562 lons[ix + 1], array0[ix + 1][iy], lon2);
2563 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
2564 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2565 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2566
2567 const double aux10 = NN(lons[ix], array1[ix][iy],
2568 lons[ix + 1], array1[ix + 1][iy], lon2);
2569 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
2570 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2571 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2572
2573 *var = NN(time0, aux0, time1, aux1, time);
2574 }
2575}
2576
2577/*****************************************************************************/
2578
2580 const double jsec,
2581 int *year,
2582 int *mon,
2583 int *day,
2584 int *hour,
2585 int *min,
2586 int *sec,
2587 double *remain) {
2588
2589 struct tm t0, *t1;
2590
2591 t0.tm_year = 100;
2592 t0.tm_mon = 0;
2593 t0.tm_mday = 1;
2594 t0.tm_hour = 0;
2595 t0.tm_min = 0;
2596 t0.tm_sec = 0;
2597
2598 const time_t jsec0 = (time_t) jsec + timegm(&t0);
2599 t1 = gmtime(&jsec0);
2600
2601 *year = t1->tm_year + 1900;
2602 *mon = t1->tm_mon + 1;
2603 *day = t1->tm_mday;
2604 *hour = t1->tm_hour;
2605 *min = t1->tm_min;
2606 *sec = t1->tm_sec;
2607 *remain = jsec - floor(jsec);
2608}
2609
2610/*****************************************************************************/
2611
2613 const double kz[EP],
2614 const double kw[EP],
2615 const int nk,
2616 const double p) {
2617
2618 /* Check number of data points... */
2619 if (nk < 2)
2620 return 1.0;
2621
2622 /* Get altitude... */
2623 const double z = Z(p);
2624
2625 /* Get weighting factor... */
2626 if (z < kz[0])
2627 return kw[0];
2628 else if (z > kz[nk - 1])
2629 return kw[nk - 1];
2630 else {
2631 const int idx = locate_irr(kz, nk, z);
2632 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
2633 }
2634}
2635
2636/*****************************************************************************/
2637
2639 const double t,
2640 const double h2o) {
2641
2642 /*
2643 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
2644 and water vapor volume mixing ratio [1].
2645
2646 Reference: https://en.wikipedia.org/wiki/Lapse_rate
2647 */
2648
2649 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
2650
2651 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
2652}
2653
2654/*****************************************************************************/
2655
2657 ctl_t *ctl) {
2658
2659 if (0 == ctl->met_press_level_def) {
2660
2661 ctl->met_np = 138;
2662
2663 const double press[138] = {
2664 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
2665 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
2666 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
2667 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
2668 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2669 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
2670 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
2671 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
2672 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
2673 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
2674 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
2675 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
2676 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
2677 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
2678 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
2679 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
2680 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
2681 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
2682 1010.8487, 1013.2500, 1044.45
2683 };
2684
2685 for (int ip = 0; ip < ctl->met_np; ip++)
2686 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2687
2688 } else if (1 == ctl->met_press_level_def) {
2689
2690 ctl->met_np = 92;
2691
2692 const double press[92] = {
2693 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
2694 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
2695 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
2696 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
2697 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
2698 113.6382,
2699 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
2700 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
2701 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2702 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2703 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2704 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2705 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2706 1007.4431, 1010.8487, 1013.2500, 1044.45
2707 };
2708
2709 for (int ip = 0; ip < ctl->met_np; ip++)
2710 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2711
2712 } else if (2 == ctl->met_press_level_def) {
2713
2714 ctl->met_np = 60;
2715
2716 const double press[60] = {
2717 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2718 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2719 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2720 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2721 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2722 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2723 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2724 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1044.45
2725 };
2726
2727 for (int ip = 0; ip < ctl->met_np; ip++)
2728 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2729
2730 } else if (3 == ctl->met_press_level_def) {
2731
2732 ctl->met_np = 147;
2733
2734 const double press[147] = {
2735 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
2736 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
2737 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
2738 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
2739 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2740 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
2741 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
2742 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
2743 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
2744 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
2745 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
2746 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
2747 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
2748 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
2749 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
2750 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
2751 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
2752 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
2753 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
2754 1031.97,
2755 1035.09, 1038.21, 1041.33, 1044.45
2756 };
2757
2758 for (int ip = 0; ip < ctl->met_np; ip++)
2759 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2760
2761 } else if (4 == ctl->met_press_level_def) {
2762
2763 ctl->met_np = 101;
2764
2765 const double press[101] = {
2766 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
2767 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
2768 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
2769 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
2770 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
2771 113.6382,
2772 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
2773 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
2774 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2775 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2776 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2777 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2778 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2779 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
2780 1028.85, 1031.97,
2781 1035.09, 1038.21, 1041.33, 1044.45
2782 };
2783
2784 for (int ip = 0; ip < ctl->met_np; ip++)
2785 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2786
2787 } else if (5 == ctl->met_press_level_def) {
2788
2789 ctl->met_np = 62;
2790
2791 const double press[62] = {
2792 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2793 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2794 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2795 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2796 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2797 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2798 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2799 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
2800 1044.45
2801 };
2802
2803 for (int ip = 0; ip < ctl->met_np; ip++)
2804 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2805
2806 } else if (6 == ctl->met_press_level_def) {
2807
2808 ctl->met_np = 137;
2809
2810 const double press[137] = {
2811 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
2812 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
2813 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
2814 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
2815 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
2816 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2817 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
2818 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
2819 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
2820 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
2821 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
2822 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
2823 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
2824 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
2825 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
2826 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
2827 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
2828 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
2829 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
2830 1030.06, 1037.25, 1044.45
2831 };
2832
2833 for (int ip = 0; ip < ctl->met_np; ip++)
2834 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2835
2836 } else if (7 == ctl->met_press_level_def) {
2837
2838 ctl->met_np = 59;
2839
2840 const double press[59] = {
2841 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2842 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2843 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2844 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2845 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2846 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2847 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2848 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2849 1028.53, 1046.13
2850 };
2851
2852 for (int ip = 0; ip < ctl->met_np; ip++)
2853 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2854
2855 } else {
2856 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.");
2857 }
2858
2859 if (ctl->met_np > EP) {
2860 ERRMSG("Recompile with larger EP to use this pressure level definition.");
2861 }
2862}
2863
2864/*****************************************************************************/
2865
2867 const double *xx,
2868 const int n,
2869 const double x) {
2870
2871 int ilo = 0;
2872 int ihi = n - 1;
2873 int i = (ihi + ilo) >> 1;
2874
2875 if (xx[i] < xx[i + 1])
2876 while (ihi > ilo + 1) {
2877 i = (ihi + ilo) >> 1;
2878 if (xx[i] > x)
2879 ihi = i;
2880 else
2881 ilo = i;
2882 } else
2883 while (ihi > ilo + 1) {
2884 i = (ihi + ilo) >> 1;
2885 if (xx[i] <= x)
2886 ihi = i;
2887 else
2888 ilo = i;
2889 }
2890
2891 return ilo;
2892}
2893
2894/*****************************************************************************/
2895
2897 const float *xx,
2898 const int n,
2899 const double x,
2900 const int ig) {
2901
2902 int ilo = 0;
2903 int ihi = n - 1;
2904 int i = (ihi + ilo) >> 1;
2905
2906 if ((xx[ig] <= x && x < xx[ig + 1]) || (xx[ig] >= x && x > xx[ig + 1]))
2907 return ig;
2908
2909 if (xx[i] < xx[i + 1])
2910 while (ihi > ilo + 1) {
2911 i = (ihi + ilo) >> 1;
2912 if (xx[i] > x)
2913 ihi = i;
2914 else
2915 ilo = i;
2916 } else
2917 while (ihi > ilo + 1) {
2918 i = (ihi + ilo) >> 1;
2919 if (xx[i] <= x)
2920 ihi = i;
2921 else
2922 ilo = i;
2923 }
2924
2925 return ilo;
2926}
2927
2928/*****************************************************************************/
2929
2931 const double *xx,
2932 const int n,
2933 const double x) {
2934
2935 /* Calculate index... */
2936 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2937
2938 /* Check range... */
2939 if (i < 0)
2940 return 0;
2941 else if (i > n - 2)
2942 return n - 2;
2943 else
2944 return i;
2945}
2946
2947/*****************************************************************************/
2948
2950 float profiles[EX][EY][EP],
2951 const int np,
2952 const int lon_ap_ind,
2953 const int lat_ap_ind,
2954 const double height_ap,
2955 int *ind) {
2956
2957 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2958 np, height_ap, 0);
2959 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2960 np, height_ap, ind[0]);
2961 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2962 np, height_ap, ind[1]);
2963 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2964 np, height_ap, ind[2]);
2965}
2966
2967/*****************************************************************************/
2968
2970 const ctl_t *ctl,
2971 const cache_t *cache,
2972 met_t *met0,
2973 met_t *met1,
2974 atm_t *atm) {
2975
2976 /* Set timer... */
2977 SELECT_TIMER("MODULE_ADVECT", "PHYSICS", NVTX_GPU);
2978
2979 /* Use omega vertical velocity... */
2980 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2981
2982 /* Loop over particles... */
2983 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2984
2985 /* Init... */
2987 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2988 x[3] = { 0, 0, 0 };
2989
2990 /* Loop over integration nodes... */
2991 for (int i = 0; i < ctl->advect; i++) {
2992
2993 /* Set position... */
2994 if (i == 0) {
2995 dts = 0.0;
2996 x[0] = atm->lon[ip];
2997 x[1] = atm->lat[ip];
2998 x[2] = atm->p[ip];
2999 } else {
3000 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3001 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
3002 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
3003 x[2] = atm->p[ip] + dts * w[i - 1];
3004 }
3005 const double tm = atm->time[ip] + dts;
3006
3007 /* Interpolate meteo data on pressure levels... */
3008 if (ctl->advect_vert_coord == 0) {
3009 intpol_met_time_3d(met0, met0->u, met1, met1->u,
3010 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3011 intpol_met_time_3d(met0, met0->v, met1, met1->v,
3012 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3013 intpol_met_time_3d(met0, met0->w, met1, met1->w,
3014 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3015 }
3016
3017 /* Interpolate meteo data on model levels... */
3018 else {
3019 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
3020 met1, met1->pl, met1->ul,
3021 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3022 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
3023 met1, met1->pl, met1->vl,
3024 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3025 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
3026 met1, met1->pl, met1->wl,
3027 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3028 }
3029
3030 /* Get mean wind... */
3031 double k = 1.0;
3032 if (ctl->advect == 2)
3033 k = (i == 0 ? 0.0 : 1.0);
3034 else if (ctl->advect == 4)
3035 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3036 um += k * u[i];
3037 vm += k * v[i];
3038 wm += k * w[i];
3039 }
3040
3041 /* Set new position... */
3042 atm->time[ip] += cache->dt[ip];
3043 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
3044 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3045 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
3046 atm->p[ip] += cache->dt[ip] * wm;
3047 }
3048 }
3049
3050 /* Use zeta or eta vertical velocity... */
3051 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
3052
3053 /* Select quantity index depending on coordinate... */
3054 const int qnt = (ctl->advect_vert_coord == 1
3055 ? ctl->qnt_zeta : ctl->qnt_eta);
3056
3057 /* Loop over particles... */
3058 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3059
3060 /* Convert pressure to vertical coordinate (zeta or eta)... */
3062 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
3063 met1, met1->pl, met1->zetal,
3064 atm->time[ip], atm->p[ip],
3065 atm->lon[ip], atm->lat[ip],
3066 &atm->q[qnt][ip], ci, cw, 1);
3067
3068 /* Init... */
3069 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
3070 wdotm = 0, x[3] = { 0, 0, 0 };
3071
3072 /* Loop over integration nodes (Runge–Kutta steps)... */
3073 for (int i = 0; i < ctl->advect; i++) {
3074
3075 /* Set position... */
3076 if (i == 0) {
3077 dts = 0.0;
3078 x[0] = atm->lon[ip];
3079 x[1] = atm->lat[ip];
3080 x[2] = atm->q[qnt][ip];
3081 } else {
3082 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3083 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
3084 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
3085 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
3086 }
3087
3088 const double tm = atm->time[ip] + dts;
3089
3090 /* Interpolate meteo data... */
3091 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
3092 met1, met1->zetal, met1->ul,
3093 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3094 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
3095 met1, met1->zetal, met1->vl,
3096 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3097 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
3098 met1, met1->zetal, met1->zeta_dotl,
3099 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
3100
3101 /* Compute Runge–Kutta weights... */
3102 double k = 1.0;
3103 if (ctl->advect == 2)
3104 k = (i == 0 ? 0.0 : 1.0);
3105 else if (ctl->advect == 4)
3106 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3107
3108 um += k * u[i];
3109 vm += k * v[i];
3110 wdotm += k * wdot[i];
3111 }
3112
3113 /* Update particle position... */
3114 atm->time[ip] += cache->dt[ip];
3115 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
3116 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3117 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
3118 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
3119
3120 /* Convert vertical coordinate (zeta or eta) back to pressure... */
3121 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
3122 met1, met1->zetal, met1->pl,
3123 atm->time[ip],
3124 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
3125 &atm->p[ip], ci, cw, 1);
3126 }
3127 }
3128}
3129
3130/*****************************************************************************/
3131
3133 const ctl_t *ctl,
3134 const cache_t *cache,
3135 met_t *met0,
3136 met_t *met1,
3137 atm_t *atm) {
3138
3139 /* Check parameters... */
3140 if (ctl->advect_vert_coord != 1)
3141 return;
3142
3143 /* Set timer... */
3144 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS", NVTX_GPU);
3145
3146 /* Loop over particles... */
3147 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
3148
3149 /* Initialize pressure consistent with zeta... */
3151 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
3152 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
3153 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
3154 }
3155}
3156
3157/*****************************************************************************/
3158
3160 const ctl_t *ctl,
3161 const cache_t *cache,
3162 const clim_t *clim,
3163 met_t *met0,
3164 met_t *met1,
3165 atm_t *atm) {
3166
3167 /* Set timer... */
3168 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS", NVTX_GPU);
3169
3170 /* Check quantity flags... */
3171 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
3172 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
3173 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
3174 return;
3175
3176 /* Loop over particles... */
3177 PARTICLE_LOOP(0, atm->np, 1,
3178 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3179
3180 /* Check latitude and pressure range... */
3181 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
3182 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
3183 continue;
3184
3185 /* Check surface layer... */
3186 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
3187 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
3188
3189 /* Get surface pressure... */
3190 double ps;
3192 INTPOL_2D(ps, 1);
3193
3194 /* Check pressure... */
3195 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
3196 continue;
3197
3198 /* Check height... */
3199 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
3200 continue;
3201
3202 /* Check zeta range... */
3203 if (ctl->bound_zetas > 0) {
3204 double t;
3205 INTPOL_3D(t, 1);
3206 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
3207 continue;
3208 }
3209
3210 /* Check planetary boundary layer... */
3211 if (ctl->bound_pbl) {
3212 double pbl;
3213 INTPOL_2D(pbl, 0);
3214 if (atm->p[ip] < pbl)
3215 continue;
3216 }
3217 }
3218
3219 /* Set mass and volume mixing ratio... */
3220 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
3221 atm->q[ctl->qnt_m][ip] =
3222 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
3223 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
3224 atm->q[ctl->qnt_vmr][ip] =
3225 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
3226
3227 /* Set CFC-10 volume mixing ratio... */
3228 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
3229 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
3230
3231 /* Set CFC-11 volume mixing ratio... */
3232 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
3233 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
3234
3235 /* Set CFC-12 volume mixing ratio... */
3236 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
3237 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
3238
3239 /* Set N2O volume mixing ratio... */
3240 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
3241 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
3242
3243 /* Set SF6 volume mixing ratio... */
3244 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
3245 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
3246
3247 /* Set age of air... */
3248 if (ctl->qnt_aoa >= 0)
3249 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
3250 }
3251}
3252
3253/*****************************************************************************/
3254
3256 const ctl_t *ctl,
3257 met_t *met0,
3258 met_t *met1,
3259 atm_t *atm,
3260 const double tt) {
3261
3262 /* Check quantities... */
3263 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
3264 return;
3265 if (ctl->molmass <= 0)
3266 ERRMSG("Molar mass is not defined!");
3267
3268 /* Set timer... */
3269 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS", NVTX_GPU);
3270
3271 /* Allocate... */
3272 const int ensemble_mode = (ctl->nens > 0);
3273 const int np = atm->np;
3274 const int nz = ctl->chemgrid_nz;
3275 const int nx = ctl->chemgrid_nx;
3276 const int ny = ctl->chemgrid_ny;
3277 const int ngrid = nx * ny * nz;
3278 const int nens = ensemble_mode ? ctl->nens : 1;
3279
3280 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
3281 double *restrict const press =
3282 (double *) malloc((size_t) nz * sizeof(double));
3283 double *restrict const mass =
3284 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
3285 double *restrict const area =
3286 (double *) malloc((size_t) ny * sizeof(double));
3287 double *restrict const lon =
3288 (double *) malloc((size_t) nx * sizeof(double));
3289 double *restrict const lat =
3290 (double *) malloc((size_t) ny * sizeof(double));
3291
3292 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3293 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3294 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3295
3296 /* Set grid box size... */
3297 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
3298 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
3299 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
3300
3301 /* Set vertical coordinates... */
3302#ifdef _OPENACC
3303#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])
3304#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
3305#pragma acc parallel loop independent gang vector
3306#else
3307#pragma omp parallel for default(shared)
3308#endif
3309 for (int iz = 0; iz < nz; iz++) {
3310 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
3311 press[iz] = P(z[iz]);
3312 }
3313
3314 /* Set time interval for output... */
3315 const double t0 = tt - 0.5 * ctl->dt_mod;
3316 const double t1 = tt + 0.5 * ctl->dt_mod;
3317
3318 /* Get indices... */
3319#ifdef _OPENACC
3320#pragma acc parallel loop independent gang vector
3321#else
3322#pragma omp parallel for default(shared)
3323#endif
3324 for (int ip = 0; ip < np; ip++) {
3325 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
3326 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
3327 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
3328 if (atm->time[ip] < t0 || atm->time[ip] > t1
3329 || ixs[ip] < 0 || ixs[ip] >= nx
3330 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
3331 izs[ip] = -1;
3332 }
3333
3334 /* Set horizontal coordinates... */
3335#ifdef _OPENACC
3336#pragma acc parallel loop independent gang vector
3337#else
3338#pragma omp parallel for default(shared)
3339#endif
3340 for (int ix = 0; ix < nx; ix++)
3341 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3342
3343#ifdef _OPENACC
3344#pragma acc parallel loop independent gang vector
3345#else
3346#pragma omp parallel for default(shared)
3347#endif
3348 for (int iy = 0; iy < ny; iy++) {
3349 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3350 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3351 }
3352
3353 /* Get mass per grid box... */
3354#ifdef _OPENACC
3355#pragma acc parallel loop independent gang vector
3356#endif
3357 for (int ip = 0; ip < np; ip++) {
3358 if (izs[ip] >= 0) {
3359 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3360 if (ensemble_mode) {
3361 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3362 mass_idx += ens * ngrid;
3363 }
3364#ifdef _OPENACC
3365#pragma acc atomic update
3366#endif
3367 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
3368 }
3369 }
3370
3371 /* Assign grid data to air parcels ... */
3372#ifdef _OPENACC
3373#pragma acc parallel loop independent gang vector
3374#else
3375#pragma omp parallel for default(shared)
3376#endif
3377 for (int ip = 0; ip < np; ip++)
3378 if (izs[ip] >= 0) {
3379
3380 /* Interpolate temperature... */
3381 double temp;
3383 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
3384 press[izs[ip]],
3385 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
3386
3387 /* Set mass... */
3388 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3389 if (ensemble_mode) {
3390 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3391 mass_idx += ens * ngrid;
3392 }
3393
3394 /* Calculate volume mixing ratio... */
3395 const double m = mass[mass_idx];
3396 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
3397 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
3398 }
3399
3400 /* Free... */
3401#ifdef _OPENACC
3402#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
3403#endif
3404 free(mass);
3405 free(lon);
3406 free(lat);
3407 free(area);
3408 free(z);
3409 free(press);
3410 free(ixs);
3411 free(iys);
3412 free(izs);
3413}
3414
3415/*****************************************************************************/
3416
3418 const ctl_t *ctl,
3419 const cache_t *cache,
3420 const clim_t *clim,
3421 met_t *met0,
3422 met_t *met1,
3423 atm_t *atm) {
3424
3425 /* Set timer... */
3426 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS", NVTX_GPU);
3427
3428 /* Loop over particles... */
3429 PARTICLE_LOOP(0, atm->np, 0,
3430 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3431
3432 /* Set H2O and O3 using meteo data... */
3434 if (ctl->qnt_Ch2o >= 0) {
3435 double h2o;
3436 INTPOL_3D(h2o, 1);
3437 SET_ATM(qnt_Ch2o, h2o);
3438 }
3439 if (ctl->qnt_Co3 >= 0) {
3440 double o3;
3441 INTPOL_3D(o3, 1);
3442 SET_ATM(qnt_Co3, o3);
3443 }
3444
3445 /* Set radical species... */
3446 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
3447 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3448 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
3449 atm->lat[ip], atm->p[ip]));
3450 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
3451 atm->lat[ip], atm->p[ip]));
3452 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
3453 atm->lat[ip], atm->p[ip]));
3454 }
3455}
3456
3457/*****************************************************************************/
3458
3460 const ctl_t *ctl,
3461 cache_t *cache,
3462 met_t *met0,
3463 met_t *met1,
3464 atm_t *atm) {
3465
3466 /* Set timer... */
3467 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
3468
3469 /* Create random numbers... */
3470 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
3471
3472 /* Loop over particles... */
3473 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3474
3475 /* Interpolate surface pressure... */
3476 double ps;
3478 INTPOL_2D(ps, 1);
3479
3480 /* Initialize pressure range for vertical mixing... */
3481 double pbot = ps, ptop = ps;
3482
3483 /* Mixing in the PBL... */
3484 if (ctl->conv_mix_pbl) {
3485
3486 /* Interpolate PBL... */
3487 double pbl;
3488 INTPOL_2D(pbl, 0);
3489
3490 /* Set pressure range... */
3491 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
3492 }
3493
3494 /* Convective mixing... */
3495 if (ctl->conv_cape >= 0) {
3496
3497 /* Interpolate CAPE, CIN, and equilibrium level... */
3498 double cape, cin, pel;
3499 INTPOL_2D(cape, 0);
3500 INTPOL_2D(cin, 0);
3501 INTPOL_2D(pel, 0);
3502
3503 /* Set pressure range... */
3504 if (isfinite(cape) && cape >= ctl->conv_cape
3505 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
3506 ptop = GSL_MIN(ptop, pel);
3507 }
3508
3509 /* Apply vertical mixing... */
3510 if (ptop != pbot && atm->p[ip] >= ptop) {
3511
3512 /* Get density range... */
3513 double tbot, ttop;
3514 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
3515 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
3516 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
3517 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
3518 const double rhobot = pbot / tbot;
3519 const double rhotop = ptop / ttop;
3520
3521 /* Get new density... */
3522 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
3523
3524 /* Get pressure... */
3525 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
3526 }
3527 }
3528}
3529
3530/*****************************************************************************/
3531
3532#ifdef DD
3533void module_dd(
3534 ctl_t *ctl,
3535 atm_t *atm,
3536 cache_t *cache,
3537 dd_t *dd,
3538 met_t **met) {
3539
3540 /* Initialize particles locally... */
3541 int nparticles = 0;
3542 particle_t *particles;
3543 ALLOC(particles, particle_t, DD_NPART);
3544
3545 /* Assign particles to new subdomains... */
3546 dd_assign_rect_subdomains_atm(atm, ctl, dd, 0);
3547
3548 /* Sorting particles according to location and target rank... */
3549 dd_sort(ctl, *met, atm, dd, &nparticles, &dd->rank);
3550
3551 /* Transform from struct of array to array of struct... */
3552 dd_atm2particles(atm, particles, ctl, &nparticles, cache, dd->rank);
3553
3554 /********************* CPU region start ***********************************/
3555
3556 /* Perform the communication... */
3557 dd_communicate_particles(particles, &nparticles, dd->MPI_Particle,
3558 dd->neighbours, ctl->dd_nbr_neighbours, *ctl);
3559
3560 /********************* CPU region end *************************************/
3561
3562 /* Transform from array of struct to struct of array... */
3563 dd_particles2atm(atm, particles, ctl, &nparticles, cache);
3564
3565 /* Free local particle array... */
3566 free(particles);
3567}
3568#endif
3569
3570/*****************************************************************************/
3571
3573 const ctl_t *ctl,
3574 const cache_t *cache,
3575 const clim_t *clim,
3576 atm_t *atm) {
3577
3578 /* Set timer... */
3579 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
3580
3581 /* Check quantity flags... */
3582 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3583 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3584
3585 /* Loop over particles... */
3586 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
3587
3588 /* Get weighting factor... */
3589 const double w = tropo_weight(clim, atm, ip);
3590
3591 /* Set lifetime... */
3592 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
3593
3594 /* Calculate exponential decay... */
3595 const double aux = exp(-cache->dt[ip] / tdec);
3596 if (ctl->qnt_m >= 0) {
3597 if (ctl->qnt_mloss_decay >= 0)
3598 atm->q[ctl->qnt_mloss_decay][ip]
3599 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3600 atm->q[ctl->qnt_m][ip] *= aux;
3601 if (ctl->qnt_loss_rate >= 0)
3602 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
3603 }
3604 if (ctl->qnt_vmr >= 0)
3605 atm->q[ctl->qnt_vmr][ip] *= aux;
3606 }
3607}
3608
3609/*****************************************************************************/
3610
3612 const ctl_t *ctl,
3613 cache_t *cache,
3614 met_t *met0,
3615 met_t *met1,
3616 atm_t *atm) {
3617
3618 /* Set timer... */
3619 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS", NVTX_GPU);
3620
3621 /* Create random numbers... */
3622 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3623
3624 /* Loop over particles... */
3625 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3626
3627 /* Get indices... */
3628 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
3629 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
3630 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
3631
3632 /* Get standard deviations of local wind data... */
3633 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
3634 for (int i = 0; i < 2; i++)
3635 for (int j = 0; j < 2; j++)
3636 for (int k = 0; k < 2; k++) {
3637 umean += met0->u[ix + i][iy + j][iz + k];
3638 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
3639 vmean += met0->v[ix + i][iy + j][iz + k];
3640 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
3641 wmean += met0->w[ix + i][iy + j][iz + k];
3642 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
3643
3644 umean += met1->u[ix + i][iy + j][iz + k];
3645 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
3646 vmean += met1->v[ix + i][iy + j][iz + k];
3647 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
3648 wmean += met1->w[ix + i][iy + j][iz + k];
3649 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
3650 }
3651 usig = usig / 16.f - SQR(umean / 16.f);
3652 usig = (usig > 0 ? sqrtf(usig) : 0);
3653 vsig = vsig / 16.f - SQR(vmean / 16.f);
3654 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
3655 wsig = wsig / 16.f - SQR(wmean / 16.f);
3656 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
3657
3658 /* Set temporal correlations for mesoscale fluctuations... */
3659 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
3660 const double r2 = sqrt(1 - r * r);
3661
3662 /* Calculate horizontal mesoscale wind fluctuations... */
3663 if (ctl->turb_mesox > 0) {
3664 cache->uvwp[ip][0] =
3665 (float) (r * cache->uvwp[ip][0] +
3666 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
3667 atm->lon[ip] +=
3668 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3669
3670 cache->uvwp[ip][1] =
3671 (float) (r * cache->uvwp[ip][1] +
3672 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
3673 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3674 }
3675
3676 /* Calculate vertical mesoscale wind fluctuations... */
3677 if (ctl->turb_mesoz > 0) {
3678 cache->uvwp[ip][2] =
3679 (float) (r * cache->uvwp[ip][2] +
3680 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
3681 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
3682 }
3683 }
3684}
3685
3686/*****************************************************************************/
3687
3689 const ctl_t *ctl,
3690 cache_t *cache,
3691 met_t *met0,
3692 met_t *met1,
3693 atm_t *atm) {
3694
3695 /* Set timer... */
3696 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS", NVTX_GPU);
3697
3698 /* Create random numbers... */
3699 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3700
3701 /* Loop over particles... */
3702 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3703
3704 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
3705 tau_u = 300., tau_w = 100.;
3706
3707 /* Get surface and PBL pressure... */
3708 double pbl, ps;
3710 INTPOL_2D(ps, 1);
3711 INTPOL_2D(pbl, 0);
3712
3713 /* Boundary layer... */
3714 if (atm->p[ip] >= pbl) {
3715
3716 /* Calculate heights... */
3717 const double p = MIN(atm->p[ip], ps);
3718 const double zs = Z(ps);
3719 const double z = 1e3 * (Z(p) - zs);
3720 const double zi = 1e3 * (Z(pbl) - zs);
3721 const double zratio = z / zi;
3722
3723 /* Calculate friction velocity... */
3724 double ess, nss, h2o, t;
3725 INTPOL_2D(ess, 0);
3726 INTPOL_2D(nss, 0);
3727 INTPOL_3D(t, 1);
3728 INTPOL_3D(h2o, 0);
3729 const double rho = RHO(p, TVIRT(t, h2o));
3730 const double tau = sqrt(SQR(ess) + SQR(nss));
3731 const double ustar = sqrt(tau / rho);
3732
3733 /* Get surface sensible heat flux... */
3734 double shf;
3735 INTPOL_2D(shf, 1);
3736
3737 /* Stable or neutral conditions... */
3738 if (shf <= 0) {
3739
3740 /* Calcalute turbulent velocity variances... */
3741 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
3742 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
3743
3744 /* Calculate derivative dsig_w/dz... */
3745 dsigw_dz = -1.3 * ustar / zi;
3746
3747 /* Calcalute Lagrangian timescales... */
3748 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
3749 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
3750 }
3751
3752 /* Unstable conditions... */
3753 else {
3754
3755 /* Convective velocity... */
3756 const double wstar =
3757 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
3758
3759 /* Calcalute turbulent velocity variances... */
3760 sig_u = 1e-2
3761 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
3762 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
3763 * pow(zratio, 2.0 / 3.0)
3764 + (1.8 - 1.4 * zratio) * SQR(ustar));
3765
3766 /* Calculate derivative dsig_w/dz... */
3767 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
3768 * (0.8 *
3769 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
3770 - 1.8 * pow(zratio, 2.0 / 3.0)));
3771
3772 /* Calculate Lagrangian timescales... */
3773 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
3774 const double eps =
3775 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
3776 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
3777 tau_u = 2 * SQR(sig_u) / (C0 * eps);
3778 tau_w = 2 * SQR(sig_w) / (C0 * eps);
3779 }
3780 }
3781
3782 /* Set minimum values... */
3783 sig_u = MAX(sig_u, 0.25);
3784 sig_w = MAX(sig_w, 0.1);
3785 tau_u = MAX(tau_u, 300.);
3786 tau_w = MAX(tau_w, 100.);
3787
3788 /* Update perturbations... */
3789 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
3790 const double ru2 = sqrt(1.0 - SQR(ru));
3791 cache->uvwp[ip][0]
3792 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
3793 cache->uvwp[ip][1]
3794 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
3795
3796 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
3797 const double rw2 = sqrt(1.0 - SQR(rw));
3798 cache->uvwp[ip][2]
3799 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
3800 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
3801
3802 /* Calculate new air parcel position... */
3803 atm->lon[ip] +=
3804 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3805 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3806 atm->p[ip] +=
3807 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
3808 }
3809}
3810
3811/*****************************************************************************/
3812
3814 const ctl_t *ctl,
3815 cache_t *cache,
3816 const clim_t *clim,
3817 met_t *met0,
3818 met_t *met1,
3819 atm_t *atm) {
3820
3821 /* Set timer... */
3822 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS", NVTX_GPU);
3823
3824 /* Create random numbers... */
3825 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3826
3827 /* Loop over particles... */
3828 PARTICLE_LOOP(0, atm->np, 1,
3829 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3830
3831 /* Get PBL and surface pressure... */
3832 double pbl, ps;
3834 INTPOL_2D(pbl, 1);
3835 INTPOL_2D(ps, 0);
3836
3837 /* Get weighting factors... */
3838 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
3839 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
3840 const double wstrat = 1.0 - wpbl - wtrop;
3841
3842 /* Set diffusivity... */
3843 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
3844 + wstrat * ctl->turb_dx_strat;
3845 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
3846 + wstrat * ctl->turb_dz_strat;
3847
3848 /* Horizontal turbulent diffusion... */
3849 if (dx > 0) {
3850 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
3851 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
3852 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
3853 }
3854
3855 /* Vertical turbulent diffusion... */
3856 if (dz > 0) {
3857 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
3858 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
3859 }
3860 }
3861}
3862
3863/*****************************************************************************/
3864
3866 const ctl_t *ctl,
3867 const cache_t *cache,
3868 met_t *met0,
3869 met_t *met1,
3870 atm_t *atm) {
3871
3872 /* Set timer... */
3873 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS", NVTX_GPU);
3874
3875 /* Check quantity flags... */
3876 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3877 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3878
3879 /* Loop over particles... */
3880 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3881
3882 /* Get surface pressure... */
3883 double ps;
3885 INTPOL_2D(ps, 1);
3886
3887 /* Check whether particle is above the surface layer... */
3888 if (atm->p[ip] < ps - ctl->dry_depo_dp)
3889 continue;
3890
3891 /* Set depth of surface layer... */
3892 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
3893
3894 /* Calculate sedimentation velocity for particles... */
3895 double v_dep;
3896 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
3897
3898 /* Get temperature... */
3899 double t;
3900 INTPOL_3D(t, 1);
3901
3902 /* Set deposition velocity... */
3903 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3904 atm->q[ctl->qnt_rhop][ip]);
3905 }
3906
3907 /* Use explicit sedimentation velocity for gases... */
3908 else
3909 v_dep = ctl->dry_depo_vdep;
3910
3911 /* Calculate loss of mass based on deposition velocity... */
3912 const double aux = exp(-cache->dt[ip] * v_dep / dz);
3913 if (ctl->qnt_m >= 0) {
3914 if (ctl->qnt_mloss_dry >= 0)
3915 atm->q[ctl->qnt_mloss_dry][ip]
3916 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3917 atm->q[ctl->qnt_m][ip] *= aux;
3918 if (ctl->qnt_loss_rate >= 0)
3919 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
3920 }
3921 if (ctl->qnt_vmr >= 0)
3922 atm->q[ctl->qnt_vmr][ip] *= aux;
3923 }
3924}
3925
3926/*****************************************************************************/
3927
3929 const ctl_t *ctl,
3930 const cache_t *cache,
3931 const clim_t *clim,
3932 met_t *met0,
3933 met_t *met1,
3934 atm_t *atm) {
3935
3936 /* Set timer... */
3937 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS", NVTX_GPU);
3938
3939 /* Check quantity flags... */
3940 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3941 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3942
3943 /* Parameter of SO2 correction... */
3944 const double a = 3.12541941e-06;
3945 const double b = -5.72532259e-01;
3946 const double low = pow(1. / a, 1. / b);
3947
3948 /* Loop over particles... */
3949 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3950
3951 /* Check whether particle is inside cloud... */
3952 double lwc, rwc;
3954 INTPOL_3D(lwc, 1);
3955 INTPOL_3D(rwc, 0);
3956 if (!(lwc > 0 || rwc > 0))
3957 continue;
3958
3959 /* Get temperature... */
3960 double t;
3961 INTPOL_3D(t, 0);
3962
3963 /* Get molecular density... */
3964 const double M = MOLEC_DENS(atm->p[ip], t);
3965
3966 /* Reaction rate (Berglen et al., 2004)... */
3967 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3968
3969 /* Henry constant of SO2... */
3970 const double H_SO2 =
3971 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3972 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3973
3974 /* Henry constant of H2O2... */
3975 const double H_h2o2 =
3976 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3977
3978 /* Correction factor for high SO2 concentration
3979 (if qnt_Cx is defined, the correction is switched on)... */
3980 double cor = 1.0;
3981 if (ctl->qnt_Cx >= 0)
3982 cor = atm->q[ctl->qnt_Cx][ip] >
3983 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3984
3985 const double h2o2 = H_h2o2
3986 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3987 * M * cor * 1000. / AVO; /* unit: mol/L */
3988
3989 /* Volume water content in cloud [m^3 m^(-3)]... */
3990 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3991 const double CWC = (lwc + rwc) * rho_air / 1e3;
3992
3993 /* Calculate exponential decay (Rolph et al., 1992)... */
3994 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3995 const double aux = exp(-cache->dt[ip] * rate_coef);
3996 if (ctl->qnt_m >= 0) {
3997 if (ctl->qnt_mloss_h2o2 >= 0)
3998 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3999 atm->q[ctl->qnt_m][ip] *= aux;
4000 if (ctl->qnt_loss_rate >= 0)
4001 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4002 }
4003 if (ctl->qnt_vmr >= 0)
4004 atm->q[ctl->qnt_vmr][ip] *= aux;
4005 }
4006}
4007
4008/*****************************************************************************/
4009
4011 const ctl_t *ctl,
4012 cache_t *cache,
4013 met_t *met0,
4014 met_t *met1,
4015 atm_t *atm) {
4016
4017 double t;
4018
4019 /* Set timer... */
4020 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS", NVTX_GPU);
4021
4022 /* Save pressure... */
4023 if (ctl->isosurf == 1) {
4024 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
4025 cache->iso_var[ip] = atm->p[ip];
4026 }
4027 }
4028
4029 /* Save density... */
4030 else if (ctl->isosurf == 2) {
4031 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4033 INTPOL_3D(t, 1);
4034 cache->iso_var[ip] = atm->p[ip] / t;
4035 }
4036 }
4037
4038 /* Save potential temperature... */
4039 else if (ctl->isosurf == 3) {
4040 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4042 INTPOL_3D(t, 1);
4043 cache->iso_var[ip] = THETA(atm->p[ip], t);
4044 }
4045 }
4046
4047 /* Read balloon pressure data... */
4048 else if (ctl->isosurf == 4) {
4049
4050 /* Write info... */
4051 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
4052
4053 /* Open file... */
4054 FILE *in;
4055 if (!(in = fopen(ctl->balloon, "r")))
4056 ERRMSG("Cannot open file!");
4057
4058 /* Read pressure time series... */
4059 char line[LEN];
4060 while (fgets(line, LEN, in))
4061 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
4062 &(cache->iso_ps[cache->iso_n])) == 2)
4063 if ((++cache->iso_n) > NP)
4064 ERRMSG("Too many data points!");
4065
4066 /* Check number of points... */
4067 if (cache->iso_n < 1)
4068 ERRMSG("Could not read any data!");
4069
4070 /* Close file... */
4071 fclose(in);
4072
4073 /* Update of cache data on device... */
4074 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
4075 }
4076}
4077
4078/*****************************************************************************/
4079
4081 const ctl_t *ctl,
4082 const cache_t *cache,
4083 met_t *met0,
4084 met_t *met1,
4085 atm_t *atm) {
4086
4087 /* Set timer... */
4088 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
4089
4090 /* Loop over particles... */
4091 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
4092
4093 /* Init... */
4094 double t;
4096
4097 /* Restore pressure... */
4098 if (ctl->isosurf == 1)
4099 atm->p[ip] = cache->iso_var[ip];
4100
4101 /* Restore density... */
4102 else if (ctl->isosurf == 2) {
4103 INTPOL_3D(t, 1);
4104 atm->p[ip] = cache->iso_var[ip] * t;
4105 }
4106
4107 /* Restore potential temperature... */
4108 else if (ctl->isosurf == 3) {
4109 INTPOL_3D(t, 1);
4110 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
4111 }
4112
4113 /* Interpolate pressure... */
4114 else if (ctl->isosurf == 4) {
4115 if (atm->time[ip] <= cache->iso_ts[0])
4116 atm->p[ip] = cache->iso_ps[0];
4117 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
4118 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
4119 else {
4120 const int idx =
4121 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
4122 atm->p[ip] =
4123 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
4124 cache->iso_ps[idx + 1], atm->time[ip]);
4125 }
4126 }
4127 }
4128}
4129
4130/*****************************************************************************/
4131
4132#ifdef KPP
4133void module_kpp_chem(
4134 ctl_t *ctl,
4135 cache_t *cache,
4136 clim_t *clim,
4137 met_t *met0,
4138 met_t *met1,
4139 atm_t *atm) {
4140
4141 /* Set timer... */
4142 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS", NVTX_GPU);
4143
4144 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
4145 double rtol[1] = { 1.0e-3 };
4146 double atol[1] = { 1.0 };
4147
4148 /* Loop over particles... */
4149#ifdef _OPENACC
4150#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
4151#endif
4152 PARTICLE_LOOP(0, atm->np, 1,
4153 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
4154
4155 /* Initialize... */
4156 double var[nvar], fix[nfix], rconst[nreact];
4157 for (int i = 0; i < nvar; i++)
4158 var[i] = 0.0;
4159 for (int i = 0; i < nfix; i++)
4160 fix[i] = 0.0;
4161 for (int i = 0; i < nreact; i++)
4162 rconst[i] = 0.0;
4163 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
4164
4165 /* Integrate... */
4166 double rpar[20];
4167 int ipar[20];
4168 for (int i = 0; i < 20; i++) {
4169 ipar[i] = 0;
4170 rpar[i] = 0.0;
4171 }
4172 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) */
4173 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
4174 ipar[3] = 4; /* choice of the method:Rodas3 */
4175 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
4176 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
4177
4178 /* Save results.. */
4179 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
4180 }
4181}
4182#endif
4183
4184/*****************************************************************************/
4185
4187 const ctl_t *ctl,
4188 const cache_t *cache,
4189 const clim_t *clim,
4190 met_t *met0,
4191 met_t *met1,
4192 atm_t *atm) {
4193
4194 /* Set timer... */
4195 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
4196
4197 /* Check quantity flags... */
4198 if (ctl->qnt_tsts >= 0)
4199 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
4200 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
4201
4202 /* Loop over particles... */
4203 PARTICLE_LOOP(0, atm->np, 0,
4204 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4205
4206 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
4207 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
4208 o3, lwc, rwc, iwc, swc, cc, z, zt;
4209
4210 /* Interpolate meteo data... */
4212 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
4213
4214 /* Set quantities... */
4215 SET_ATM(qnt_ps, ps);
4216 SET_ATM(qnt_ts, ts);
4217 SET_ATM(qnt_zs, zs);
4218 SET_ATM(qnt_us, us);
4219 SET_ATM(qnt_vs, vs);
4220 SET_ATM(qnt_ess, ess);
4221 SET_ATM(qnt_nss, nss);
4222 SET_ATM(qnt_shf, shf);
4223 SET_ATM(qnt_lsm, lsm);
4224 SET_ATM(qnt_sst, sst);
4225 SET_ATM(qnt_pbl, pbl);
4226 SET_ATM(qnt_pt, pt);
4227 SET_ATM(qnt_tt, tt);
4228 SET_ATM(qnt_zt, zt);
4229 SET_ATM(qnt_h2ot, h2ot);
4230 SET_ATM(qnt_zg, z);
4231 SET_ATM(qnt_p, atm->p[ip]);
4232 SET_ATM(qnt_t, t);
4233 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
4234 SET_ATM(qnt_u, u);
4235 SET_ATM(qnt_v, v);
4236 SET_ATM(qnt_w, w);
4237 SET_ATM(qnt_h2o, h2o);
4238 SET_ATM(qnt_o3, o3);
4239 SET_ATM(qnt_lwc, lwc);
4240 SET_ATM(qnt_rwc, rwc);
4241 SET_ATM(qnt_iwc, iwc);
4242 SET_ATM(qnt_swc, swc);
4243 SET_ATM(qnt_cc, cc);
4244 SET_ATM(qnt_pct, pct);
4245 SET_ATM(qnt_pcb, pcb);
4246 SET_ATM(qnt_cl, cl);
4247 SET_ATM(qnt_plcl, plcl);
4248 SET_ATM(qnt_plfc, plfc);
4249 SET_ATM(qnt_pel, pel);
4250 SET_ATM(qnt_cape, cape);
4251 SET_ATM(qnt_cin, cin);
4252 SET_ATM(qnt_o3c, o3c);
4253 SET_ATM(qnt_hno3,
4254 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
4255 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
4256 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4257 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
4258 atm->lat[ip], atm->p[ip]));
4259 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
4260 atm->lat[ip], atm->p[ip]));
4261 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
4262 atm->lat[ip], atm->p[ip]));
4263 SET_ATM(qnt_vh, sqrt(u * u + v * v));
4264 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
4265 SET_ATM(qnt_psat, PSAT(t));
4266 SET_ATM(qnt_psice, PSICE(t));
4267 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
4268 SET_ATM(qnt_sh, SH(h2o));
4269 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
4270 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
4271 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
4272 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
4273 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
4274 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
4275 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
4276 SET_ATM(qnt_eta_dot, atm->q[ctl->qnt_eta_dot][ip]);
4277 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
4278 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
4279 SET_ATM(qnt_pv, pv);
4280 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
4281 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
4282 SET_ATM(qnt_tnat,
4283 nat_temperature(atm->p[ip], h2o,
4284 clim_zm(&clim->hno3, atm->time[ip],
4285 atm->lat[ip], atm->p[ip])));
4286 SET_ATM(qnt_tsts,
4287 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
4288 }
4289}
4290
4291/*****************************************************************************/
4292
4294 const ctl_t *ctl,
4295 const clim_t *clim,
4296 atm_t *atm,
4297 const double t) {
4298
4299 /* Set timer... */
4300 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
4301
4302 /* Allocate... */
4303 const int np = atm->np;
4304 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
4305 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
4306 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
4307
4308 /* Set grid box size... */
4309 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
4310 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
4311 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
4312
4313 /* Set time interval... */
4314 const double t0 = t - 0.5 * ctl->dt_mod;
4315 const double t1 = t + 0.5 * ctl->dt_mod;
4316
4317 /* Get indices... */
4318#ifdef _OPENACC
4319#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
4320#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
4321#pragma acc parallel loop independent gang vector
4322#else
4323#pragma omp parallel for default(shared)
4324#endif
4325 for (int ip = 0; ip < np; ip++) {
4326 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
4327 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
4328 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
4329 if (atm->time[ip] < t0 || atm->time[ip] > t1
4330 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
4331 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
4332 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
4333 izs[ip] = -1;
4334 }
4335
4336 /* Calculate interparcel mixing... */
4337 const int use_ensemble = (ctl->nens > 0);
4338
4339 const int quantities[] = {
4340 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
4341 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
4342 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
4343 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
4344 ctl->qnt_Csf6, ctl->qnt_aoa
4345 };
4346 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
4347
4348 for (int i = 0; i < n_qnt; i++)
4349 if (quantities[i] >= 0)
4350 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
4351 use_ensemble);
4352
4353 /* Free... */
4354#ifdef _OPENACC
4355#pragma acc exit data delete(ixs,iys,izs)
4356#endif
4357 free(ixs);
4358 free(iys);
4359 free(izs);
4360}
4361
4362/*****************************************************************************/
4363
4365 const ctl_t *ctl,
4366 const clim_t *clim,
4367 atm_t *atm,
4368 const int *ixs,
4369 const int *iys,
4370 const int *izs,
4371 const int qnt_idx,
4372 const int use_ensemble) {
4373
4374 const int np = atm->np;
4375 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
4376 const int nens = use_ensemble ? ctl->nens : 1;
4377 const int total_grid = ngrid * nens;
4378
4379 double *restrict const cmean =
4380 (double *) malloc((size_t) total_grid * sizeof(double));
4381 int *restrict const count =
4382 (int *) malloc((size_t) total_grid * sizeof(int));
4383
4384 /* Init... */
4385#ifdef _OPENACC
4386#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
4387#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
4388#pragma acc parallel loop independent gang vector
4389#else
4390#ifdef __NVCOMPILER
4391#pragma novector
4392#endif
4393#pragma omp parallel for
4394#endif
4395 for (int i = 0; i < total_grid; i++) {
4396 count[i] = 0;
4397 cmean[i] = 0.0;
4398 }
4399
4400 /* Loop over particles... */
4401#ifdef _OPENACC
4402#pragma acc parallel loop independent gang vector
4403#endif
4404 for (int ip = 0; ip < np; ip++)
4405 if (izs[ip] >= 0) {
4406 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4407 const int idx =
4408 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4409 ctl->mixing_nz);
4410#ifdef _OPENACC
4411#pragma acc atomic update
4412#endif
4413 cmean[idx] += atm->q[qnt_idx][ip];
4414#ifdef _OPENACC
4415#pragma acc atomic update
4416#endif
4417 count[idx]++;
4418 }
4419
4420 /* Compute means... */
4421#ifdef _OPENACC
4422#pragma acc parallel loop independent gang vector
4423#else
4424#ifdef __NVCOMPILER
4425#pragma novector
4426#endif
4427#pragma omp parallel for
4428#endif
4429 for (int i = 0; i < total_grid; i++)
4430 if (count[i] > 0)
4431 cmean[i] /= count[i];
4432
4433 /* Interparcel mixing... */
4434#ifdef _OPENACC
4435#pragma acc parallel loop independent gang vector
4436#else
4437#pragma omp parallel for
4438#endif
4439 for (int ip = 0; ip < np; ip++) {
4440 if (izs[ip] >= 0) {
4441 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4442
4443 double mixparam = 1.0;
4444 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
4445 const double w = tropo_weight(clim, atm, ip);
4446 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
4447 }
4448
4449 const int idx =
4450 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4451 ctl->mixing_nz);
4452 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
4453 }
4454 }
4455
4456 /* Free... */
4457#ifdef _OPENACC
4458#pragma acc exit data delete(cmean,count)
4459#endif
4460 free(cmean);
4461 free(count);
4462}
4463
4464/*****************************************************************************/
4465
4467 const ctl_t *ctl,
4468 const cache_t *cache,
4469 const clim_t *clim,
4470 met_t *met0,
4471 met_t *met1,
4472 atm_t *atm) {
4473
4474 /* Set timer... */
4475 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS", NVTX_GPU);
4476
4477 /* Check quantity flags... */
4478 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4479 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4480
4481 /* Parameter of SO2 correction... */
4482 const double a = 4.71572206e-08;
4483 const double b = -8.28782867e-01;
4484 const double low = pow(1. / a, 1. / b);
4485
4486 /* Loop over particles... */
4487 PARTICLE_LOOP(0, atm->np, 1,
4488 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4489
4490 /* Get temperature... */
4491 double t;
4493 INTPOL_3D(t, 1);
4494
4495 /* Calculate molecular density... */
4496 const double M = MOLEC_DENS(atm->p[ip], t);
4497
4498 /* Use constant reaction rate... */
4499 double k = NAN;
4500 if (ctl->oh_chem_reaction == 1)
4501 k = ctl->oh_chem[0];
4502
4503 /* Calculate bimolecular reaction rate... */
4504 else if (ctl->oh_chem_reaction == 2)
4505 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
4506
4507 /* Calculate termolecular reaction rate... */
4508 if (ctl->oh_chem_reaction == 3) {
4509
4510 /* Calculate rate coefficient for X + OH + M -> XOH + M
4511 (JPL Publication 19-05) ... */
4512 const double k0 =
4513 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
4514 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
4515 const double ki =
4516 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
4517 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
4518 const double c = log10(k0 * M / ki);
4519 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
4520 }
4521
4522 /* Correction factor for high SO2 concentration
4523 (if qnt_Cx is defined, the correction is switched on)... */
4524 double cor = 1;
4525 if (ctl->qnt_Cx >= 0)
4526 cor =
4527 atm->q[ctl->qnt_Cx][ip] >
4528 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
4529
4530 /* Calculate exponential decay... */
4531 const double rate_coef =
4532 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
4533 atm->lat[ip], atm->p[ip]) * M * cor;
4534 const double aux = exp(-cache->dt[ip] * rate_coef);
4535 if (ctl->qnt_m >= 0) {
4536 if (ctl->qnt_mloss_oh >= 0)
4537 atm->q[ctl->qnt_mloss_oh][ip]
4538 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4539 atm->q[ctl->qnt_m][ip] *= aux;
4540 if (ctl->qnt_loss_rate >= 0)
4541 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4542 }
4543 if (ctl->qnt_vmr >= 0)
4544 atm->q[ctl->qnt_vmr][ip] *= aux;
4545 }
4546}
4547
4548/*****************************************************************************/
4549
4551 const cache_t *cache,
4552 met_t *met0,
4553 met_t *met1,
4554 atm_t *atm) {
4555
4556 /* Set timer... */
4557 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
4558
4559 /* Loop over particles... */
4560 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
4561
4562 /* Init... */
4563 double ps;
4565
4566 /* Calculate modulo... */
4567 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
4568 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
4569
4570 /* Check latitude... */
4571 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
4572 if (atm->lat[ip] > 90) {
4573 atm->lat[ip] = 180 - atm->lat[ip];
4574 atm->lon[ip] += 180;
4575 }
4576 if (atm->lat[ip] < -90) {
4577 atm->lat[ip] = -180 - atm->lat[ip];
4578 atm->lon[ip] += 180;
4579 }
4580 }
4581
4582 /* Check longitude... */
4583 while (atm->lon[ip] < -180)
4584 atm->lon[ip] += 360;
4585 while (atm->lon[ip] >= 180)
4586 atm->lon[ip] -= 360;
4587
4588 /* Check pressure... */
4589 if (atm->p[ip] < met0->p[met0->np - 1]) {
4590 atm->p[ip] = met0->p[met0->np - 1];
4591 } else if (atm->p[ip] > 300.) {
4592 INTPOL_2D(ps, 1);
4593 if (atm->p[ip] > ps)
4594 atm->p[ip] = ps;
4595 }
4596 }
4597}
4598
4599/*****************************************************************************/
4600
4602 const int ntask) {
4603
4604 /* Initialize GSL random number generators... */
4605 gsl_rng_env_setup();
4606 if (omp_get_max_threads() > NTHREADS)
4607 ERRMSG("Too many threads!");
4608 for (int i = 0; i < NTHREADS; i++) {
4609 rng[i] = gsl_rng_alloc(gsl_rng_default);
4610 gsl_rng_set(rng[i], gsl_rng_default_seed
4611 + (long unsigned) (ntask * NTHREADS + i));
4612 }
4613
4614 /* Initialize cuRAND random number generators... */
4615#ifdef CURAND
4616 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
4617 CURAND_STATUS_SUCCESS)
4618 ERRMSG("Cannot create random number generator!");
4619 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
4620 CURAND_STATUS_SUCCESS)
4621 ERRMSG("Cannot set seed for random number generator!");
4622 if (curandSetStream
4623 (rng_curand,
4624 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
4625 CURAND_STATUS_SUCCESS)
4626 ERRMSG("Cannot set stream for random number generator!");
4627#endif
4628}
4629
4630/*****************************************************************************/
4631
4633 const ctl_t *ctl,
4634 double *rs,
4635 const size_t n,
4636 const int method) {
4637
4638 /* Use GSL random number generators... */
4639 if (ctl->rng_type == 0) {
4640
4641 /* Uniform distribution... */
4642 if (method == 0) {
4643#pragma omp parallel for default(shared)
4644 for (size_t i = 0; i < n; ++i)
4645 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
4646 }
4647
4648 /* Normal distribution... */
4649 else if (method == 1) {
4650#pragma omp parallel for default(shared)
4651 for (size_t i = 0; i < n; ++i)
4652 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
4653 }
4654
4655 /* Update of random numbers on device... */
4656#ifdef _OPENACC
4657 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
4658#pragma acc update device(rs[:n])
4659#endif
4660 }
4661
4662 /* Use Squares random number generator (Widynski, 2022)... */
4663 else if (ctl->rng_type == 1) {
4664
4665 /* Set key (don't change this!)... */
4666 const uint64_t key = 0xc8e4fd154ce32f6d;
4667
4668 /* Uniform distribution... */
4669#ifdef _OPENACC
4670#pragma acc data present(rs)
4671#pragma acc parallel loop independent gang vector
4672#else
4673#pragma omp parallel for default(shared)
4674#endif
4675 for (size_t i = 0; i < n + 1; ++i) {
4676 uint64_t r, t, x, y, z;
4677 y = x = (rng_ctr + i) * key;
4678 z = y + key;
4679 x = x * x + y;
4680 x = (x >> 32) | (x << 32);
4681 x = x * x + z;
4682 x = (x >> 32) | (x << 32);
4683 x = x * x + y;
4684 x = (x >> 32) | (x << 32);
4685 t = x = x * x + z;
4686 x = (x >> 32) | (x << 32);
4687 r = t ^ ((x * x + y) >> 32);
4688 rs[i] = (double) r / (double) UINT64_MAX;
4689 }
4690 rng_ctr += n + 1;
4691
4692 /* Normal distribution... */
4693 if (method == 1) {
4694#ifdef _OPENACC
4695#pragma acc parallel loop independent gang vector
4696#else
4697#pragma omp parallel for default(shared)
4698#endif
4699 for (size_t i = 0; i < n; i += 2) {
4700 const double r = sqrt(-2.0 * log(rs[i]));
4701 const double phi = 2.0 * M_PI * rs[i + 1];
4702 rs[i] = r * cosf((float) phi);
4703 rs[i + 1] = r * sinf((float) phi);
4704 }
4705 }
4706 }
4707
4708 /* Use cuRAND random number generators... */
4709 else if (ctl->rng_type == 2) {
4710#ifdef CURAND
4711#pragma acc host_data use_device(rs)
4712 {
4713
4714 /* Uniform distribution... */
4715 if (method == 0) {
4716 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
4717 CURAND_STATUS_SUCCESS)
4718 ERRMSG("Cannot create random numbers!");
4719 }
4720
4721 /* Normal distribution... */
4722 else if (method == 1) {
4723 if (curandGenerateNormalDouble
4724 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
4725 1.0) != CURAND_STATUS_SUCCESS)
4726 ERRMSG("Cannot create random numbers!");
4727 }
4728 }
4729#else
4730 ERRMSG("MPTRAC was compiled without cuRAND!");
4731#endif
4732 }
4733}
4734
4735/*****************************************************************************/
4736
4738 const ctl_t *ctl,
4739 const cache_t *cache,
4740 met_t *met0,
4741 met_t *met1,
4742 atm_t *atm) {
4743
4744 /* Set timer... */
4745 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
4746
4747 /* Loop over particles... */
4748 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4749
4750 /* Get temperature... */
4751 double t;
4753 INTPOL_3D(t, 1);
4754
4755 /* Sedimentation velocity... */
4756 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4757 atm->q[ctl->qnt_rhop][ip]);
4758
4759 /* Calculate pressure change... */
4760 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
4761 }
4762}
4763
4764/*****************************************************************************/
4765
4767 const ctl_t *ctl,
4768 met_t *met0,
4769 atm_t *atm) {
4770
4771 /* Set timer... */
4772 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
4773
4774 /* Allocate... */
4775 const int np = atm->np;
4776 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
4777 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
4778 if (a == NULL || p == NULL)
4779 ERRMSG("Out of memory!");
4780
4781#ifdef _OPENACC
4782#pragma acc enter data create(a[0:np],p[0:np])
4783#pragma acc data present(ctl,met0,atm,a,p)
4784#endif
4785
4786 /* Get box index... */
4787#ifdef _OPENACC
4788#pragma acc parallel loop independent gang vector
4789#else
4790#pragma omp parallel for default(shared)
4791#endif
4792 for (int ip = 0; ip < np; ip++) {
4793 a[ip] =
4794 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
4795 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
4796 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
4797 p[ip] = ip;
4798 }
4799
4800 /* Sorting... */
4801#ifdef THRUST
4802#ifdef _OPENACC
4803#pragma acc host_data use_device(a,p)
4804#endif
4805 thrustSortWrapper(a, np, p);
4806#else
4807#ifdef _OPENACC
4808 ERRMSG("GSL sort fallback not available on GPU, use THRUST!");
4809#endif
4810 gsl_sort_index((size_t *) p, a, 1, (size_t) np);
4811#endif
4812
4813 /* Sort data... */
4814 module_sort_help(atm->time, p, np);
4815 module_sort_help(atm->p, p, np);
4816 module_sort_help(atm->lon, p, np);
4817 module_sort_help(atm->lat, p, np);
4818 for (int iq = 0; iq < ctl->nq; iq++)
4819 module_sort_help(atm->q[iq], p, np);
4820
4821 /* Free... */
4822#ifdef _OPENACC
4823#pragma acc exit data delete(a,p)
4824#endif
4825 free(a);
4826 free(p);
4827}
4828
4829/*****************************************************************************/
4830
4832 double *a,
4833 const int *p,
4834 const int np) {
4835
4836 /* Allocate... */
4837 double *restrict const help =
4838 (double *) malloc((size_t) np * sizeof(double));
4839 if (help == NULL)
4840 ERRMSG("Out of memory!");
4841
4842 /* Reordering of array... */
4843#ifdef _OPENACC
4844#pragma acc enter data create(help[0:np])
4845#pragma acc data present(a,p,help)
4846#pragma acc parallel loop independent gang vector
4847#else
4848#pragma omp parallel for default(shared)
4849#endif
4850 for (int ip = 0; ip < np; ip++)
4851 help[ip] = a[p[ip]];
4852#ifdef _OPENACC
4853#pragma acc parallel loop independent gang vector
4854#else
4855#pragma omp parallel for default(shared)
4856#endif
4857 for (int ip = 0; ip < np; ip++)
4858 a[ip] = help[ip];
4859
4860 /* Free... */
4861#ifdef _OPENACC
4862#pragma acc exit data delete(help)
4863#endif
4864 free(help);
4865}
4866
4867/*****************************************************************************/
4868
4870 const ctl_t *ctl,
4871 cache_t *cache,
4872 met_t *met0,
4873 atm_t *atm,
4874 const double t) {
4875
4876 /* Set timer... */
4877 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
4878
4879 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
4880 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
4881
4882 const int local =
4883 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
4884
4885 /* Loop over particles... */
4886 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
4887
4888 /* Set time step for each air parcel... */
4889 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
4890 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
4891 && ctl->direction * (atm->time[ip] - t) < 0))
4892 cache->dt[ip] = t - atm->time[ip];
4893 else
4894 cache->dt[ip] = 0.0;
4895
4896 /* Check horizontal boundaries of local meteo data... */
4897#ifndef DD
4898 int dd = 1;
4899#else
4900 int dd = 0;
4901#endif
4902 if (dd) {
4903 if (local && (atm->lon[ip] <= met0->lon[0]
4904 || atm->lon[ip] >= met0->lon[met0->nx - 1]
4905 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
4906 cache->dt[ip] = 0.0;
4907 } else {
4908 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
4909 cache->dt[ip] = 0;
4910 }
4911 }
4912}
4913
4914/*****************************************************************************/
4915
4917 ctl_t *ctl,
4918 const atm_t *atm) {
4919
4920 /* Set timer... */
4921 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS", NVTX_GPU);
4922
4923 /* Set start time... */
4924 if (ctl->direction == 1) {
4925 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4926 if (ctl->t_stop > 1e99)
4927 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4928 } else {
4929 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4930 if (ctl->t_stop > 1e99)
4931 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4932 }
4933
4934 /* Check time interval... */
4935 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
4936 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
4937
4938 /* Round start time... */
4939 if (ctl->direction == 1)
4940 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4941 else
4942 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4943}
4944
4945/*****************************************************************************/
4946
4948 const ctl_t *ctl,
4949 const cache_t *cache,
4950 const clim_t *clim,
4951 met_t *met0,
4952 met_t *met1,
4953 atm_t *atm) {
4954
4955 /* Set timer... */
4956 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS", NVTX_GPU);
4957
4958 /* Loop over particles... */
4959 PARTICLE_LOOP(0, atm->np, 1,
4960 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4961
4962 /* Get temperature... */
4963 double t;
4965 INTPOL_3D(t, 1);
4966
4967 /* Get molecular density... */
4968 const double M = MOLEC_DENS(atm->p[ip], t);
4969
4970 /* Get total column ozone... */
4971 double o3c;
4972 INTPOL_2D(o3c, 1);
4973
4974 /* Get solar zenith angle... */
4975 const double sza =
4976 acos(cos_sza(atm->time[ip], atm->lon[ip], atm->lat[ip]));
4977
4978 /* Get O(1D) volume mixing ratio... */
4979 const double o1d =
4980 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4981
4982 /* Reactions for CFC-10... */
4983 if (ctl->qnt_Cccl4 >= 0) {
4984 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4985 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4986 atm->p[ip], sza, o3c);
4987 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4988 }
4989
4990 /* Reactions for CFC-11... */
4991 if (ctl->qnt_Cccl3f >= 0) {
4992 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4993 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4994 atm->p[ip], sza, o3c);
4995 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4996 }
4997
4998 /* Reactions for CFC-12... */
4999 if (ctl->qnt_Cccl2f2 >= 0) {
5000 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
5001 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
5002 atm->p[ip], sza, o3c);
5003 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5004 }
5005
5006 /* Reactions for N2O... */
5007 if (ctl->qnt_Cn2o >= 0) {
5008 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
5009 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
5010 atm->p[ip], sza, o3c);
5011 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5012 }
5013 }
5014}
5015
5016/*****************************************************************************/
5017
5019 const ctl_t *ctl,
5020 const cache_t *cache,
5021 met_t *met0,
5022 met_t *met1,
5023 atm_t *atm) {
5024
5025 /* Set timer... */
5026 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS", NVTX_GPU);
5027
5028 /* Check quantity flags... */
5029 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5030 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5031
5032 /* Loop over particles... */
5033 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5034
5035 /* Check whether particle is below cloud top... */
5036 double pct;
5038 INTPOL_2D(pct, 1);
5039 if (!isfinite(pct) || atm->p[ip] <= pct)
5040 continue;
5041
5042 /* Get cloud bottom pressure... */
5043 double pcb;
5044 INTPOL_2D(pcb, 0);
5045
5046 /* Estimate precipitation rate (Pisso et al., 2019)... */
5047 double cl;
5048 INTPOL_2D(cl, 0);
5049 const double Is =
5050 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
5051 if (Is < 0.01)
5052 continue;
5053
5054 /* Check whether particle is inside or below cloud... */
5055 double lwc, rwc, iwc, swc;
5056 INTPOL_3D(lwc, 1);
5057 INTPOL_3D(rwc, 0);
5058 INTPOL_3D(iwc, 0);
5059 INTPOL_3D(swc, 0);
5060 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
5061
5062 /* Get temperature... */
5063 double t;
5064 INTPOL_3D(t, 0);
5065
5066 /* Calculate in-cloud scavenging coefficient... */
5067 double lambda = 0;
5068 if (inside) {
5069
5070 /* Calculate retention factor... */
5071 double eta;
5072 if (t > 273.15)
5073 eta = 1;
5074 else if (t <= 238.15)
5075 eta = ctl->wet_depo_ic_ret_ratio;
5076 else
5077 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
5078
5079 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5080 if (ctl->wet_depo_ic_a > 0)
5081 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
5082
5083 /* Use Henry's law for gases... */
5084 else if (ctl->wet_depo_ic_h[0] > 0) {
5085
5086 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5087 double h = ctl->wet_depo_ic_h[0]
5088 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
5089
5090 /* Use effective Henry's constant for SO2
5091 (Berglen, 2004; Simpson, 2012)... */
5092 if (ctl->wet_depo_so2_ph > 0) {
5093 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
5094 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
5095 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
5096 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
5097 }
5098
5099 /* Estimate depth of cloud layer... */
5100 const double dz = 1e3 * (Z(pct) - Z(pcb));
5101
5102 /* Calculate scavenging coefficient... */
5103 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5104 }
5105 }
5106
5107 /* Calculate below-cloud scavenging coefficient... */
5108 else {
5109
5110 /* Calculate retention factor... */
5111 double eta;
5112 if (t > 270)
5113 eta = 1;
5114 else
5115 eta = ctl->wet_depo_bc_ret_ratio;
5116
5117 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5118 if (ctl->wet_depo_bc_a > 0)
5119 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
5120
5121 /* Use Henry's law for gases... */
5122 else if (ctl->wet_depo_bc_h[0] > 0) {
5123
5124 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5125 const double h = ctl->wet_depo_bc_h[0]
5126 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
5127
5128 /* Estimate depth of cloud layer... */
5129 const double dz = 1e3 * (Z(pct) - Z(pcb));
5130
5131 /* Calculate scavenging coefficient... */
5132 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5133 }
5134 }
5135
5136 /* Calculate exponential decay of mass... */
5137 const double aux = exp(-cache->dt[ip] * lambda);
5138 if (ctl->qnt_m >= 0) {
5139 if (ctl->qnt_mloss_wet >= 0)
5140 atm->q[ctl->qnt_mloss_wet][ip]
5141 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5142 atm->q[ctl->qnt_m][ip] *= aux;
5143 if (ctl->qnt_loss_rate >= 0)
5144 atm->q[ctl->qnt_loss_rate][ip] += lambda;
5145 }
5146 if (ctl->qnt_vmr >= 0)
5147 atm->q[ctl->qnt_vmr][ip] *= aux;
5148 }
5149}
5150
5151/*****************************************************************************/
5152
5154 ctl_t **ctl,
5155 cache_t **cache,
5156 clim_t **clim,
5157 met_t **met0,
5158 met_t **met1,
5159 atm_t **atm,
5160 dd_t **dd) {
5161
5162 /* Initialize GPU... */
5163#ifdef _OPENACC
5164 SELECT_TIMER("ACC_INIT", "INIT", NVTX_GPU);
5165 int rank = 0;
5166#ifdef MPI
5167 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5168#endif
5169 if (acc_get_num_devices(acc_device_nvidia) <= 0)
5170 ERRMSG("Not running on a GPU device!");
5171 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
5172 acc_device_nvidia);
5173 acc_device_t device_type = acc_get_device_type();
5174 acc_init(device_type);
5175#endif
5176
5177 /* Allocate... */
5178 SELECT_TIMER("ALLOC", "MEMORY", NVTX_CPU);
5179 ALLOC(*ctl, ctl_t, 1);
5180 ALLOC(*cache, cache_t, 1);
5181 ALLOC(*clim, clim_t, 1);
5182 ALLOC(*met0, met_t, 1);
5183 ALLOC(*met1, met_t, 1);
5184 ALLOC(*atm, atm_t, 1);
5185 ALLOC(*dd, dd_t, 1);
5186
5187 /* Create data region on GPU... */
5188#ifdef _OPENACC
5189 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY", NVTX_GPU);
5190 ctl_t *ctlup = *ctl;
5191 cache_t *cacheup = *cache;
5192 clim_t *climup = *clim;
5193 met_t *met0up = *met0;
5194 met_t *met1up = *met1;
5195 atm_t *atmup = *atm;
5196#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
5197#ifdef DD
5198 dd_t *ddup = *dd;
5199#pragma acc enter data create(ddup[:1])
5200#endif
5201#endif
5202}
5203
5204/*****************************************************************************/
5205
5207 ctl_t *ctl,
5208 cache_t *cache,
5209 clim_t *clim,
5210 met_t *met0,
5211 met_t *met1,
5212 atm_t *atm,
5213 dd_t *dd) {
5214
5215 /* Delete data region on GPU... */
5216#ifdef _OPENACC
5217 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY", NVTX_GPU);
5218#pragma acc exit data delete (ctl,cache,clim,met0,met1,atm)
5219#endif
5220
5221 /* Free... */
5222 SELECT_TIMER("FREE", "MEMORY", NVTX_CPU);
5223 free(atm);
5224 free(ctl);
5225 free(cache);
5226 free(clim);
5227 free(met0);
5228 free(met1);
5229
5230 /* Free MPI datatype... */
5231#ifdef DD
5232 MPI_Type_free(&dd->MPI_Particle);
5233#endif
5234 free(dd);
5235}
5236
5237/*****************************************************************************/
5238
5240 ctl_t *ctl,
5241 clim_t *clim,
5242 const double t,
5243 met_t **met0,
5244 met_t **met1,
5245 dd_t *dd) {
5246
5247 static int init;
5248
5249 met_t *mets;
5250
5251 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
5252
5253 /* Set timer... */
5254 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5255
5256 /* Init... */
5257 if (t == ctl->t_start || !init) {
5258 init = 1;
5259
5260 /* Read meteo data... */
5261 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
5262 ctl->metbase, ctl->dt_met, filename);
5263 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5264 ERRMSG("Cannot open file!");
5265
5266 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
5267 ctl->metbase, ctl->dt_met, filename);
5268 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5269 ERRMSG("Cannot open file!");
5270
5271 /* Update GPU... */
5272 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
5273 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5274
5275 /* Caching... */
5276 if (ctl->met_cache && t != ctl->t_stop) {
5277 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
5278 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
5279 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5280 LOG(1, "Caching: %s", cachefile);
5281 if (system(cmd) != 0)
5282 WARN("Caching command failed!");
5283 }
5284 }
5285
5286 /* Read new data for forward trajectories... */
5287 if (t > (*met1)->time) {
5288
5289 /* Pointer swap... */
5290 mets = *met1;
5291 *met1 = *met0;
5292 *met0 = mets;
5293
5294 /* Read new meteo data... */
5295 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
5296 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5297 ERRMSG("Cannot open file!");
5298
5299 /* Update GPU... */
5300 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
5301 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5302
5303 /* Caching... */
5304 if (ctl->met_cache && t != ctl->t_stop) {
5305 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
5306 cachefile);
5307 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5308 LOG(1, "Caching: %s", cachefile);
5309 if (system(cmd) != 0)
5310 WARN("Caching command failed!");
5311 }
5312 }
5313
5314 /* Read new data for backward trajectories... */
5315 if (t < (*met0)->time) {
5316
5317 /* Pointer swap... */
5318 mets = *met1;
5319 *met1 = *met0;
5320 *met0 = mets;
5321
5322 /* Read new meteo data... */
5323 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
5324 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5325 ERRMSG("Cannot open file!");
5326
5327 /* Update GPU... */
5328 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
5329 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
5330
5331 /* Caching... */
5332 if (ctl->met_cache && t != ctl->t_stop) {
5333 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
5334 cachefile);
5335 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5336 LOG(1, "Caching: %s", cachefile);
5337 if (system(cmd) != 0)
5338 WARN("Caching command failed!");
5339 }
5340 }
5341
5342 /* Check that grids are consistent... */
5343 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
5344 if ((*met0)->nx != (*met1)->nx
5345 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
5346 ERRMSG("Meteo grid dimensions do not match!");
5347 for (int ix = 0; ix < (*met0)->nx; ix++)
5348 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
5349 ERRMSG("Meteo grid longitudes do not match!");
5350 for (int iy = 0; iy < (*met0)->ny; iy++)
5351 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
5352 ERRMSG("Meteo grid latitudes do not match!");
5353 for (int ip = 0; ip < (*met0)->np; ip++)
5354 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
5355 ERRMSG("Meteo grid pressure levels do not match!");
5356 }
5357}
5358
5359/*****************************************************************************/
5360
5362 ctl_t *ctl,
5363 cache_t *cache,
5364 clim_t *clim,
5365 atm_t *atm,
5366 const int ntask) {
5367
5368 /* Initialize timesteps... */
5369 module_timesteps_init(ctl, atm);
5370
5371 /* Initialize random number generator... */
5372 module_rng_init(ntask);
5373
5374 /* Update GPU memory... */
5375 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
5376}
5377
5378/*****************************************************************************/
5379
5381 const char *filename,
5382 const ctl_t *ctl,
5383 atm_t *atm) {
5384
5385 int result;
5386
5387 /* Set timer... */
5388 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
5389
5390 /* Init... */
5391 atm->np = 0;
5392
5393 /* Write info... */
5394 LOG(1, "Read atmospheric data: %s", filename);
5395
5396 /* Read ASCII data... */
5397 if (ctl->atm_type == 0)
5398 result = read_atm_asc(filename, ctl, atm);
5399
5400 /* Read binary data... */
5401 else if (ctl->atm_type == 1)
5402 result = read_atm_bin(filename, ctl, atm);
5403
5404 /* Read netCDF data... */
5405 else if (ctl->atm_type == 2)
5406 result = read_atm_nc(filename, ctl, atm);
5407
5408 /* Read CLaMS data... */
5409 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
5410 result = read_atm_clams(filename, ctl, atm);
5411
5412 /* Error... */
5413 else
5414 ERRMSG("Atmospheric data type not supported!");
5415
5416 /* Check result... */
5417 if (result != 1)
5418 return 0;
5419
5420 /* Check number of air parcels... */
5421 if (atm->np < 1)
5422 ERRMSG("Can not read any data!");
5423
5424 /* Write info... */
5425 double mini, maxi;
5426 LOG(2, "Number of particles: %d", atm->np);
5427 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5428 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5429 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5430 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5431 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5432 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5433 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5434 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5435 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5436 for (int iq = 0; iq < ctl->nq; iq++) {
5437 char msg[5 * LEN];
5438 sprintf(msg, "Quantity %s range: %s ... %s %s",
5439 ctl->qnt_name[iq], ctl->qnt_format[iq],
5440 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5441 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5442 LOG(2, msg, mini, maxi);
5443 }
5444
5445 /* Return success... */
5446 return 1;
5447}
5448
5449/*****************************************************************************/
5450
5452 const ctl_t *ctl,
5453 clim_t *clim) {
5454
5455 /* Set timer... */
5456 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
5457
5458 /* Init tropopause climatology... */
5459 clim_tropo_init(clim);
5460
5461 /* Read photolysis rates... */
5462 if (ctl->clim_photo[0] != '-')
5463 read_clim_photo(ctl->clim_photo, &clim->photo);
5464
5465 /* Read HNO3 climatology... */
5466 if (ctl->clim_hno3_filename[0] != '-')
5467 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
5468
5469 /* Read OH climatology... */
5470 if (ctl->clim_oh_filename[0] != '-') {
5471 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
5472 if (ctl->oh_chem_beta > 0)
5473 clim_oh_diurnal_correction(ctl, clim);
5474 }
5475
5476 /* Read H2O2 climatology... */
5477 if (ctl->clim_h2o2_filename[0] != '-')
5478 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
5479
5480 /* Read HO2 climatology... */
5481 if (ctl->clim_ho2_filename[0] != '-')
5482 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
5483
5484 /* Read O(1D) climatology... */
5485 if (ctl->clim_o1d_filename[0] != '-')
5486 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
5487
5488 /* Read CFC-10 time series... */
5489 if (ctl->clim_ccl4_timeseries[0] != '-')
5491
5492 /* Read CFC-11 time series... */
5493 if (ctl->clim_ccl3f_timeseries[0] != '-')
5495
5496 /* Read CFC-12 time series... */
5497 if (ctl->clim_ccl2f2_timeseries[0] != '-')
5499
5500 /* Read N2O time series... */
5501 if (ctl->clim_n2o_timeseries[0] != '-')
5502 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
5503
5504 /* Read SF6 time series... */
5505 if (ctl->clim_sf6_timeseries[0] != '-')
5506 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
5507}
5508
5509/*****************************************************************************/
5510
5512 const char *filename,
5513 int argc,
5514 char *argv[],
5515 ctl_t *ctl) {
5516
5517 /* Set timer... */
5518 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
5519
5520 /* Write info... */
5521 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
5522 "(executable: %s | version: %s | compiled: %s, %s)\n",
5523 argv[0], VERSION, __DATE__, __TIME__);
5524
5525 /* Initialize quantity indices... */
5526 ctl->qnt_idx = -1;
5527 ctl->qnt_ens = -1;
5528 ctl->qnt_stat = -1;
5529 ctl->qnt_m = -1;
5530 ctl->qnt_vmr = -1;
5531 ctl->qnt_rp = -1;
5532 ctl->qnt_rhop = -1;
5533 ctl->qnt_ps = -1;
5534 ctl->qnt_ts = -1;
5535 ctl->qnt_zs = -1;
5536 ctl->qnt_us = -1;
5537 ctl->qnt_vs = -1;
5538 ctl->qnt_ess = -1;
5539 ctl->qnt_nss = -1;
5540 ctl->qnt_shf = -1;
5541 ctl->qnt_lsm = -1;
5542 ctl->qnt_sst = -1;
5543 ctl->qnt_pbl = -1;
5544 ctl->qnt_pt = -1;
5545 ctl->qnt_tt = -1;
5546 ctl->qnt_zt = -1;
5547 ctl->qnt_h2ot = -1;
5548 ctl->qnt_zg = -1;
5549 ctl->qnt_p = -1;
5550 ctl->qnt_t = -1;
5551 ctl->qnt_rho = -1;
5552 ctl->qnt_u = -1;
5553 ctl->qnt_v = -1;
5554 ctl->qnt_w = -1;
5555 ctl->qnt_h2o = -1;
5556 ctl->qnt_o3 = -1;
5557 ctl->qnt_lwc = -1;
5558 ctl->qnt_rwc = -1;
5559 ctl->qnt_iwc = -1;
5560 ctl->qnt_swc = -1;
5561 ctl->qnt_cc = -1;
5562 ctl->qnt_pct = -1;
5563 ctl->qnt_pcb = -1;
5564 ctl->qnt_cl = -1;
5565 ctl->qnt_plcl = -1;
5566 ctl->qnt_plfc = -1;
5567 ctl->qnt_pel = -1;
5568 ctl->qnt_cape = -1;
5569 ctl->qnt_cin = -1;
5570 ctl->qnt_o3c = -1;
5571 ctl->qnt_hno3 = -1;
5572 ctl->qnt_oh = -1;
5573 ctl->qnt_h2o2 = -1;
5574 ctl->qnt_ho2 = -1;
5575 ctl->qnt_o1d = -1;
5576 ctl->qnt_mloss_oh = -1;
5577 ctl->qnt_mloss_h2o2 = -1;
5578 ctl->qnt_mloss_kpp = -1;
5579 ctl->qnt_mloss_wet = -1;
5580 ctl->qnt_mloss_dry = -1;
5581 ctl->qnt_mloss_decay = -1;
5582 ctl->qnt_loss_rate = -1;
5583 ctl->qnt_psat = -1;
5584 ctl->qnt_psice = -1;
5585 ctl->qnt_pw = -1;
5586 ctl->qnt_sh = -1;
5587 ctl->qnt_rh = -1;
5588 ctl->qnt_rhice = -1;
5589 ctl->qnt_theta = -1;
5590 ctl->qnt_zeta = -1;
5591 ctl->qnt_zeta_d = -1;
5592 ctl->qnt_zeta_dot = -1;
5593 ctl->qnt_eta = -1;
5594 ctl->qnt_eta_dot = -1;
5595 ctl->qnt_tvirt = -1;
5596 ctl->qnt_lapse = -1;
5597 ctl->qnt_vh = -1;
5598 ctl->qnt_vz = -1;
5599 ctl->qnt_pv = -1;
5600 ctl->qnt_tdew = -1;
5601 ctl->qnt_tice = -1;
5602 ctl->qnt_tsts = -1;
5603 ctl->qnt_tnat = -1;
5604 ctl->qnt_Cx = -1;
5605 ctl->qnt_Ch2o = -1;
5606 ctl->qnt_Co3 = -1;
5607 ctl->qnt_Cco = -1;
5608 ctl->qnt_Coh = -1;
5609 ctl->qnt_Ch = -1;
5610 ctl->qnt_Cho2 = -1;
5611 ctl->qnt_Ch2o2 = -1;
5612 ctl->qnt_Co1d = -1;
5613 ctl->qnt_Co3p = -1;
5614 ctl->qnt_Cccl4 = -1;
5615 ctl->qnt_Cccl3f = -1;
5616 ctl->qnt_Cccl2f2 = -1;
5617 ctl->qnt_Cn2o = -1;
5618 ctl->qnt_Csf6 = -1;
5619 ctl->qnt_aoa = -1;
5620
5621#ifdef DD
5622 ctl->qnt_destination = -1;
5623 ctl->qnt_subdomain = -1;
5624#endif
5625
5626 /* Read quantities... */
5627 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
5628 if (ctl->nq > NQ)
5629 ERRMSG("Too many quantities!");
5630 for (int iq = 0; iq < ctl->nq; iq++) {
5631
5632 /* Read quantity name and format... */
5633 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
5634 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
5635 ctl->qnt_longname[iq]);
5636 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
5637 ctl->qnt_format[iq]);
5638 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
5639 sprintf(ctl->qnt_format[iq], "%%.2f");
5640
5641 /* Try to identify quantity... */
5642 SET_QNT(qnt_idx, "idx", "particle index", "-")
5643 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
5644 SET_QNT(qnt_stat, "stat", "station flag", "-")
5645 SET_QNT(qnt_m, "m", "mass", "kg")
5646 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
5647 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
5648 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
5649 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
5650 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
5651 SET_QNT(qnt_zs, "zs", "surface height", "km")
5652 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
5653 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
5654 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
5655 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
5656 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
5657 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
5658 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
5659 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
5660 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
5661 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
5662 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
5663 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
5664 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
5665 SET_QNT(qnt_p, "p", "pressure", "hPa")
5666 SET_QNT(qnt_t, "t", "temperature", "K")
5667 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
5668 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
5669 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
5670 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
5671 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
5672 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
5673 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
5674 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
5675 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
5676 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
5677 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
5678 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
5679 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
5680 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
5681 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
5682 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
5683 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
5684 SET_QNT(qnt_cape, "cape", "convective available potential energy",
5685 "J/kg")
5686 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
5687 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
5688 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
5689 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
5690 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
5691 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
5692 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
5693 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
5694 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
5695 "mass loss due to H2O2 chemistry", "kg")
5696 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
5697 "kg")
5698 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
5699 "kg")
5700 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
5701 "kg")
5702 SET_QNT(qnt_mloss_decay, "mloss_decay",
5703 "mass loss due to exponential decay", "kg")
5704 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
5705 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
5706 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
5707 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
5708 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
5709 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
5710 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
5711 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
5712 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
5713 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
5714 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
5715 "K/day")
5716 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
5717 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
5718 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
5719 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
5720 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
5721 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
5722 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
5723 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
5724 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
5725 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
5726 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
5727 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
5728 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
5729 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
5730 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
5731 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
5732 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
5733 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
5734 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
5735 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
5736 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
5737 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
5738 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
5739 "ppv")
5740 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
5741 "ppv")
5742 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
5743 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
5744 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
5745#ifdef DD
5746 SET_QNT(qnt_destination, "destination",
5747 "subdomain index of destination", "-")
5748 SET_QNT(qnt_subdomain, "subdomain", "current subdomain index", "-")
5749#endif
5750 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
5751 }
5752
5753 /* Vertical coordinate and velocity... */
5754 ctl->advect_vert_coord =
5755 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
5756 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
5757 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
5758
5759 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
5760 ERRMSG("Add quantity zeta for diabatic advection!");
5761 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
5762 ERRMSG("Add quantity eta for etadot avection!");
5763
5764 ctl->met_vert_coord =
5765 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
5766 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
5767 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
5768
5769 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
5770 ERRMSG
5771 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
5772 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
5773 ERRMSG
5774 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
5775
5776 /* Time steps of simulation... */
5777 ctl->direction =
5778 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
5779 if (ctl->direction != -1 && ctl->direction != 1)
5780 ERRMSG("Set DIRECTION to -1 or 1!");
5781 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
5782 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
5783
5784 /* Meteo data... */
5785 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
5786 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
5787 ctl->met_convention =
5788 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
5789 ctl->met_type =
5790 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
5791 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
5792 ERRMSG
5793 ("Please use meteo files in netcdf format for diabatic calculations.");
5794 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
5795 ERRMSG
5796 ("Please use meteo files in netcdf format for etadot calculations.");
5797 ctl->met_clams =
5798 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
5799 ctl->met_nc_scale =
5800 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
5801 ctl->met_nc_level =
5802 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
5803 ctl->met_nc_quant =
5804 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
5805 ctl->met_zstd_level =
5806 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
5807 for (int i = 0; i < METVAR; i++) {
5808 char defprec[LEN] = "0", deftol[LEN] = "0.0";
5809 if (i == 0) /* geopotential height */
5810 sprintf(deftol, "0.5");
5811 else if (i == 1) /* temperature */
5812 sprintf(deftol, "5.0");
5813 else /* other variables */
5814 sprintf(defprec, "8");
5815 ctl->met_comp_prec[i] =
5816 (int) scan_ctl(filename, argc, argv, "MET_COMP_PREC", i, defprec, NULL);
5817 ctl->met_comp_tol[i] =
5818 scan_ctl(filename, argc, argv, "MET_COMP_TOL", i, deftol, NULL);
5819 }
5820 ctl->met_cms_batch =
5821 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
5822 ctl->met_cms_zstd =
5823 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
5824 ctl->met_cms_nd0x =
5825 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0X", -1, "48", NULL);
5826 ctl->met_cms_nd0y =
5827 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0Y", -1, "24", NULL);
5828 ctl->met_cms_maxlev =
5829 (int) scan_ctl(filename, argc, argv, "MET_CMS_MAXLEV", -1, "6", NULL);
5830 ctl->met_cms_eps_z =
5831 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
5832 ctl->met_cms_eps_t =
5833 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
5834 ctl->met_cms_eps_u =
5835 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
5836 ctl->met_cms_eps_v =
5837 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
5838 ctl->met_cms_eps_w =
5839 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
5840 ctl->met_cms_eps_pv =
5841 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
5842 ctl->met_cms_eps_h2o =
5843 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
5844 ctl->met_cms_eps_o3 =
5845 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
5846 ctl->met_cms_eps_lwc =
5847 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
5848 ctl->met_cms_eps_rwc =
5849 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
5850 ctl->met_cms_eps_iwc =
5851 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
5852 ctl->met_cms_eps_swc =
5853 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
5854 ctl->met_cms_eps_cc =
5855 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
5856 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
5857 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
5858 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
5859 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
5860 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
5861 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
5862 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
5863 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
5864 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
5865 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
5866 ctl->met_detrend =
5867 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
5868 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
5869 if (ctl->met_np > EP)
5870 ERRMSG("Too many pressure levels!");
5871 ctl->met_press_level_def =
5872 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
5873 NULL);
5874 if (ctl->met_press_level_def >= 0) {
5875 level_definitions(ctl);
5876 } else {
5877 if (ctl->met_np > 0) {
5878 for (int ip = 0; ip < ctl->met_np; ip++)
5879 ctl->met_p[ip] =
5880 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
5881 }
5882 }
5883 ctl->met_nlev =
5884 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
5885 if (ctl->met_nlev > EP)
5886 ERRMSG("Too many model levels!");
5887 for (int ip = 0; ip < ctl->met_nlev; ip++)
5888 ctl->met_lev_hyam[ip] =
5889 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
5890 for (int ip = 0; ip < ctl->met_nlev; ip++)
5891 ctl->met_lev_hybm[ip] =
5892 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
5893 ctl->met_geopot_sx =
5894 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
5895 ctl->met_geopot_sy =
5896 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
5897 ctl->met_relhum =
5898 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
5899 ctl->met_cape =
5900 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
5901 if (ctl->met_cape < 0 || ctl->met_cape > 1)
5902 ERRMSG("Set MET_CAPE to 0 or 1!");
5903 ctl->met_pbl =
5904 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
5905 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
5906 ERRMSG("Set MET_PBL to 0 ... 3!");
5907 ctl->met_pbl_min =
5908 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
5909 ctl->met_pbl_max =
5910 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
5911 ctl->met_tropo =
5912 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
5913 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
5914 ERRMSG("Set MET_TROPO to 0 ... 5!");
5915 ctl->met_tropo_pv =
5916 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
5917 ctl->met_tropo_theta =
5918 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
5919 ctl->met_tropo_spline =
5920 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
5921 ctl->met_dt_out =
5922 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
5923 ctl->met_cache =
5924 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
5925 ctl->met_mpi_share =
5926 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
5927
5928 /* Sorting... */
5929 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
5930
5931 /* Isosurface parameters... */
5932 ctl->isosurf =
5933 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
5934 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
5935
5936 /* Random number generator... */
5937 ctl->rng_type =
5938 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
5939 if (ctl->rng_type < 0 || ctl->rng_type > 2)
5940 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
5941
5942 /* Advection parameters... */
5943 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
5944 if (!
5945 (ctl->advect == 0 || ctl->advect == 1 || ctl->advect == 2
5946 || ctl->advect == 4))
5947 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
5948
5949 /* Diffusion parameters... */
5950 ctl->diffusion
5951 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
5952 if (ctl->diffusion < 0 || ctl->diffusion > 2)
5953 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
5954 ctl->turb_dx_pbl =
5955 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
5956 ctl->turb_dx_trop =
5957 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
5958 ctl->turb_dx_strat =
5959 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
5960 ctl->turb_dz_pbl =
5961 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
5962 ctl->turb_dz_trop =
5963 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
5964 ctl->turb_dz_strat =
5965 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
5966 ctl->turb_mesox =
5967 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
5968 ctl->turb_mesoz =
5969 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5970
5971 /* Convection... */
5972 ctl->conv_mix_pbl
5973 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
5974 ctl->conv_pbl_trans
5975 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
5976 ctl->conv_cape
5977 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5978 ctl->conv_cin
5979 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5980 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5981
5982 /* Boundary conditions... */
5983 ctl->bound_mass =
5984 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5985 ctl->bound_mass_trend =
5986 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5987 ctl->bound_vmr =
5988 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5989 ctl->bound_vmr_trend =
5990 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5991 ctl->bound_lat0 =
5992 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5993 ctl->bound_lat1 =
5994 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5995 ctl->bound_p0 =
5996 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5997 ctl->bound_p1 =
5998 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5999 ctl->bound_dps =
6000 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
6001 ctl->bound_dzs =
6002 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
6003 ctl->bound_zetas =
6004 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
6005 ctl->bound_pbl =
6006 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
6007
6008 /* Species parameters... */
6009 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
6010 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
6011 ctl->molmass = 120.907;
6012 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
6013 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
6014 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
6015 ctl->molmass = 137.359;
6016 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
6017 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
6018 } else if (strcasecmp(ctl->species, "CH4") == 0) {
6019 ctl->molmass = 16.043;
6020 ctl->oh_chem_reaction = 2;
6021 ctl->oh_chem[0] = 2.45e-12;
6022 ctl->oh_chem[1] = 1775;
6023 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
6024 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6025 } else if (strcasecmp(ctl->species, "CO") == 0) {
6026 ctl->molmass = 28.01;
6027 ctl->oh_chem_reaction = 3;
6028 ctl->oh_chem[0] = 6.9e-33;
6029 ctl->oh_chem[1] = 2.1;
6030 ctl->oh_chem[2] = 1.1e-12;
6031 ctl->oh_chem[3] = -1.3;
6032 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
6033 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
6034 } else if (strcasecmp(ctl->species, "CO2") == 0) {
6035 ctl->molmass = 44.009;
6036 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
6037 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6038 } else if (strcasecmp(ctl->species, "H2O") == 0) {
6039 ctl->molmass = 18.01528;
6040 } else if (strcasecmp(ctl->species, "N2O") == 0) {
6041 ctl->molmass = 44.013;
6042 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
6043 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
6044 } else if (strcasecmp(ctl->species, "NH3") == 0) {
6045 ctl->molmass = 17.031;
6046 ctl->oh_chem_reaction = 2;
6047 ctl->oh_chem[0] = 1.7e-12;
6048 ctl->oh_chem[1] = 710;
6049 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
6050 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
6051 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
6052 ctl->molmass = 63.012;
6053 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
6054 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
6055 } else if (strcasecmp(ctl->species, "NO") == 0) {
6056 ctl->molmass = 30.006;
6057 ctl->oh_chem_reaction = 3;
6058 ctl->oh_chem[0] = 7.1e-31;
6059 ctl->oh_chem[1] = 2.6;
6060 ctl->oh_chem[2] = 3.6e-11;
6061 ctl->oh_chem[3] = 0.1;
6062 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
6063 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6064 } else if (strcasecmp(ctl->species, "NO2") == 0) {
6065 ctl->molmass = 46.005;
6066 ctl->oh_chem_reaction = 3;
6067 ctl->oh_chem[0] = 1.8e-30;
6068 ctl->oh_chem[1] = 3.0;
6069 ctl->oh_chem[2] = 2.8e-11;
6070 ctl->oh_chem[3] = 0.0;
6071 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
6072 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6073 } else if (strcasecmp(ctl->species, "O3") == 0) {
6074 ctl->molmass = 47.997;
6075 ctl->oh_chem_reaction = 2;
6076 ctl->oh_chem[0] = 1.7e-12;
6077 ctl->oh_chem[1] = 940;
6078 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
6079 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
6080 } else if (strcasecmp(ctl->species, "SF6") == 0) {
6081 ctl->molmass = 146.048;
6082 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
6083 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
6084 } else if (strcasecmp(ctl->species, "SO2") == 0) {
6085 ctl->molmass = 64.066;
6086 ctl->oh_chem_reaction = 3;
6087 ctl->oh_chem[0] = 2.9e-31;
6088 ctl->oh_chem[1] = 4.1;
6089 ctl->oh_chem[2] = 1.7e-12;
6090 ctl->oh_chem[3] = -0.2;
6091 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
6092 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
6093 }
6094
6095 /* Molar mass... */
6096 char defstr[LEN];
6097 sprintf(defstr, "%g", ctl->molmass);
6098 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
6099
6100 /* OH chemistry... */
6101 sprintf(defstr, "%d", ctl->oh_chem_reaction);
6102 ctl->oh_chem_reaction =
6103 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
6104 NULL);
6105 for (int ip = 0; ip < 4; ip++) {
6106 sprintf(defstr, "%g", ctl->oh_chem[ip]);
6107 ctl->oh_chem[ip] =
6108 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
6109 }
6110 ctl->oh_chem_beta =
6111 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
6112
6113 /* H2O2 chemistry... */
6114 ctl->h2o2_chem_reaction =
6115 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
6116
6117 /* KPP chemistry... */
6118 ctl->kpp_chem =
6119 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
6120 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
6121
6122 /* First order tracer chemistry... */
6123 ctl->tracer_chem =
6124 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
6125
6126 /* Wet deposition... */
6127 for (int ip = 0; ip < 2; ip++) {
6128 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
6129 ctl->wet_depo_ic_h[ip] =
6130 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
6131 }
6132 for (int ip = 0; ip < 1; ip++) {
6133 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
6134 ctl->wet_depo_bc_h[ip] =
6135 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
6136 }
6137 ctl->wet_depo_so2_ph =
6138 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
6139 ctl->wet_depo_ic_a =
6140 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
6141 ctl->wet_depo_ic_b =
6142 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
6143 ctl->wet_depo_bc_a =
6144 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
6145 ctl->wet_depo_bc_b =
6146 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
6147 ctl->wet_depo_pre[0] =
6148 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
6149 ctl->wet_depo_pre[1] =
6150 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
6152 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
6154 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
6155
6156 /* Dry deposition... */
6157 ctl->dry_depo_vdep =
6158 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
6159 ctl->dry_depo_dp =
6160 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
6161
6162 /* Climatological data... */
6163 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
6164 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
6165 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
6166 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
6167 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
6168 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
6169 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
6170 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
6171 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
6172 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
6173 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
6174 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
6175 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
6176 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
6177 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
6178 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
6179 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
6180 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
6181 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
6182 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
6183 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
6184 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
6185
6186 /* Mixing... */
6187 ctl->mixing_dt =
6188 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
6189 ctl->mixing_trop =
6190 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
6191 ctl->mixing_strat =
6192 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
6193 ctl->mixing_z0 =
6194 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
6195 ctl->mixing_z1 =
6196 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
6197 ctl->mixing_nz =
6198 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
6199 ctl->mixing_lon0 =
6200 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
6201 ctl->mixing_lon1 =
6202 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
6203 ctl->mixing_nx =
6204 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
6205 ctl->mixing_lat0 =
6206 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
6207 ctl->mixing_lat1 =
6208 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
6209 ctl->mixing_ny =
6210 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
6211
6212 /* Chemistry grid... */
6213 ctl->chemgrid_z0 =
6214 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
6215 ctl->chemgrid_z1 =
6216 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
6217 ctl->chemgrid_nz =
6218 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
6219 ctl->chemgrid_lon0 =
6220 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
6221 ctl->chemgrid_lon1 =
6222 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
6223 ctl->chemgrid_nx =
6224 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
6225 ctl->chemgrid_lat0 =
6226 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
6227 ctl->chemgrid_lat1 =
6228 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
6229 ctl->chemgrid_ny =
6230 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
6231
6232 /* Exponential decay... */
6233 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
6234 ctl->tdec_strat =
6235 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
6236
6237 /* PSC analysis... */
6238 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
6239 ctl->psc_hno3 =
6240 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
6241
6242 /* Output of atmospheric data... */
6243 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
6244 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
6245 ctl->atm_dt_out =
6246 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
6247 ctl->atm_filter =
6248 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
6249 ctl->atm_stride =
6250 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
6251 ctl->atm_type =
6252 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
6253 ctl->atm_type_out =
6254 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
6255 if (ctl->atm_type_out == -1)
6256 ctl->atm_type_out = ctl->atm_type;
6257 ctl->atm_nc_level =
6258 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
6259 for (int iq = 0; iq < ctl->nq; iq++)
6260 ctl->atm_nc_quant[iq] =
6261 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
6262 ctl->obs_type =
6263 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
6264
6265 /* Output of CSI data... */
6266 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
6267 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
6268 ctl->csi_dt_out =
6269 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
6270 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
6271 ctl->csi_obsmin =
6272 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
6273 ctl->csi_modmin =
6274 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
6275 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
6276 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
6277 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
6278 ctl->csi_lon0 =
6279 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
6280 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
6281 ctl->csi_nx =
6282 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
6283 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
6284 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
6285 ctl->csi_ny =
6286 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
6287
6288 /* Output of ensemble data... */
6289 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
6290 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
6291 ctl->ens_dt_out =
6292 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
6293
6294 /* Output of grid data... */
6295 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
6296 ctl->grid_basename);
6297 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
6298 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
6299 ctl->grid_dt_out =
6300 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
6301 ctl->grid_sparse =
6302 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
6303 ctl->grid_nc_level =
6304 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
6305 for (int iq = 0; iq < ctl->nq; iq++)
6306 ctl->grid_nc_quant[iq] =
6307 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
6308 ctl->grid_stddev =
6309 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
6310 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
6311 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
6312 ctl->grid_nz =
6313 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
6314 ctl->grid_lon0 =
6315 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
6316 ctl->grid_lon1 =
6317 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
6318 ctl->grid_nx =
6319 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
6320 ctl->grid_lat0 =
6321 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
6322 ctl->grid_lat1 =
6323 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
6324 ctl->grid_ny =
6325 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
6326 ctl->grid_type =
6327 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
6328
6329 /* Output of profile data... */
6330 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
6331 ctl->prof_basename);
6332 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
6333 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
6334 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
6335 ctl->prof_nz =
6336 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
6337 ctl->prof_lon0 =
6338 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
6339 ctl->prof_lon1 =
6340 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
6341 ctl->prof_nx =
6342 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
6343 ctl->prof_lat0 =
6344 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
6345 ctl->prof_lat1 =
6346 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
6347 ctl->prof_ny =
6348 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
6349
6350 /* Output of sample data... */
6351 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
6352 ctl->sample_basename);
6353 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
6354 ctl->sample_kernel);
6355 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
6356 ctl->sample_obsfile);
6357 ctl->sample_dx =
6358 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
6359 ctl->sample_dz =
6360 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
6361
6362 /* Output of station data... */
6363 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
6364 ctl->stat_basename);
6365 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
6366 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
6367 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
6368 ctl->stat_t0 =
6369 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
6370 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
6371
6372 /* Output of VTK data... */
6373 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
6374 ctl->vtk_dt_out =
6375 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
6376 ctl->vtk_stride =
6377 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
6378 ctl->vtk_scale =
6379 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
6380 ctl->vtk_offset =
6381 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
6382 ctl->vtk_sphere =
6383 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
6384
6385 /* Domain decomposition... */
6386 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
6388 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
6389 (ctl->dd == 1) ? "2" : "1", NULL);
6390 ctl->dd_subdomains_zonal =
6391 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
6392 (ctl->dd == 1) ? "2" : "1", NULL);
6394 ctl->dd = 1;
6395 else if (ctl->dd == 1)
6396 ERRMSG("Please provide zonal and meridional subdomain numbers!")
6397 ctl->dd_nbr_neighbours =
6398 (int) scan_ctl(filename, argc, argv, "DD_NBR_NEIGHBOURS", -1, "8",
6399 NULL);
6400 ctl->dd_halos_size =
6401 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
6402}
6403
6404/*****************************************************************************/
6405
6407 const char *filename,
6408 const ctl_t *ctl,
6409 const clim_t *clim,
6410 met_t *met,
6411 dd_t *dd) {
6412
6413 /* Write info... */
6414 LOG(1, "Read meteo data: %s", filename);
6415
6416 /* Set rank... */
6417 int rank = 0;
6418#ifdef MPI
6419 if (ctl->met_mpi_share)
6420 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
6421#endif
6422
6423 /* Check rank... */
6424 if (!ctl->met_mpi_share || rank == 0) {
6425
6426 /* Read netCDF data... */
6427 if (ctl->met_type == 0) {
6428 if (read_met_nc(filename, ctl, met, dd) != 1)
6429 return 0;
6430 }
6431
6432 /* Read binary data... */
6433 else if ((ctl->met_type >= 1 && ctl->met_type <= 5) || ctl->met_type == 7) {
6434 if (read_met_bin(filename, ctl, met) != 1)
6435 return 0;
6436 }
6437
6438#ifdef ECCODES
6439 /* Read grib data... */
6440 else if (ctl->met_type == 6) {
6441 if (read_met_grib(filename, ctl, met) != 1)
6442 return 0;
6443 }
6444#endif
6445
6446 /* Not implemented... */
6447 else
6448 ERRMSG("MET_TYPE not implemented!");
6449
6450 /* Preprocessing for netCDF and grib files... */
6451 if (ctl->met_type == 0 || ctl->met_type == 6) {
6452
6453 /* Extrapolate data for lower boundary... */
6455
6456 /* Fix polar winds... */
6458
6459 /* Create periodic boundary conditions... */
6460#ifndef DD
6461 read_met_periodic(met);
6462#endif
6463
6464 /* Downsampling... */
6465 read_met_sample(ctl, met);
6466
6467 /* Calculate geopotential heights... */
6468 read_met_geopot(ctl, met);
6469
6470 /* Calculate potential vorticity... */
6471 read_met_pv(met);
6472
6473 /* Calculate boundary layer data... */
6474 read_met_pbl(ctl, met);
6475
6476 /* Calculate tropopause data... */
6477 read_met_tropo(ctl, clim, met);
6478
6479 /* Calculate cloud properties... */
6480 read_met_cloud(met);
6481
6482 /* Calculate convective available potential energy... */
6483 read_met_cape(ctl, clim, met);
6484
6485 /* Calculate total column ozone... */
6486 read_met_ozone(met);
6487
6488 /* Detrending... */
6489 read_met_detrend(ctl, met);
6490
6491 /* Check meteo data and smooth zeta profiles ... */
6492 read_met_monotonize(ctl, met);
6493 }
6494 }
6495
6496 /* Broadcast data via MPI... */
6497#ifdef MPI
6498 if (ctl->met_mpi_share) {
6499
6500 /* Set timer... */
6501 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
6502 LOG(2, "Broadcast data on rank %d...", rank);
6503
6504 /* Broadcast... */
6505 broadcast_large_data(met, sizeof(met_t));
6506 }
6507#endif
6508
6509 /* Return success... */
6510 return 1;
6511}
6512
6513/*****************************************************************************/
6514
6516 ctl_t *ctl,
6517 cache_t *cache,
6518 clim_t *clim,
6519 met_t **met0,
6520 met_t **met1,
6521 atm_t *atm,
6522 double t,
6523 dd_t *dd) {
6524
6525 /* Initialize modules... */
6526 if (t == ctl->t_start) {
6527
6528 /* Initialize isosurface data... */
6529 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6530 module_isosurf_init(ctl, cache, *met0, *met1, atm);
6531
6532 /* Initialize advection... */
6533 module_advect_init(ctl, cache, *met0, *met1, atm);
6534
6535 /* Initialize chemistry... */
6536 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
6537 }
6538
6539 /* Set time steps of air parcels... */
6540 module_timesteps(ctl, cache, *met0, atm, t);
6541
6542 /* Sort particles... */
6543 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
6544 module_sort(ctl, *met0, atm);
6545
6546
6547 /* Check positions (initial)... */
6548 module_position(cache, *met0, *met1, atm);
6549
6550 /* Advection... */
6551 if (ctl->advect > 0)
6552 module_advect(ctl, cache, *met0, *met1, atm);
6553
6554 /* Turbulent diffusion... */
6555 if (ctl->diffusion == 1
6556 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
6557 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
6558 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
6559 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
6560
6561 /* Mesoscale diffusion... */
6562 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
6563 module_diff_meso(ctl, cache, *met0, *met1, atm);
6564
6565 /* Diffusion... */
6566 if (ctl->diffusion == 2)
6567 module_diff_pbl(ctl, cache, *met0, *met1, atm);
6568
6569 /* Convection... */
6570 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
6571 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
6572 module_convection(ctl, cache, *met0, *met1, atm);
6573
6574 /* Sedimentation... */
6575 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
6576 module_sedi(ctl, cache, *met0, *met1, atm);
6577
6578 /* Isosurface... */
6579 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6580 module_isosurf(ctl, cache, *met0, *met1, atm);
6581
6582 /* Check positions (final)... */
6583 module_position(cache, *met0, *met1, atm);
6584
6585 /* Interpolate meteo data... */
6586 if (ctl->met_dt_out > 0
6587 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
6588 module_meteo(ctl, cache, clim, *met0, *met1, atm);
6589
6590 /* Check boundary conditions (initial)... */
6591 if ((ctl->bound_lat0 < ctl->bound_lat1)
6592 && (ctl->bound_p0 > ctl->bound_p1))
6593 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6594
6595 /* Initialize quantity of total loss rate... */
6596 if (ctl->qnt_loss_rate >= 0) {
6597 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
6598 atm->q[ctl->qnt_loss_rate][ip] = 0;
6599 }
6600 }
6601
6602 /* Decay of particle mass... */
6603 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
6604 module_decay(ctl, cache, clim, atm);
6605
6606 /* Interparcel mixing... */
6607 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
6608 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
6609 module_mixing(ctl, clim, atm, t);
6610
6611 /* Calculate the tracer vmr in the chemistry grid... */
6612 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
6613 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
6614 module_chem_grid(ctl, *met0, *met1, atm, t);
6615
6616 /* OH chemistry... */
6617 if (ctl->oh_chem_reaction != 0)
6618 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
6619
6620 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
6621 if (ctl->h2o2_chem_reaction != 0)
6622 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
6623
6624 /* First-order tracer chemistry... */
6625 if (ctl->tracer_chem)
6626 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
6627
6628 /* Domain decomposition... */
6629 if (dd->init) {
6630#ifdef DD
6631 module_dd(ctl, atm, cache, dd, met0);
6632#else
6633 ERRMSG("DD initialized, but model is compiled without DD.")
6634#endif
6635 }
6636
6637 /* KPP chemistry... */
6638 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
6639#ifdef KPP
6640 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
6641#else
6642 ERRMSG("Code was compiled without KPP!");
6643#endif
6644 }
6645
6646 /* Wet deposition... */
6647 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
6648 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
6649 module_wet_depo(ctl, cache, *met0, *met1, atm);
6650
6651 /* Dry deposition... */
6652 if (ctl->dry_depo_vdep > 0)
6653 module_dry_depo(ctl, cache, *met0, *met1, atm);
6654
6655 /* Check boundary conditions (final)... */
6656 if ((ctl->bound_lat0 < ctl->bound_lat1)
6657 && (ctl->bound_p0 > ctl->bound_p1))
6658 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6659}
6660
6661/*****************************************************************************/
6662
6664 const ctl_t *ctl,
6665 const cache_t *cache,
6666 const clim_t *clim,
6667 met_t **met0,
6668 met_t **met1,
6669 const atm_t *atm) {
6670
6671 /* Update GPU... */
6672 if (ctl != NULL) {
6673#ifdef _OPENACC
6674 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6675#pragma acc update device(ctl[:1])
6676#endif
6677 }
6678
6679 if (cache != NULL) {
6680#ifdef _OPENACC
6681 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6682#pragma acc update device(cache[:1])
6683#endif
6684 }
6685
6686 if (clim != NULL) {
6687#ifdef _OPENACC
6688 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6689#pragma acc update device(clim[:1])
6690#endif
6691 }
6692
6693 if (met0 != NULL) {
6694#ifdef _OPENACC
6695 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6696 met_t *met0up = *met0;
6697#pragma acc update device(met0up[:1])
6698#endif
6699 }
6700
6701 if (met1 != NULL) {
6702#ifdef _OPENACC
6703 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6704 met_t *met1up = *met1;
6705#pragma acc update device(met1up[:1])
6706#endif
6707 }
6708
6709 if (atm != NULL) {
6710#ifdef _OPENACC
6711 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6712#pragma acc update device(atm[:1])
6713#endif
6714 }
6715}
6716
6717/*****************************************************************************/
6718
6720 const ctl_t *ctl,
6721 const cache_t *cache,
6722 const clim_t *clim,
6723 met_t **met0,
6724 met_t **met1,
6725 const atm_t *atm) {
6726
6727 /* Update GPU... */
6728 if (ctl != NULL) {
6729#ifdef _OPENACC
6730 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6731#pragma acc update host(ctl[:1])
6732#endif
6733 }
6734
6735 if (cache != NULL) {
6736#ifdef _OPENACC
6737 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6738#pragma acc update host(cache[:1])
6739#endif
6740 }
6741
6742 if (clim != NULL) {
6743#ifdef _OPENACC
6744 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6745#pragma acc update host(clim[:1])
6746#endif
6747 }
6748
6749 if (met0 != NULL) {
6750#ifdef _OPENACC
6751 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6752 met_t *met0up = *met0;
6753#pragma acc update host(met0up[:1])
6754#endif
6755 }
6756
6757 if (met1 != NULL) {
6758#ifdef _OPENACC
6759 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
6760 met_t *met1up = *met1;
6761#pragma acc update host(met1up[:1])
6762#endif
6763 }
6764
6765 if (atm != NULL) {
6766#ifdef _OPENACC
6767 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
6768#pragma acc update host(atm[:1])
6769#endif
6770 }
6771}
6772
6773/*****************************************************************************/
6774
6776 const char *filename,
6777 const ctl_t *ctl,
6778 const atm_t *atm,
6779 const double t) {
6780
6781 /* Set timer... */
6782 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
6783
6784 /* Write info... */
6785 LOG(1, "Write atmospheric data: %s", filename);
6786
6787 /* Write ASCII data... */
6788 if (ctl->atm_type_out == 0)
6789 write_atm_asc(filename, ctl, atm, t);
6790
6791 /* Write binary data... */
6792 else if (ctl->atm_type_out == 1)
6793 write_atm_bin(filename, ctl, atm);
6794
6795 /* Write netCDF data... */
6796 else if (ctl->atm_type_out == 2)
6797 write_atm_nc(filename, ctl, atm);
6798
6799 /* Write CLaMS trajectory data... */
6800 else if (ctl->atm_type_out == 3)
6801 write_atm_clams_traj(filename, ctl, atm, t);
6802
6803 /* Write CLaMS pos data... */
6804 else if (ctl->atm_type_out == 4)
6805 write_atm_clams(filename, ctl, atm);
6806
6807 /* Error... */
6808 else
6809 ERRMSG("Atmospheric data type not supported!");
6810
6811 /* Write info... */
6812 double mini, maxi;
6813 LOG(2, "Number of particles: %d", atm->np);
6814 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6815 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6816 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6817 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6818 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6819 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6820 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
6821 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6822 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
6823 for (int iq = 0; iq < ctl->nq; iq++) {
6824 char msg[5 * LEN];
6825 sprintf(msg, "Quantity %s range: %s ... %s %s",
6826 ctl->qnt_name[iq], ctl->qnt_format[iq],
6827 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6828 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6829 LOG(2, msg, mini, maxi);
6830 }
6831}
6832
6833/*****************************************************************************/
6834
6836 const char *filename,
6837 const ctl_t *ctl,
6838 met_t *met) {
6839
6840 /* Set timer... */
6841 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
6842
6843 /* Write info... */
6844 LOG(1, "Write meteo data: %s", filename);
6845
6846 /* Check compression flags... */
6847#ifndef ZFP
6848 if (ctl->met_type == 3)
6849 ERRMSG("MPTRAC was compiled without ZFP compression!");
6850#endif
6851#ifndef ZSTD
6852 if (ctl->met_type == 4)
6853 ERRMSG("MPTRAC was compiled without ZSTD compression!");
6854#endif
6855#ifndef CMS
6856 if (ctl->met_type == 5)
6857 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6858#endif
6859#ifndef SZ3
6860 if (ctl->met_type == 7)
6861 ERRMSG("MPTRAC was compiled without SZ3 compression!");
6862#endif
6863
6864 /* Write netCDF data... */
6865 if (ctl->met_type == 0)
6866 write_met_nc(filename, ctl, met);
6867
6868 /* Write binary data... */
6869 else if (ctl->met_type >= 1 && ctl->met_type <= 7)
6870 write_met_bin(filename, ctl, met);
6871
6872 /* Not implemented... */
6873 else
6874 ERRMSG("MET_TYPE not implemented!");
6875}
6876
6877/*****************************************************************************/
6878
6880 const char *dirname,
6881 const ctl_t *ctl,
6882 met_t *met0,
6883 met_t *met1,
6884 atm_t *atm,
6885 const double t) {
6886
6887 char ext[10], filename[2 * LEN];
6888
6889 double r;
6890
6891 int year, mon, day, hour, min, sec;
6892
6893 /* Get time... */
6894 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
6895
6896 /* Update host... */
6897 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
6898 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
6899 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
6900 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
6901 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
6902 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
6903 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
6904
6905 /* Write atmospheric data... */
6906 if (ctl->atm_basename[0] != '-' &&
6907 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
6908 if (ctl->atm_type_out == 0)
6909 sprintf(ext, "tab");
6910 else if (ctl->atm_type_out == 1)
6911 sprintf(ext, "bin");
6912 else if (ctl->atm_type_out == 2)
6913 sprintf(ext, "nc");
6914 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6915 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
6916 mptrac_write_atm(filename, ctl, atm, t);
6917 }
6918
6919 /* Write gridded data... */
6920 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
6921 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6922 dirname, ctl->grid_basename, year, mon, day, hour, min,
6923 ctl->grid_type == 0 ? "tab" : "nc");
6924 write_grid(filename, ctl, met0, met1, atm, t);
6925 }
6926
6927 /* Write CSI data... */
6928 if (ctl->csi_basename[0] != '-') {
6929 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
6930 write_csi(filename, ctl, atm, t);
6931 }
6932
6933 /* Write ensemble data... */
6934 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
6935 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
6936 dirname, ctl->ens_basename, year, mon, day, hour, min);
6937 write_ens(filename, ctl, atm, t);
6938 }
6939
6940 /* Write profile data... */
6941 if (ctl->prof_basename[0] != '-') {
6942 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
6943 write_prof(filename, ctl, met0, met1, atm, t);
6944 }
6945
6946 /* Write sample data... */
6947 if (ctl->sample_basename[0] != '-') {
6948 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
6949 write_sample(filename, ctl, met0, met1, atm, t);
6950 }
6951
6952 /* Write station data... */
6953 if (ctl->stat_basename[0] != '-') {
6954 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
6955 write_station(filename, ctl, atm, t);
6956 }
6957
6958 /* Write VTK data... */
6959 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
6960 static int nvtk;
6961 if (t == ctl->t_start)
6962 nvtk = 0;
6963 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
6964 write_vtk(filename, ctl, atm, t);
6965 }
6966}
6967
6968/*****************************************************************************/
6969
6971 const double p,
6972 const double h2o,
6973 const double hno3) {
6974
6975 /* Check water vapor volume mixing ratio... */
6976 const double h2o_help = MAX(h2o, 0.1e-6);
6977
6978 /* Calculate T_NAT... */
6979 const double p_hno3 = hno3 * p / 1.333224;
6980 const double p_h2o = h2o_help * p / 1.333224;
6981 const double a = 0.009179 - 0.00088 * log10(p_h2o);
6982 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
6983 const double c = -11397.0 / a;
6984 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
6985 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
6986 if (x2 > 0)
6987 tnat = x2;
6988
6989 return tnat;
6990}
6991
6992/*****************************************************************************/
6993
6995 const ctl_t *ctl,
6996 const atm_t *atm,
6997 const int ip,
6998 const double pbl,
6999 const double ps) {
7000
7001 /* Get pressure range... */
7002 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
7003 const double p0 = pbl;
7004
7005 /* Get weighting factor... */
7006 if (atm->p[ip] > p0)
7007 return 1;
7008 else if (atm->p[ip] < p1)
7009 return 0;
7010 else
7011 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
7012}
7013
7014/*****************************************************************************/
7015
7017 const char *filename,
7018 const ctl_t *ctl,
7019 atm_t *atm) {
7020
7021 /* Open file... */
7022 FILE *in;
7023 if (!(in = fopen(filename, "r"))) {
7024 WARN("Cannot open file!");
7025 return 0;
7026 }
7027
7028 /* Read line... */
7029 char line[LEN];
7030 while (fgets(line, LEN, in)) {
7031
7032 /* Read data... */
7033 char *tok;
7034 TOK(line, tok, "%lg", atm->time[atm->np]);
7035 TOK(NULL, tok, "%lg", atm->p[atm->np]);
7036 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
7037 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
7038 for (int iq = 0; iq < ctl->nq; iq++)
7039 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
7040
7041 /* Convert altitude to pressure... */
7042 atm->p[atm->np] = P(atm->p[atm->np]);
7043
7044 /* Increment data point counter... */
7045 if ((++atm->np) > NP)
7046 ERRMSG("Too many data points!");
7047 }
7048
7049 /* Close file... */
7050 fclose(in);
7051
7052 /* Return success... */
7053 return 1;
7054}
7055
7056/*****************************************************************************/
7057
7059 const char *filename,
7060 const ctl_t *ctl,
7061 atm_t *atm) {
7062
7063 /* Open file... */
7064 FILE *in;
7065 if (!(in = fopen(filename, "r")))
7066 return 0;
7067
7068 /* Check version of binary data... */
7069 int version;
7070 FREAD(&version, int,
7071 1,
7072 in);
7073 if (version != 100)
7074 ERRMSG("Wrong version of binary data!");
7075
7076 /* Read data... */
7077 FREAD(&atm->np, int,
7078 1,
7079 in);
7080 FREAD(atm->time, double,
7081 (size_t) atm->np,
7082 in);
7083 FREAD(atm->p, double,
7084 (size_t) atm->np,
7085 in);
7086 FREAD(atm->lon, double,
7087 (size_t) atm->np,
7088 in);
7089 FREAD(atm->lat, double,
7090 (size_t) atm->np,
7091 in);
7092 for (int iq = 0; iq < ctl->nq; iq++)
7093 FREAD(atm->q[iq], double,
7094 (size_t) atm->np,
7095 in);
7096
7097 /* Read final flag... */
7098 int final;
7099 FREAD(&final, int,
7100 1,
7101 in);
7102 if (final != 999)
7103 ERRMSG("Error while reading binary data!");
7104
7105 /* Close file... */
7106 fclose(in);
7107
7108 /* Return success... */
7109 return 1;
7110}
7111
7112/*****************************************************************************/
7113
7115 const char *filename,
7116 const ctl_t *ctl,
7117 atm_t *atm) {
7118
7119 int ncid, varid;
7120
7121 /* Open file... */
7122 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7123 return 0;
7124
7125 /* Get dimensions... */
7126 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
7127
7128 /* Get time... */
7129 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
7130 NC(nc_get_var_double(ncid, varid, atm->time));
7131 } else {
7132 WARN("TIME_INIT not found use time instead!");
7133 double time_init;
7134 NC_GET_DOUBLE("time", &time_init, 1);
7135 for (int ip = 0; ip < atm->np; ip++) {
7136 atm->time[ip] = time_init;
7137 }
7138 }
7139
7140 /* Read zeta coordinate, pressure is optional... */
7141 if (ctl->advect_vert_coord == 1) {
7142 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
7143 NC_GET_DOUBLE("PRESS", atm->p, 0);
7144 }
7145
7146 /* Read pressure, zeta coordinate is optional... */
7147 else {
7148 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
7149 NC(nc_get_var_double(ncid, varid, atm->p));
7150 } else {
7151 WARN("PRESS_INIT not found use PRESS instead!");
7152 nc_inq_varid(ncid, "PRESS", &varid);
7153 NC(nc_get_var_double(ncid, varid, atm->p));
7154 }
7155 }
7156
7157 /* Read further quantities if requested... */
7158 for (int iq = 0; iq < ctl->nq; iq++)
7159 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7160
7161 /* Read longitude and latitude... */
7162 NC_GET_DOUBLE("LON", atm->lon, 1);
7163 NC_GET_DOUBLE("LAT", atm->lat, 1);
7164
7165 /* Close file... */
7166 NC(nc_close(ncid));
7167
7168 /* Return success... */
7169 return 1;
7170}
7171
7172/*****************************************************************************/
7173
7175 const char *filename,
7176 const ctl_t *ctl,
7177 atm_t *atm) {
7178
7179 int ncid, varid;
7180
7181 /* Open file... */
7182 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7183 return 0;
7184
7185 /* Get dimensions... */
7186 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
7187
7188 /* Read geolocations... */
7189 NC_GET_DOUBLE("time", atm->time, 1);
7190 NC_GET_DOUBLE("press", atm->p, 1);
7191 NC_GET_DOUBLE("lon", atm->lon, 1);
7192 NC_GET_DOUBLE("lat", atm->lat, 1);
7193
7194 /* Read variables... */
7195 for (int iq = 0; iq < ctl->nq; iq++)
7196 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7197
7198 /* Close file... */
7199 NC(nc_close(ncid));
7200
7201 /* Return success... */
7202 return 1;
7203}
7204
7205/*****************************************************************************/
7206
7208 const char *filename,
7209 clim_photo_t *photo) {
7210
7211 int ncid, varid;
7212
7213 /* Write info... */
7214 LOG(1, "Read photolysis rates: %s", filename);
7215
7216 /* Open netCDF file... */
7217 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7218 WARN("Photolysis rate data are missing!");
7219 return;
7220 }
7221
7222 /* Read pressure data... */
7223 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
7224 NC_GET_DOUBLE("press", photo->p, 1);
7225 if (photo->p[0] < photo->p[1])
7226 ERRMSG("Pressure data are not descending!");
7227
7228 /* Read total column ozone data... */
7229 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
7230 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
7231 if (photo->o3c[0] > photo->o3c[1])
7232 ERRMSG("Total column ozone data are not ascending!");
7233
7234 /* Read solar zenith angle data... */
7235 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
7236 NC_GET_DOUBLE("sza", photo->sza, 1);
7237 if (photo->sza[0] > photo->sza[1])
7238 ERRMSG("Solar zenith angle data are not ascending!");
7239
7240 /* Read data... */
7241 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
7242 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
7243 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
7244 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
7245 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
7246 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
7247 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
7248 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
7249 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
7250
7251 /* Close netCDF file... */
7252 NC(nc_close(ncid));
7253
7254 /* Write info... */
7255 LOG(2, "Number of pressure levels: %d", photo->np);
7256 LOG(2, "Altitude levels: %g, %g ... %g km",
7257 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
7258 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7259 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
7260 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
7261 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
7262 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
7263 RAD2DEG(photo->sza[photo->nsza - 1]));
7264 LOG(2, "Number of total column ozone values: %d", photo->no3c);
7265 LOG(2, "Total column ozone: %g, %g ... %g DU",
7266 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
7267 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
7268 photo->n2o[0][0][0], photo->n2o[1][0][0],
7269 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7270 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
7271 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
7272 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7273 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
7274 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
7275 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7276 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
7277 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
7278 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7279 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
7280 photo->o2[0][0][0], photo->o2[1][0][0],
7281 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7282 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
7283 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
7284 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7285 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
7286 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
7287 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7288 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
7289 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
7290 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7291 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
7292 photo->h2o[0][0][0], photo->h2o[1][0][0],
7293 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7294}
7295
7296/*****************************************************************************/
7297
7299 const int ncid,
7300 const char *varname,
7301 const clim_photo_t *photo,
7302 double var[CP][CSZA][CO3]) {
7303
7304 /* Allocate... */
7305 double *help;
7306 ALLOC(help, double,
7307 photo->np * photo->nsza * photo->no3c);
7308
7309 /* Read varible... */
7310 int varid;
7311 NC_GET_DOUBLE(varname, help, 1);
7312
7313 /* Copy data... */
7314 for (int ip = 0; ip < photo->np; ip++)
7315 for (int is = 0; is < photo->nsza; is++)
7316 for (int io = 0; io < photo->no3c; io++)
7317 var[ip][is][io] =
7318 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
7319
7320 /* Free... */
7321 free(help);
7322}
7323
7324/*****************************************************************************/
7325
7327 const char *filename,
7328 clim_ts_t *ts) {
7329
7330 /* Write info... */
7331 LOG(1, "Read climatological time series: %s", filename);
7332
7333 /* Open file... */
7334 FILE *in;
7335 if (!(in = fopen(filename, "r"))) {
7336 WARN("Cannot open file!");
7337 return 0;
7338 }
7339
7340 /* Read data... */
7341 char line[LEN];
7342 int nh = 0;
7343 while (fgets(line, LEN, in))
7344 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
7345
7346 /* Convert years to seconds... */
7347 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
7348
7349 /* Check data... */
7350 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
7351 ERRMSG("Time series must be ascending!");
7352
7353 /* Count time steps... */
7354 if ((++nh) >= CTS)
7355 ERRMSG("Too many data points!");
7356 }
7357
7358 /* Close file... */
7359 fclose(in);
7360
7361 /* Check number of data points... */
7362 ts->ntime = nh;
7363 if (nh < 2)
7364 ERRMSG("Not enough data points!");
7365
7366 /* Write info... */
7367 LOG(2, "Number of time steps: %d", ts->ntime);
7368 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
7369 ts->time[nh - 1]);
7370 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
7371 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
7372 (size_t) nh));
7373
7374 /* Exit success... */
7375 return 1;
7376}
7377
7378/*****************************************************************************/
7379
7381 const char *filename,
7382 const char *varname,
7383 clim_zm_t *zm) {
7384
7385 int ncid, varid, it, iy, iz, iz2, nt;
7386
7387 double *help, varmin = 1e99, varmax = -1e99;
7388
7389 /* Write info... */
7390 LOG(1, "Read %s data: %s", varname, filename);
7391
7392 /* Open netCDF file... */
7393 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7394 WARN("%s climatology data are missing!", varname);
7395 return;
7396 }
7397
7398 /* Read pressure data... */
7399 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
7400 NC_GET_DOUBLE("press", zm->p, 1);
7401 if (zm->p[0] < zm->p[1])
7402 ERRMSG("Pressure data are not descending!");
7403
7404 /* Read latitudes... */
7405 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
7406 NC_GET_DOUBLE("lat", zm->lat, 1);
7407 if (zm->lat[0] > zm->lat[1])
7408 ERRMSG("Latitude data are not ascending!");
7409
7410 /* Set time data (for monthly means)... */
7411 zm->ntime = 12;
7412 zm->time[0] = 1209600.00;
7413 zm->time[1] = 3888000.00;
7414 zm->time[2] = 6393600.00;
7415 zm->time[3] = 9072000.00;
7416 zm->time[4] = 11664000.00;
7417 zm->time[5] = 14342400.00;
7418 zm->time[6] = 16934400.00;
7419 zm->time[7] = 19612800.00;
7420 zm->time[8] = 22291200.00;
7421 zm->time[9] = 24883200.00;
7422 zm->time[10] = 27561600.00;
7423 zm->time[11] = 30153600.00;
7424
7425 /* Check number of timesteps... */
7426 NC_INQ_DIM("time", &nt, 12, 12, 1);
7427
7428 /* Read data... */
7429 ALLOC(help, double,
7430 zm->nlat * zm->np * zm->ntime);
7431 NC_GET_DOUBLE(varname, help, 1);
7432 for (it = 0; it < zm->ntime; it++)
7433 for (iz = 0; iz < zm->np; iz++)
7434 for (iy = 0; iy < zm->nlat; iy++)
7435 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
7436 free(help);
7437
7438 /* Fix data gaps... */
7439 for (it = 0; it < zm->ntime; it++)
7440 for (iy = 0; iy < zm->nlat; iy++)
7441 for (iz = 0; iz < zm->np; iz++) {
7442 if (zm->vmr[it][iz][iy] < 0) {
7443 for (iz2 = 0; iz2 < zm->np; iz2++)
7444 if (zm->vmr[it][iz2][iy] >= 0) {
7445 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7446 break;
7447 }
7448 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
7449 if (zm->vmr[it][iz2][iy] >= 0) {
7450 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7451 break;
7452 }
7453 }
7454 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
7455 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
7456 }
7457
7458 /* Close netCDF file... */
7459 NC(nc_close(ncid));
7460
7461 /* Write info... */
7462 LOG(2, "Number of time steps: %d", zm->ntime);
7463 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
7464 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
7465 LOG(2, "Number of pressure levels: %d", zm->np);
7466 LOG(2, "Altitude levels: %g, %g ... %g km",
7467 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
7468 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
7469 zm->p[1], zm->p[zm->np - 1]);
7470 LOG(2, "Number of latitudes: %d", zm->nlat);
7471 LOG(2, "Latitudes: %g, %g ... %g deg",
7472 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
7473 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
7474 varmax);
7475}
7476
7477/*****************************************************************************/
7478
7480 const char *filename,
7481 double kz[EP],
7482 double kw[EP],
7483 int *nk) {
7484
7485 /* Write info... */
7486 LOG(1, "Read kernel function: %s", filename);
7487
7488 /* Open file... */
7489 FILE *in;
7490 if (!(in = fopen(filename, "r")))
7491 ERRMSG("Cannot open file!");
7492
7493 /* Read data... */
7494 char line[LEN];
7495 int n = 0;
7496 while (fgets(line, LEN, in))
7497 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
7498 if (n > 0 && kz[n] < kz[n - 1])
7499 ERRMSG("Height levels must be ascending!");
7500 if ((++n) >= EP)
7501 ERRMSG("Too many height levels!");
7502 }
7503
7504 /* Close file... */
7505 fclose(in);
7506
7507 /* Check number of data points... */
7508 *nk = n;
7509 if (n < 2)
7510 ERRMSG("Not enough height levels!");
7511
7512 /* Normalize kernel function... */
7513 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
7514 for (int iz = 0; iz < n; iz++)
7515 kw[iz] /= kmax;
7516}
7517
7518/*****************************************************************************/
7519
7521 const char *filename,
7522 const ctl_t *ctl,
7523 met_t *met) {
7524
7525 FILE *in;
7526
7527 double r;
7528
7529 int year, mon, day, hour, min, sec;
7530
7531 /* Set timer... */
7532 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
7533
7534 /* Open file... */
7535 if (!(in = fopen(filename, "r"))) {
7536 WARN("Cannot open file!");
7537 return 0;
7538 }
7539
7540 /* Check type of binary data... */
7541 int met_type;
7542 FREAD(&met_type, int,
7543 1,
7544 in);
7545 if (met_type != ctl->met_type)
7546 ERRMSG("Wrong MET_TYPE of binary data!");
7547
7548 /* Check version of binary data... */
7549 int version;
7550 FREAD(&version, int,
7551 1,
7552 in);
7553 if (version != 103)
7554 ERRMSG("Wrong version of binary data!");
7555
7556 /* Read time... */
7557 FREAD(&met->time, double,
7558 1,
7559 in);
7560 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7561 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7562 met->time, year, mon, day, hour, min);
7563 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7564 || day < 1 || day > 31 || hour < 0 || hour > 23)
7565 ERRMSG("Error while reading time!");
7566
7567 /* Read dimensions... */
7568 FREAD(&met->nx, int,
7569 1,
7570 in);
7571 LOG(2, "Number of longitudes: %d", met->nx);
7572 if (met->nx < 2 || met->nx > EX)
7573 ERRMSG("Number of longitudes out of range!");
7574
7575 FREAD(&met->ny, int,
7576 1,
7577 in);
7578 LOG(2, "Number of latitudes: %d", met->ny);
7579 if (met->ny < 2 || met->ny > EY)
7580 ERRMSG("Number of latitudes out of range!");
7581
7582 FREAD(&met->np, int,
7583 1,
7584 in);
7585 LOG(2, "Number of levels: %d", met->np);
7586 if (met->np < 2 || met->np > EP)
7587 ERRMSG("Number of levels out of range!");
7588
7589 /* Read grid... */
7590 FREAD(met->lon, double,
7591 (size_t) met->nx,
7592 in);
7593 LOG(2, "Longitudes: %g, %g ... %g deg",
7594 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7595
7596 FREAD(met->lat, double,
7597 (size_t) met->ny,
7598 in);
7599 LOG(2, "Latitudes: %g, %g ... %g deg",
7600 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7601
7602 FREAD(met->p, double,
7603 (size_t) met->np,
7604 in);
7605 LOG(2, "Altitude levels: %g, %g ... %g km",
7606 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7607 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7608 met->p[0], met->p[1], met->p[met->np - 1]);
7609
7610 /* Read surface data... */
7611 read_met_bin_2d(in, met, met->ps, "PS");
7612 read_met_bin_2d(in, met, met->ts, "TS");
7613 read_met_bin_2d(in, met, met->zs, "ZS");
7614 read_met_bin_2d(in, met, met->us, "US");
7615 read_met_bin_2d(in, met, met->vs, "VS");
7616 read_met_bin_2d(in, met, met->ess, "ESS");
7617 read_met_bin_2d(in, met, met->nss, "NSS");
7618 read_met_bin_2d(in, met, met->shf, "SHF");
7619 read_met_bin_2d(in, met, met->lsm, "LSM");
7620 read_met_bin_2d(in, met, met->sst, "SST");
7621 read_met_bin_2d(in, met, met->pbl, "PBL");
7622 read_met_bin_2d(in, met, met->pt, "PT");
7623 read_met_bin_2d(in, met, met->tt, "TT");
7624 read_met_bin_2d(in, met, met->zt, "ZT");
7625 read_met_bin_2d(in, met, met->h2ot, "H2OT");
7626 read_met_bin_2d(in, met, met->pct, "PCT");
7627 read_met_bin_2d(in, met, met->pcb, "PCB");
7628 read_met_bin_2d(in, met, met->cl, "CL");
7629 read_met_bin_2d(in, met, met->plcl, "PLCL");
7630 read_met_bin_2d(in, met, met->plfc, "PLFC");
7631 read_met_bin_2d(in, met, met->pel, "PEL");
7632 read_met_bin_2d(in, met, met->cape, "CAPE");
7633 read_met_bin_2d(in, met, met->cin, "CIN");
7634 read_met_bin_2d(in, met, met->o3c, "O3C");
7635
7636 /* Read level data... */
7637 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
7638 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
7639 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
7640 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
7641 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
7642 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
7643 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
7644 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
7645 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
7646 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
7647 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
7648 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
7649 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
7650
7651 /* Read final flag... */
7652 int final;
7653 FREAD(&final, int,
7654 1,
7655 in);
7656 if (final != 999)
7657 ERRMSG("Error while reading binary data!");
7658
7659 /* Close file... */
7660 fclose(in);
7661
7662 /* Return success... */
7663 return 1;
7664}
7665
7666/*****************************************************************************/
7667
7669 FILE *in,
7670 const met_t *met,
7671 float var[EX][EY],
7672 const char *varname) {
7673
7674 float *help;
7675
7676 /* Allocate... */
7677 ALLOC(help, float,
7678 EX * EY);
7679
7680 /* Read uncompressed... */
7681 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
7682 FREAD(help, float,
7683 (size_t) (met->nx * met->ny),
7684 in);
7685
7686 /* Copy data... */
7687 for (int ix = 0; ix < met->nx; ix++)
7688 for (int iy = 0; iy < met->ny; iy++)
7689 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
7690
7691 /* Free... */
7692 free(help);
7693}
7694
7695/*****************************************************************************/
7696
7698 FILE *in,
7699 const ctl_t *ctl,
7700 const met_t *met,
7701 float var[EX][EY][EP],
7702 const char *varname,
7703 const float bound_min,
7704 const float bound_max) {
7705
7706 float *help;
7707
7708 /* Allocate... */
7709 ALLOC(help, float,
7710 EX * EY * EP);
7711
7712 /* Read uncompressed data... */
7713 if (ctl->met_type == 1) {
7714 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
7715 FREAD(help, float,
7716 (size_t) (met->nx * met->ny * met->np),
7717 in);
7718 }
7719
7720 /* Read packed data... */
7721 else if (ctl->met_type == 2)
7722 compress_pck(varname, help, (size_t) (met->ny * met->nx),
7723 (size_t) met->np, 1, in);
7724
7725 /* Read ZFP data... */
7726 else if (ctl->met_type == 3) {
7727#ifdef ZFP
7728 int precision;
7729 FREAD(&precision, int,
7730 1,
7731 in);
7732
7733 double tolerance;
7734 FREAD(&tolerance, double,
7735 1,
7736 in);
7737
7738 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
7739 tolerance, 1, in);
7740#else
7741 ERRMSG("MPTRAC was compiled without ZFP compression!");
7742#endif
7743 }
7744
7745 /* Read zstd data... */
7746 else if (ctl->met_type == 4) {
7747#ifdef ZSTD
7748 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
7749 ctl->met_zstd_level, in);
7750#else
7751 ERRMSG("MPTRAC was compiled without ZSTD compression!");
7752#endif
7753 }
7754
7755 /* Read cmultiscale data... */
7756 else if (ctl->met_type == 5) {
7757#ifdef CMS
7758 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
7759 (size_t) met->np, met->p, 1, in);
7760#else
7761 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
7762#endif
7763 }
7764
7765 /* Read SZ3 data... */
7766 else if (ctl->met_type == 7) {
7767#ifdef SZ3
7768 int precision;
7769 FREAD(&precision, int,
7770 1,
7771 in);
7772
7773 double tolerance;
7774 FREAD(&tolerance, double,
7775 1,
7776 in);
7777
7778 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
7779 tolerance, 1, in);
7780#else
7781 ERRMSG("MPTRAC was compiled without sz3 compression!");
7782#endif
7783 }
7784
7785 /* Copy data... */
7786#pragma omp parallel for default(shared) collapse(2)
7787 for (int ix = 0; ix < met->nx; ix++)
7788 for (int iy = 0; iy < met->ny; iy++)
7789 for (int ip = 0; ip < met->np; ip++) {
7790 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7791 if (var[ix][iy][ip] < bound_min)
7792 var[ix][iy][ip] = bound_min;
7793 else if (var[ix][iy][ip] > bound_max)
7794 var[ix][iy][ip] = bound_max;
7795 }
7796
7797 /* Free... */
7798 free(help);
7799}
7800
7801/*****************************************************************************/
7802
7804 const ctl_t *ctl,
7805 const clim_t *clim,
7806 met_t *met) {
7807
7808 /* Check parameters... */
7809 if (ctl->met_cape != 1)
7810 return;
7811
7812 /* Set timer... */
7813 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
7814 LOG(2, "Calculate CAPE...");
7815
7816 /* Vertical spacing (about 100 m)... */
7817 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
7818
7819 /* Loop over columns... */
7820#pragma omp parallel for default(shared) collapse(2)
7821 for (int ix = 0; ix < met->nx; ix++)
7822 for (int iy = 0; iy < met->ny; iy++) {
7823
7824 /* Get potential temperature and water vapor at lowest 50 hPa... */
7825 int n = 0;
7826 double h2o = 0, t, theta = 0;
7827 double pbot = MIN(met->ps[ix][iy], met->p[0]);
7828 double ptop = pbot - 50.;
7829 for (int ip = 0; ip < met->np; ip++) {
7830 if (met->p[ip] <= pbot) {
7831 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
7832 h2o += met->h2o[ix][iy][ip];
7833 n++;
7834 }
7835 if (met->p[ip] < ptop && n > 0)
7836 break;
7837 }
7838 theta /= n;
7839 h2o /= n;
7840
7841 /* Cannot compute anything if water vapor is missing... */
7842 met->plcl[ix][iy] = NAN;
7843 met->plfc[ix][iy] = NAN;
7844 met->pel[ix][iy] = NAN;
7845 met->cape[ix][iy] = NAN;
7846 met->cin[ix][iy] = NAN;
7847 if (h2o <= 0)
7848 continue;
7849
7850 /* Find lifted condensation level (LCL)... */
7851 ptop = P(20.);
7852 pbot = met->ps[ix][iy];
7853 do {
7854 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
7855 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
7856 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
7857 ptop = met->plcl[ix][iy];
7858 else
7859 pbot = met->plcl[ix][iy];
7860 } while (pbot - ptop > 0.1);
7861
7862 /* Calculate CIN up to LCL... */
7864 double dcape, dz, h2o_env, t_env;
7865 double p = met->ps[ix][iy];
7866 met->cape[ix][iy] = met->cin[ix][iy] = 0;
7867 do {
7868 dz = dz0 * TVIRT(t, h2o);
7869 p /= pfac;
7870 t = theta / pow(1000. / p, 0.286);
7871 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7872 &t_env, ci, cw, 1);
7873 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7874 &h2o_env, ci, cw, 0);
7875 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7876 TVIRT(t_env, h2o_env) * dz;
7877 if (dcape < 0)
7878 met->cin[ix][iy] += fabsf((float) dcape);
7879 } while (p > met->plcl[ix][iy]);
7880
7881 /* Calculate level of free convection (LFC), equilibrium level (EL),
7882 and convective available potential energy (CAPE)... */
7883 dcape = 0;
7884 p = met->plcl[ix][iy];
7885 t = theta / pow(1000. / p, 0.286);
7886 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
7887 do {
7888 dz = dz0 * TVIRT(t, h2o);
7889 p /= pfac;
7890 t -= lapse_rate(t, h2o) * dz;
7891 double psat = PSAT(t);
7892 h2o = psat / (p - (1. - EPS) * psat);
7893 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7894 &t_env, ci, cw, 1);
7895 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7896 &h2o_env, ci, cw, 0);
7897 double dcape_old = dcape;
7898 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7899 TVIRT(t_env, h2o_env) * dz;
7900 if (dcape > 0) {
7901 met->cape[ix][iy] += (float) dcape;
7902 if (!isfinite(met->plfc[ix][iy]))
7903 met->plfc[ix][iy] = (float) p;
7904 } else if (dcape_old > 0)
7905 met->pel[ix][iy] = (float) p;
7906 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
7907 met->cin[ix][iy] += fabsf((float) dcape);
7908 } while (p > ptop);
7909
7910 /* Check results... */
7911 if (!isfinite(met->plfc[ix][iy]))
7912 met->cin[ix][iy] = NAN;
7913 }
7914}
7915
7916/*****************************************************************************/
7917
7919 met_t *met) {
7920
7921 /* Set timer... */
7922 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
7923 LOG(2, "Calculate cloud data...");
7924
7925 /* Thresholds for cloud detection... */
7926 const double ccmin = 0.01, cwmin = 1e-6;
7927
7928 /* Loop over columns... */
7929#pragma omp parallel for default(shared) collapse(2)
7930 for (int ix = 0; ix < met->nx; ix++)
7931 for (int iy = 0; iy < met->ny; iy++) {
7932
7933 /* Init... */
7934 met->pct[ix][iy] = NAN;
7935 met->pcb[ix][iy] = NAN;
7936 met->cl[ix][iy] = 0;
7937
7938 /* Loop over pressure levels... */
7939 for (int ip = 0; ip < met->np - 1; ip++) {
7940
7941 /* Check pressure... */
7942 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
7943 continue;
7944
7945 /* Check ice water and liquid water content... */
7946 if (met->cc[ix][iy][ip] > ccmin
7947 && (met->lwc[ix][iy][ip] > cwmin
7948 || met->rwc[ix][iy][ip] > cwmin
7949 || met->iwc[ix][iy][ip] > cwmin
7950 || met->swc[ix][iy][ip] > cwmin)) {
7951
7952 /* Get cloud top pressure ... */
7953 met->pct[ix][iy]
7954 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
7955
7956 /* Get cloud bottom pressure ... */
7957 if (!isfinite(met->pcb[ix][iy]))
7958 met->pcb[ix][iy]
7959 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
7960 }
7961
7962 /* Get cloud water... */
7963 met->cl[ix][iy] += (float)
7964 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
7965 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
7966 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
7967 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
7968 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
7969 }
7970 }
7971}
7972
7973/*****************************************************************************/
7974
7976 const ctl_t *ctl,
7977 met_t *met) {
7978
7979 met_t *help;
7980
7981 /* Check parameters... */
7982 if (ctl->met_detrend <= 0)
7983 return;
7984
7985 /* Set timer... */
7986 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
7987 LOG(2, "Detrend meteo data...");
7988
7989 /* Allocate... */
7990 ALLOC(help, met_t, 1);
7991
7992 /* Calculate standard deviation... */
7993 const double sigma = ctl->met_detrend / 2.355;
7994 const double tssq = 2. * SQR(sigma);
7995
7996 /* Calculate box size in latitude... */
7997 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
7998 sy = MIN(MAX(1, sy), met->ny / 2);
7999
8000 /* Calculate background... */
8001#pragma omp parallel for default(shared) collapse(2)
8002 for (int ix = 0; ix < met->nx; ix++) {
8003 for (int iy = 0; iy < met->ny; iy++) {
8004
8005 /* Calculate Cartesian coordinates... */
8006 double x0[3];
8007 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
8008
8009 /* Calculate box size in longitude... */
8010 int sx =
8011 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
8012 fabs(met->lon[1] - met->lon[0]));
8013 sx = MIN(MAX(1, sx), met->nx / 2);
8014
8015 /* Init... */
8016 float wsum = 0;
8017 for (int ip = 0; ip < met->np; ip++) {
8018 help->t[ix][iy][ip] = 0;
8019 help->u[ix][iy][ip] = 0;
8020 help->v[ix][iy][ip] = 0;
8021 help->w[ix][iy][ip] = 0;
8022 }
8023
8024 /* Loop over neighboring grid points... */
8025 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
8026 int ix3 = ix2;
8027 if (ix3 < 0)
8028 ix3 += met->nx;
8029 else if (ix3 >= met->nx)
8030 ix3 -= met->nx;
8031 for (int iy2 = MAX(iy - sy, 0);
8032 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
8033
8034 /* Calculate Cartesian coordinates... */
8035 double x1[3];
8036 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
8037
8038 /* Calculate weighting factor... */
8039 const float w = (float) exp(-DIST2(x0, x1) / tssq);
8040
8041 /* Add data... */
8042 wsum += w;
8043 for (int ip = 0; ip < met->np; ip++) {
8044 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
8045 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
8046 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
8047 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
8048 }
8049 }
8050 }
8051
8052 /* Normalize... */
8053 for (int ip = 0; ip < met->np; ip++) {
8054 help->t[ix][iy][ip] /= wsum;
8055 help->u[ix][iy][ip] /= wsum;
8056 help->v[ix][iy][ip] /= wsum;
8057 help->w[ix][iy][ip] /= wsum;
8058 }
8059 }
8060 }
8061
8062 /* Subtract background... */
8063#pragma omp parallel for default(shared) collapse(3)
8064 for (int ix = 0; ix < met->nx; ix++)
8065 for (int iy = 0; iy < met->ny; iy++)
8066 for (int ip = 0; ip < met->np; ip++) {
8067 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
8068 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
8069 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
8070 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
8071 }
8072
8073 /* Free... */
8074 free(help);
8075}
8076
8077/*****************************************************************************/
8078
8080 met_t *met) {
8081
8082 /* Set timer... */
8083 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
8084 LOG(2, "Extrapolate meteo data...");
8085
8086 /* Loop over columns... */
8087#pragma omp parallel for default(shared) collapse(2)
8088 for (int ix = 0; ix < met->nx; ix++)
8089 for (int iy = 0; iy < met->ny; iy++) {
8090
8091 /* Find lowest valid data point... */
8092 int ip0;
8093 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
8094 if (!isfinite(met->t[ix][iy][ip0])
8095 || !isfinite(met->u[ix][iy][ip0])
8096 || !isfinite(met->v[ix][iy][ip0])
8097 || !isfinite(met->w[ix][iy][ip0]))
8098 break;
8099
8100 /* Extrapolate... */
8101 for (int ip = ip0; ip >= 0; ip--) {
8102 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
8103 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
8104 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
8105 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
8106 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
8107 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
8108 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
8109 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
8110 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
8111 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
8112 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
8113 }
8114 }
8115}
8116
8117/*****************************************************************************/
8118
8120 const ctl_t *ctl,
8121 met_t *met) {
8122
8123 float *help;
8124
8125 double logp[EP];
8126
8127 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
8128
8129 /* Set timer... */
8130 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
8131 LOG(2, "Calculate geopotential heights...");
8132
8133 /* Allocate... */
8134 ALLOC(help, float,
8135 EX * EY * EP);
8136
8137 /* Calculate log pressure... */
8138#pragma omp parallel for default(shared)
8139 for (int ip = 0; ip < met->np; ip++)
8140 logp[ip] = log(met->p[ip]);
8141
8142 /* Apply hydrostatic equation to calculate geopotential heights... */
8143#pragma omp parallel for default(shared) collapse(2)
8144 for (int ix = 0; ix < met->nx; ix++)
8145 for (int iy = 0; iy < met->ny; iy++) {
8146
8147 /* Get surface height and pressure... */
8148 const double zs = met->zs[ix][iy];
8149 const double lnps = log(met->ps[ix][iy]);
8150
8151 /* Get temperature and water vapor at the surface... */
8152 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
8153 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
8154 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
8155 const double h2os =
8156 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
8157 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
8158
8159 /* Upper part of profile... */
8160 met->z[ix][iy][ip0 + 1]
8161 = (float) (zs +
8162 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
8163 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
8164 for (int ip = ip0 + 2; ip < met->np; ip++)
8165 met->z[ix][iy][ip]
8166 = (float) (met->z[ix][iy][ip - 1] +
8167 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
8168 met->h2o[ix][iy][ip - 1], logp[ip],
8169 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8170
8171 /* Lower part of profile... */
8172 met->z[ix][iy][ip0]
8173 = (float) (zs +
8174 ZDIFF(lnps, ts, h2os, logp[ip0],
8175 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
8176 for (int ip = ip0 - 1; ip >= 0; ip--)
8177 met->z[ix][iy][ip]
8178 = (float) (met->z[ix][iy][ip + 1] +
8179 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
8180 met->h2o[ix][iy][ip + 1], logp[ip],
8181 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8182 }
8183
8184 /* Check control parameters... */
8185 if (dx == 0 || dy == 0)
8186 return;
8187
8188 /* Default smoothing parameters... */
8189 if (dx < 0 || dy < 0) {
8190 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
8191 dx = 3;
8192 dy = 2;
8193 } else {
8194 dx = 6;
8195 dy = 4;
8196 }
8197 }
8198
8199 /* Calculate weights for smoothing... */
8200 float ws[dx + 1][dy + 1];
8201#pragma omp parallel for default(shared) collapse(2)
8202 for (int ix = 0; ix <= dx; ix++)
8203 for (int iy = 0; iy < dy; iy++)
8204 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
8205 * (1.0f - (float) iy / (float) dy);
8206
8207 /* Copy data... */
8208#pragma omp parallel for default(shared) collapse(3)
8209 for (int ix = 0; ix < met->nx; ix++)
8210 for (int iy = 0; iy < met->ny; iy++)
8211 for (int ip = 0; ip < met->np; ip++)
8212 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
8213
8214 /* Horizontal smoothing... */
8215#pragma omp parallel for default(shared) collapse(3)
8216 for (int ip = 0; ip < met->np; ip++)
8217 for (int ix = 0; ix < met->nx; ix++)
8218 for (int iy = 0; iy < met->ny; iy++) {
8219 float res = 0, wsum = 0;
8220 int iy0 = MAX(iy - dy + 1, 0);
8221 int iy1 = MIN(iy + dy - 1, met->ny - 1);
8222 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
8223 int ix3 = ix2;
8224 if (ix3 < 0)
8225 ix3 += met->nx;
8226 else if (ix3 >= met->nx)
8227 ix3 -= met->nx;
8228 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
8229 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
8230 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
8231 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
8232 wsum += w;
8233 }
8234 }
8235 if (wsum > 0)
8236 met->z[ix][iy][ip] = res / wsum;
8237 else
8238 met->z[ix][iy][ip] = NAN;
8239 }
8240
8241 /* Free... */
8242 free(help);
8243}
8244
8245/*****************************************************************************/
8246
8248 const char *filename,
8249 const int ncid,
8250 const ctl_t *ctl,
8251 met_t *met,
8252 dd_t *dd) {
8253
8254 char levname[LEN], tstr[10];
8255
8256 double rtime = 0, r, r2;
8257
8258 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
8259 year, mon, day, hour, min, sec;
8260
8261 size_t dimlen;
8262
8263 /* Set timer... */
8264 SELECT_TIMER("READ_MET_NC_GRID", "INPUT", NVTX_READ);
8265 LOG(2, "Read meteo grid information...");
8266
8267 /* MPTRAC meteo files... */
8268 if (!ctl->met_clams) {
8269
8270 /* Get time from filename... */
8271 met->time = time_from_filename(filename, 16);
8272
8273 /* Check time information from data file... */
8274 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8275 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
8276 NC(nc_get_var_double(ncid, varid, &rtime));
8277 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
8278 WARN("Time information in meteo file does not match filename!");
8279 } else
8280 WARN("Time information in meteo file is missing!");
8281 }
8282
8283 /* CLaMS meteo files... */
8284 else {
8285
8286 /* Read time from file... */
8287 NC_GET_DOUBLE("time", &rtime, 0);
8288
8289 /* Get time from filename (considering the century)... */
8290 if (rtime < 0)
8291 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
8292 else
8293 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
8294 year = atoi(tstr);
8295 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
8296 mon = atoi(tstr);
8297 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
8298 day = atoi(tstr);
8299 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
8300 hour = atoi(tstr);
8301 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
8302 }
8303
8304 /* Check time... */
8305 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8306 || day < 1 || day > 31 || hour < 0 || hour > 23)
8307 ERRMSG("Cannot read time from filename!");
8308 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
8309 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8310 met->time, year2, mon2, day2, hour2, min2);
8311
8312 /* Get vertical dimension... */
8313 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
8314 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
8315 ERRMSG
8316 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
8317
8318 NC(nc_inq_varndims(ncid, varid, &ndims));
8319 NC(nc_inq_vardimid(ncid, varid, dimids));
8320
8321 if (ndims == 4) {
8322 NC(nc_inq_dim
8323 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
8324 } else if (ndims == 3) {
8325 NC(nc_inq_dim
8326 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
8327 } else
8328 ERRMSG("Cannot determine vertical dimension!")
8329 met->np = (int) dimlen;
8330
8331 LOG(2, "Number of levels: %d", met->np);
8332 if (met->np < 2 || met->np > EP)
8333 ERRMSG("Number of levels out of range!");
8334
8335 if (!ctl->dd) {
8336
8337 /* Get grid dimensions... */
8338 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
8339 LOG(2, "Number of longitudes: %d", met->nx);
8340
8341 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
8342 LOG(2, "Number of latitudes: %d", met->ny);
8343
8344 /* Read longitudes and latitudes... */
8345 NC_GET_DOUBLE("lon", met->lon, 1);
8346 LOG(2, "Longitudes: %g, %g ... %g deg",
8347 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
8348 NC_GET_DOUBLE("lat", met->lat, 1);
8349 LOG(2, "Latitudes: %g, %g ... %g deg",
8350 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
8351
8352 } else {
8353
8354 /* Use 'naive', i.e. equidistant lat-lon domain decomposition... */
8355 read_met_nc_grid_dd_naive(dd, ctl, met, ncid);
8356
8357 }
8358
8359 /* Read pressure levels... */
8360 if (ctl->met_np <= 0) {
8361 NC_GET_DOUBLE(levname, met->p, 1);
8362 for (int ip = 0; ip < met->np; ip++)
8363 met->p[ip] /= 100.;
8364 LOG(2, "Altitude levels: %g, %g ... %g km",
8365 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
8366 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8367 met->p[0], met->p[1], met->p[met->np - 1]);
8368 }
8369
8370 /* Read hybrid levels... */
8371 if (strcasecmp(levname, "hybrid") == 0)
8372 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
8373
8374 /* Read model level coefficients from file... */
8375 if (ctl->met_vert_coord == 2) {
8376 NC_GET_DOUBLE("hyam", met->hyam, 1);
8377 NC_GET_DOUBLE("hybm", met->hybm, 1);
8378 }
8379
8380 /* Copy model level coefficients from control parameters... */
8381 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
8382 if (ctl->met_nlev <= 0)
8383 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
8384 for (int ip = 0; ip < ctl->met_nlev; ip++) {
8385 met->hyam[ip] = ctl->met_lev_hyam[ip];
8386 met->hybm[ip] = ctl->met_lev_hybm[ip];
8387 }
8388 }
8389
8390 /* Calculate eta levels... */
8391 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
8392 met->eta[k] = met->hyam[k] / 100000.0 + met->hybm[k];
8393 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
8394 ERRMSG("Eta levels must be ascending!");
8395 }
8396
8397 /* Check horizontal grid spacing... */
8398 for (int ix = 2; ix < met->nx; ix++)
8399 if (fabs
8400 (fabs(met->lon[ix] - met->lon[ix - 1]) -
8401 fabs(met->lon[1] - met->lon[0])) > 0.001)
8402 ERRMSG("No regular grid spacing in longitudes!");
8403 for (int iy = 2; iy < met->ny; iy++)
8404 if (fabs
8405 (fabs(met->lat[iy] - met->lat[iy - 1]) -
8406 fabs(met->lat[1] - met->lat[0])) > 0.001) {
8407 WARN("No regular grid spacing in latitudes!");
8408 break;
8409 }
8410}
8411
8412/*****************************************************************************/
8413
8415 const int ncid,
8416 const ctl_t *ctl,
8417 met_t *met,
8418 dd_t *dd) {
8419
8420 /* Set timer... */
8421 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
8422 LOG(2, "Read surface data...");
8423
8424 /* Read surface pressure... */
8425 if (read_met_nc_2d
8426 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
8427 1.0f, 1)) {
8428 for (int ix = 0; ix < met->nx; ix++)
8429 for (int iy = 0; iy < met->ny; iy++)
8430 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8431 } else
8432 if (!read_met_nc_2d
8433 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
8434 0.01f, 1)) {
8435 WARN("Cannot not read surface pressure data (use lowest level)!");
8436 for (int ix = 0; ix < met->nx; ix++)
8437 for (int iy = 0; iy < met->ny; iy++)
8438 met->ps[ix][iy]
8439 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
8440 }
8441
8442 /* MPTRAC meteo data... */
8443 if (ctl->met_clams == 0) {
8444
8445 /* Read geopotential height at the surface... */
8446 if (!read_met_nc_2d
8447 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8448 (float) (1. / (1000. * G0)), 1))
8449 if (!read_met_nc_2d
8450 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8451 (float) (1. / 1000.), 1))
8452 WARN("Cannot read surface geopotential height!");
8453 }
8454
8455 /* CLaMS meteo data... */
8456 else {
8457
8458 /* Read geopotential height at the surface
8459 (use lowermost level of 3-D data field)... */
8460 float *help;
8461 ALLOC(help, float,
8462 EX * EY * EP);
8463 memcpy(help, met->pl, sizeof(met->pl));
8464 if (!read_met_nc_3d
8465 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
8466 (float) (1e-3 / G0)))
8467 ERRMSG("Cannot read geopotential height!");
8468 for (int ix = 0; ix < met->nx; ix++)
8469 for (int iy = 0; iy < met->ny; iy++)
8470 met->zs[ix][iy] = met->pl[ix][iy][0];
8471 memcpy(met->pl, help, sizeof(met->pl));
8472 free(help);
8473 }
8474
8475 /* Read temperature at the surface... */
8476 if (!read_met_nc_2d
8477 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
8478 1))
8479 WARN("Cannot read surface temperature!");
8480
8481 /* Read zonal wind at the surface... */
8482 if (!read_met_nc_2d
8483 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
8484 met->us, 1.0, 1))
8485 WARN("Cannot read surface zonal wind!");
8486
8487 /* Read meridional wind at the surface... */
8488 if (!read_met_nc_2d
8489 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
8490 met->vs, 1.0, 1))
8491 WARN("Cannot read surface meridional wind!");
8492
8493 /* Read eastward turbulent surface stress... */
8494 if (!read_met_nc_2d
8495 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
8496 1.0, 1))
8497 WARN("Cannot read eastward turbulent surface stress!");
8498
8499 /* Read northward turbulent surface stress... */
8500 if (!read_met_nc_2d
8501 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
8502 1.0, 1))
8503 WARN("Cannot read nothward turbulent surface stress!");
8504
8505 /* Read surface sensible heat flux... */
8506 if (!read_met_nc_2d
8507 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
8508 1.0, 1))
8509 WARN("Cannot read surface sensible heat flux!");
8510
8511 /* Read land-sea mask... */
8512 if (!read_met_nc_2d
8513 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
8514 1.0, 1))
8515 WARN("Cannot read land-sea mask!");
8516
8517 /* Read sea surface temperature... */
8518 if (!read_met_nc_2d
8519 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
8520 1.0, 1))
8521 WARN("Cannot read sea surface temperature!");
8522
8523 /* Read PBL... */
8524 if (ctl->met_pbl == 0)
8525 if (!read_met_nc_2d
8526 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8527 0.01f, 1))
8528 WARN("Cannot read planetary boundary layer pressure!");
8529 if (ctl->met_pbl == 1)
8530 if (!read_met_nc_2d
8531 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8532 0.001f, 1))
8533 WARN("Cannot read planetary boundary layer height!");
8534
8535 /* Read CAPE... */
8536 if (ctl->met_cape == 0)
8537 if (!read_met_nc_2d
8538 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
8539 met->cape, 1.0, 1))
8540 WARN("Cannot read CAPE!");
8541
8542 /* Read CIN... */
8543 if (ctl->met_cape == 0)
8544 if (!read_met_nc_2d
8545 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
8546 1.0, 1))
8547 WARN("Cannot read convective inhibition!");
8548}
8549
8550/*****************************************************************************/
8551
8553 const int ncid,
8554 const ctl_t *ctl,
8555 met_t *met,
8556 dd_t *dd) {
8557
8558 /* Set timer... */
8559 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT", NVTX_READ);
8560 LOG(2, "Read level data...");
8561
8562 /* Read temperature... */
8563 if (!read_met_nc_3d
8564 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
8565 ERRMSG("Cannot read temperature!");
8566
8567 /* Read horizontal wind and vertical velocity... */
8568 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
8569 ERRMSG("Cannot read zonal wind!");
8570 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
8571 ERRMSG("Cannot read meridional wind!");
8572 if (!read_met_nc_3d
8573 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
8574 WARN("Cannot read vertical velocity!");
8575
8576 /* Read water vapor... */
8577 if (!ctl->met_relhum) {
8578 if (!read_met_nc_3d
8579 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
8580 (float) (MA / MH2O)))
8581 WARN("Cannot read specific humidity!");
8582 } else {
8583 if (!read_met_nc_3d
8584 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
8585 WARN("Cannot read relative humidity!");
8586#pragma omp parallel for default(shared) collapse(2)
8587 for (int ix = 0; ix < met->nx; ix++)
8588 for (int iy = 0; iy < met->ny; iy++)
8589 for (int ip = 0; ip < met->np; ip++) {
8590 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
8591 met->h2o[ix][iy][ip] =
8592 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
8593 }
8594 }
8595
8596 /* Read ozone... */
8597 if (!read_met_nc_3d
8598 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
8599 (float) (MA / MO3)))
8600 WARN("Cannot read ozone data!");
8601
8602 /* Read cloud data... */
8603 if (!read_met_nc_3d
8604 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
8605 WARN("Cannot read cloud liquid water content!");
8606 if (!read_met_nc_3d
8607 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
8608 WARN("Cannot read cloud rain water content!");
8609 if (!read_met_nc_3d
8610 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
8611 WARN("Cannot read cloud ice water content!");
8612 if (!read_met_nc_3d
8613 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
8614 WARN("Cannot read cloud snow water content!");
8615 if (!read_met_nc_3d
8616 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
8617 WARN("Cannot read cloud cover!");
8618
8619 /* Read zeta and zeta_dot... */
8620 if (ctl->advect_vert_coord == 1) {
8621 if (!read_met_nc_3d
8622 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
8623 WARN("Cannot read ZETA!");
8624 if (!read_met_nc_3d
8625 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
8626 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
8627 WARN("Cannot read ZETA_DOT!");
8628 }
8629
8630 /* Read eta and eta_dot... */
8631 else if (ctl->advect_vert_coord == 3) {
8632#pragma omp parallel for default(shared)
8633 for (int ix = 0; ix < met->nx; ix++)
8634 for (int iy = 0; iy < met->ny; iy++)
8635 for (int ip = 0; ip < met->np; ip++)
8636 met->zetal[ix][iy][ip] =
8637 (float) (met->hyam[ip] / 100000.0 + met->hybm[ip]);
8638 if (!read_met_nc_3d
8639 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
8640 1.0))
8641 WARN("Cannot read eta vertical velocity!");
8642 }
8643
8644 /* Store velocities on model levels... */
8645 if (ctl->met_vert_coord != 0) {
8646#pragma omp parallel for default(shared)
8647 for (int ix = 0; ix < met->nx; ix++)
8648 for (int iy = 0; iy < met->ny; iy++)
8649 for (int ip = 0; ip < met->np; ip++) {
8650 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
8651 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
8652 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
8653 }
8654
8655 /* Save number of model levels... */
8656 met->npl = met->np;
8657 }
8658
8659 /* Get pressure on model levels... */
8660 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
8661
8662 /* Read 3-D pressure field... */
8663 if (ctl->met_vert_coord == 1) {
8664 if (!read_met_nc_3d
8665 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
8666 0.01f))
8667 if (!read_met_nc_3d
8668 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
8669 ERRMSG("Cannot read pressure on model levels!");
8670 }
8671
8672 /* Use a and b coefficients for full levels (at layer midpoints)... */
8673 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
8674
8675 /* Check number of levels... */
8676 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
8677 ERRMSG("Mismatch in number of model levels!");
8678
8679 /* Calculate pressure... */
8680 for (int ix = 0; ix < met->nx; ix++)
8681 for (int iy = 0; iy < met->ny; iy++)
8682 for (int ip = 0; ip < met->np; ip++)
8683 met->pl[ix][iy][ip] =
8684 (float) (met->hyam[ip] / 100. +
8685 met->hybm[ip] * met->ps[ix][iy]);
8686 }
8687
8688 /* Use a and b coefficients for half levels (at layer interfaces)... */
8689 else if (ctl->met_vert_coord == 4) {
8690
8691 /* Check number of levels... */
8692 if (met->np + 1 != ctl->met_nlev)
8693 ERRMSG("Mismatch in number of model levels!");
8694
8695 /* Calculate pressure... */
8696#pragma omp parallel for default(shared) collapse(2)
8697 for (int ix = 0; ix < met->nx; ix++)
8698 for (int iy = 0; iy < met->ny; iy++)
8699 for (int ip = 0; ip < met->np; ip++) {
8700 const double p0 =
8701 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
8702 const double p1 =
8703 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
8704 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
8705 }
8706 }
8707
8708 /* Check ordering of pressure levels... */
8709 for (int ix = 0; ix < met->nx; ix++)
8710 for (int iy = 0; iy < met->ny; iy++)
8711 for (int ip = 1; ip < met->np; ip++)
8712 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
8713 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
8714 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
8715 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
8716 ERRMSG("Pressure profiles are not monotonic!");
8717 }
8718
8719 /* Interpolate from model levels to pressure levels... */
8720 if (ctl->met_np > 0) {
8721
8722 /* Interpolate variables... */
8723 read_met_ml2pl(ctl, met, met->t, "T");
8724 read_met_ml2pl(ctl, met, met->u, "U");
8725 read_met_ml2pl(ctl, met, met->v, "V");
8726 read_met_ml2pl(ctl, met, met->w, "W");
8727 read_met_ml2pl(ctl, met, met->h2o, "H2O");
8728 read_met_ml2pl(ctl, met, met->o3, "O3");
8729 read_met_ml2pl(ctl, met, met->lwc, "LWC");
8730 read_met_ml2pl(ctl, met, met->rwc, "RWC");
8731 read_met_ml2pl(ctl, met, met->iwc, "IWC");
8732 read_met_ml2pl(ctl, met, met->swc, "SWC");
8733 read_met_ml2pl(ctl, met, met->cc, "CC");
8734
8735 /* Set new pressure levels... */
8736 met->np = ctl->met_np;
8737 for (int ip = 0; ip < met->np; ip++)
8738 met->p[ip] = ctl->met_p[ip];
8739 }
8740
8741 /* Check ordering of pressure levels... */
8742 for (int ip = 1; ip < met->np; ip++)
8743 if (met->p[ip - 1] < met->p[ip])
8744 ERRMSG("Pressure levels must be descending!");
8745}
8746
8747/*****************************************************************************/
8748
8750 const int ncid,
8751 const char *varname,
8752 const char *varname2,
8753 const char *varname3,
8754 const char *varname4,
8755 const char *varname5,
8756 const char *varname6,
8757 const ctl_t *ctl,
8758 const met_t *met,
8759 dd_t *dd,
8760 float dest[EX][EY],
8761 const float scl,
8762 const int init) {
8763
8764 char varsel[LEN];
8765
8766 float offset, scalfac;
8767
8768 int varid;
8769
8770 /* Check if variable exists... */
8771 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8772 sprintf(varsel, "%s", varname);
8773 else if (varname2 != NULL
8774 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8775 sprintf(varsel, "%s", varname2);
8776 else if (varname3 != NULL
8777 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8778 sprintf(varsel, "%s", varname3);
8779 else if (varname4 != NULL
8780 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8781 sprintf(varsel, "%s", varname4);
8782 else if (varname5 != NULL
8783 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
8784 sprintf(varsel, "%s", varname5);
8785 else if (varname6 != NULL
8786 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
8787 sprintf(varsel, "%s", varname6);
8788 else
8789 return 0;
8790
8791 /* Read packed data... */
8792 if (ctl->met_nc_scale && !ctl->dd
8793 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8794 && nc_get_att_float(ncid, varid, "scale_factor",
8795 &scalfac) == NC_NOERR) {
8796
8797 /* Allocate... */
8798 short *help;
8799 ALLOC(help, short,
8800 EX * EY * EP);
8801
8802 /* Read fill value and missing value... */
8803 short fillval, missval;
8804 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8805 fillval = 0;
8806 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
8807 missval = 0;
8808
8809 /* Write info... */
8810 LOG(2, "Read 2-D variable: %s"
8811 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
8812 varsel, fillval, missval, scalfac, offset);
8813
8814 /* Read data... */
8815 NC(nc_get_var_short(ncid, varid, help));
8816
8817 /* Check meteo data layout... */
8818 if (ctl->met_convention != 0)
8819 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
8820
8821 /* Copy and check data... */
8822 omp_set_dynamic(1);
8823#pragma omp parallel for default(shared)
8824 for (int ix = 0; ix < met->nx; ix++)
8825 for (int iy = 0; iy < met->ny; iy++) {
8826 if (init)
8827 dest[ix][iy] = 0;
8828 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
8829 if ((fillval == 0 || aux != fillval)
8830 && (missval == 0 || aux != missval)
8831 && fabsf(aux * scalfac + offset) < 1e14f)
8832 dest[ix][iy] += scl * (aux * scalfac + offset);
8833 else
8834 dest[ix][iy] = NAN;
8835 }
8836 omp_set_dynamic(0);
8837
8838 /* Free... */
8839 free(help);
8840 }
8841
8842 /* Unpacked data... */
8843 else if (!ctl->dd) {
8844
8845 /* Allocate... */
8846 float *help;
8847 ALLOC(help, float,
8848 EX * EY);
8849
8850 /* Read fill value and missing value... */
8851 float fillval, missval;
8852 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8853 fillval = 0;
8854 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8855 missval = 0;
8856
8857 /* Write info... */
8858 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8859 varsel, fillval, missval);
8860
8861 /* Read data... */
8862 NC(nc_get_var_float(ncid, varid, help));
8863
8864 /* Check meteo data layout... */
8865 if (ctl->met_convention == 0) {
8866
8867 /* Copy and check data (ordering: lat, lon)... */
8868 omp_set_dynamic(1);
8869#pragma omp parallel for default(shared)
8870 for (int ix = 0; ix < met->nx; ix++)
8871 for (int iy = 0; iy < met->ny; iy++) {
8872 if (init)
8873 dest[ix][iy] = 0;
8874 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
8875 if ((fillval == 0 || aux != fillval)
8876 && (missval == 0 || aux != missval)
8877 && fabsf(aux) < 1e14f)
8878 dest[ix][iy] += scl * aux;
8879 else
8880 dest[ix][iy] = NAN;
8881 }
8882 omp_set_dynamic(0);
8883
8884 } else {
8885
8886 /* Copy and check data (ordering: lon, lat)... */
8887 omp_set_dynamic(1);
8888#pragma omp parallel for default(shared)
8889 for (int iy = 0; iy < met->ny; iy++)
8890 for (int ix = 0; ix < met->nx; ix++) {
8891 if (init)
8892 dest[ix][iy] = 0;
8893 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
8894 if ((fillval == 0 || aux != fillval)
8895 && (missval == 0 || aux != missval)
8896 && fabsf(aux) < 1e14f)
8897 dest[ix][iy] += scl * aux;
8898 else
8899 dest[ix][iy] = NAN;
8900 }
8901 omp_set_dynamic(0);
8902 }
8903
8904 /* Free... */
8905 free(help);
8906
8907 }
8908 /* Domain decomposed data... */
8909 else {
8910
8911 /* Read fill value and missing value... */
8912 float fillval, missval;
8913 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8914 fillval = 0;
8915 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8916 missval = 0;
8917
8918 /* Write info... */
8919 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8920 varsel, fillval, missval);
8921
8922 /* Define hyperslab... */
8923 float *help;
8924 size_t help_subdomain_start[3];
8925 size_t help_subdomain_count[3];
8926
8927 help_subdomain_start[0] = 0;
8928 help_subdomain_start[1] = dd->subdomain_start[2];
8929 help_subdomain_start[2] = dd->subdomain_start[3];
8930
8931 help_subdomain_count[0] = 1;
8932 help_subdomain_count[1] = dd->subdomain_count[2]; //y
8933 help_subdomain_count[2] = dd->subdomain_count[3]; //x
8934
8935 ALLOC(help, float,
8936 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]
8937 );
8938
8939 /* Read data... */
8940 NC(nc_get_vara_float
8941 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
8942
8943 /* Read halos at boundaries... */
8944 size_t help_halo_bnd_start[3];
8945 size_t help_halo_bnd_count[3];
8946
8947 help_halo_bnd_start[0] = 0;
8948 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
8949 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
8950
8951 help_halo_bnd_count[0] = 1;
8952 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
8953 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
8954
8955 float *help_halo;
8956 ALLOC(help_halo, float,
8957 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
8958 NC(nc_get_vara_float
8959 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
8960
8961 /* Check meteo data layout... */
8962 if (ctl->met_convention == 0) {
8963 /* Copy and check data (ordering: lat, lon)... */
8964#pragma omp parallel for default(shared) num_threads(12)
8965 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
8966 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
8967 if (init == 1)
8968 dest[ix + dd->halo_offset_start][iy] = 0;
8969 const float aux =
8970 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
8971 if ((fillval == 0 || aux != fillval)
8972 && (missval == 0 || aux != missval)
8973 && fabsf(aux) < 1e14f) {
8974 dest[ix + dd->halo_offset_start][iy] += scl * aux;
8975 } else
8976 dest[ix + dd->halo_offset_start][iy] = NAN;
8977 }
8978
8979 /* Copy and check data (ordering: lat, lon)... */
8980#pragma omp parallel for default(shared) num_threads(12)
8981 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
8982 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
8983 if (init == 1)
8984 dest[ix + dd->halo_offset_end][iy] = 0;
8985 const float aux =
8986 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
8987 if ((fillval == 0 || aux != fillval)
8988 && (missval == 0 || aux != missval)
8989 && fabsf(aux) < 1e14f)
8990 dest[ix + dd->halo_offset_end][iy] += scl * aux;
8991 else {
8992 dest[ix + dd->halo_offset_end][iy] = NAN;
8993 }
8994 }
8995
8996 } else {
8997 ERRMSG("Domain decomposition with data convection incompatible!");
8998 }
8999
9000 /* Free... */
9001 free(help);
9002 free(help_halo);
9003 }
9004
9005 /* Return... */
9006 return 1;
9007}
9008
9009/*****************************************************************************/
9010
9012 const int ncid,
9013 const char *varname,
9014 const char *varname2,
9015 const char *varname3,
9016 const char *varname4,
9017 const ctl_t *ctl,
9018 const met_t *met,
9019 dd_t *dd,
9020 float dest[EX][EY][EP],
9021 const float scl) {
9022
9023 SELECT_TIMER("read_met_nc_3d", "INPUT", NVTX_READ);
9024
9025 char varsel[LEN];
9026
9027 float offset, scalfac;
9028
9029 int varid;
9030
9031 /* Check if variable exists... */
9032 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
9033 sprintf(varsel, "%s", varname);
9034 else if (varname2 != NULL
9035 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
9036 sprintf(varsel, "%s", varname2);
9037 else if (varname3 != NULL
9038 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
9039 sprintf(varsel, "%s", varname3);
9040 else if (varname4 != NULL
9041 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
9042 sprintf(varsel, "%s", varname4);
9043 else
9044 return 0;
9045
9046 if (ctl->met_nc_scale && !ctl->dd
9047 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
9048 && nc_get_att_float(ncid, varid, "scale_factor",
9049 &scalfac) == NC_NOERR) {
9050
9051 /* Allocate... */
9052 short *help;
9053 ALLOC(help, short,
9054 EX * EY * EP);
9055
9056 /* Read fill value and missing value... */
9057 short fillval, missval;
9058 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9059 fillval = 0;
9060 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9061 missval = 0;
9062
9063 /* Write info... */
9064 LOG(2, "Read 3-D variable: %s "
9065 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9066 varsel, fillval, missval, scalfac, offset);
9067
9068 /* Read data... */
9069 NC(nc_get_var_short(ncid, varid, help));
9070
9071 /* Check meteo data layout... */
9072 if (ctl->met_convention != 0)
9073 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9074
9075 /* Copy and check data... */
9076 omp_set_dynamic(1);
9077#pragma omp parallel for default(shared)
9078 for (int ix = 0; ix < met->nx; ix++)
9079 for (int iy = 0; iy < met->ny; iy++)
9080 for (int ip = 0; ip < met->np; ip++) {
9081 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9082 if ((fillval == 0 || aux != fillval)
9083 && (missval == 0 || aux != missval)
9084 && fabsf(aux * scalfac + offset) < 1e14f)
9085 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
9086 else
9087 dest[ix][iy][ip] = NAN;
9088 }
9089 omp_set_dynamic(0);
9090
9091 /* Free... */
9092 free(help);
9093 }
9094
9095 /* Unpacked data... */
9096 else if (!ctl->dd) {
9097
9098 /* Allocate... */
9099 float *help;
9100 ALLOC(help, float,
9101 EX * EY * EP);
9102
9103 /* Read fill value and missing value... */
9104 float fillval, missval;
9105 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9106 fillval = 0;
9107 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9108 missval = 0;
9109
9110 /* Write info... */
9111 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9112 varsel, fillval, missval);
9113
9114 /* Read data... */
9115 NC(nc_get_var_float(ncid, varid, help));
9116
9117 /* Check meteo data layout... */
9118 if (ctl->met_convention == 0) {
9119
9120 /* Copy and check data (ordering: lev, lat, lon)... */
9121 omp_set_dynamic(1);
9122#pragma omp parallel for default(shared)
9123 for (int ix = 0; ix < met->nx; ix++)
9124 for (int iy = 0; iy < met->ny; iy++)
9125 for (int ip = 0; ip < met->np; ip++) {
9126 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9127 if ((fillval == 0 || aux != fillval)
9128 && (missval == 0 || aux != missval)
9129 && fabsf(aux) < 1e14f)
9130 dest[ix][iy][ip] = scl * aux;
9131 else
9132 dest[ix][iy][ip] = NAN;
9133 }
9134 omp_set_dynamic(0);
9135
9136 } else {
9137
9138 /* Copy and check data (ordering: lon, lat, lev)... */
9139 omp_set_dynamic(1);
9140#pragma omp parallel for default(shared)
9141 for (int ip = 0; ip < met->np; ip++)
9142 for (int iy = 0; iy < met->ny; iy++)
9143 for (int ix = 0; ix < met->nx; ix++) {
9144 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9145 if ((fillval == 0 || aux != fillval)
9146 && (missval == 0 || aux != missval)
9147 && fabsf(aux) < 1e14f)
9148 dest[ix][iy][ip] = scl * aux;
9149 else
9150 dest[ix][iy][ip] = NAN;
9151 }
9152 omp_set_dynamic(0);
9153 }
9154
9155 /* Free... */
9156 free(help);
9157
9158 }
9159 /* Domain decomposed data... */
9160 else {
9161
9162 /* Read fill value and missing value... */
9163 float fillval, missval;
9164 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9165 fillval = 0;
9166 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9167 missval = 0;
9168
9169 /* Write info... */
9170 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9171 varsel, fillval, missval);
9172
9173 SELECT_TIMER("read_met_nc_3d_CP1", "INPUT", NVTX_READ);
9174
9175 /* Define hyperslab... */
9176
9177 /* Allocate... */
9178 float *help;
9179 ALLOC(help, float,
9180 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
9181 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
9182
9183 SELECT_TIMER("read_met_nc_3d_CP2", "INPUT", NVTX_READ);
9184
9185 /* Use default NetCDF parallel I/O behavior */
9186 NC(nc_get_vara_float
9187 (ncid, varid, dd->subdomain_start, dd->subdomain_count, help));
9188
9189 /* Read halos separately at boundaries... */
9190 float *help_halo;
9191 ALLOC(help_halo, float,
9192 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
9193 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
9194
9195 SELECT_TIMER("read_met_nc_3d_CP3", "INPUT", NVTX_READ);
9196
9197 /* Halo read also uses independent access */
9198 NC(nc_get_vara_float(ncid,
9199 varid,
9200 dd->halo_bnd_start, dd->halo_bnd_count, help_halo));
9201
9202 SELECT_TIMER("read_met_nc_3d_CP4", "INPUT", NVTX_READ);
9203
9204 /* Check meteo data layout... */
9205 if (ctl->met_convention == 0) {
9206 /* Copy and check data (ordering: lev, lat, lon)... */
9207#pragma omp parallel for default(shared) num_threads(12)
9208 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
9209 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9210 for (int ip = 0; ip < met->np; ip++) {
9211 const float aux =
9212 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
9213 (int) dd->subdomain_count[3])];
9214 if ((fillval == 0 || aux != fillval)
9215 && (missval == 0 || aux != missval)
9216 && fabsf(aux) < 1e14f)
9217 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9218 else
9219 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9220 }
9221
9222#pragma omp parallel for default(shared) num_threads(12)
9223 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
9224 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9225 for (int ip = 0; ip < met->np; ip++) {
9226 const float aux =
9227 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
9228 (int) dd->halo_bnd_count[3])];
9229 if ((fillval == 0 || aux != fillval)
9230 && (missval == 0 || aux != missval)
9231 && fabsf(aux) < 1e14f)
9232 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9233 else
9234 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9235 }
9236
9237 } else {
9238
9239 /* Copy and check data (ordering: lon, lat, lev)... */
9240#pragma omp parallel for default(shared) num_threads(12)
9241 for (int ip = 0; ip < met->np; ip++)
9242 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9243 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
9244 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9245 if ((fillval == 0 || aux != fillval)
9246 && (missval == 0 || aux != missval)
9247 && fabsf(aux) < 1e14f)
9248 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9249 else
9250 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9251 }
9252
9253#pragma omp parallel for default(shared) num_threads(12)
9254 for (int ip = 0; ip < met->np; ip++)
9255 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9256 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
9257 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9258 if ((fillval == 0 || aux != fillval)
9259 && (missval == 0 || aux != missval)
9260 && fabsf(aux) < 1e14f)
9261 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9262 else
9263 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9264 }
9265 }
9266
9267 /* Free... */
9268 free(help);
9269 free(help_halo);
9270 }
9271
9272 /* Return... */
9273 return 1;
9274}
9275
9276/*****************************************************************************/
9277
9278#ifdef ECCODES
9279int read_met_grib(
9280 const char *filename,
9281 const ctl_t *ctl,
9282 met_t *met) {
9283
9284 /* Set filenames... */
9285 size_t filename_len = strlen(filename) + 1;
9286 char sf_filename[filename_len];
9287 char ml_filename[filename_len];
9288 strcpy(sf_filename, filename);
9289 strcpy(ml_filename, filename);
9290 get_met_replace(ml_filename, "XX", "ml");
9291 get_met_replace(sf_filename, "XX", "sf");
9292
9293 /* Open files... */
9294 FILE *ml_file = fopen(ml_filename, "rb");
9295 FILE *sf_file = fopen(sf_filename, "rb");
9296 if (ml_file == NULL || sf_file == NULL) {
9297 if (ml_file != NULL) {
9298 fclose(ml_file);
9299 WARN("Cannot open file: %s", sf_filename);
9300 }
9301 if (sf_file != NULL) {
9302 fclose(sf_file);
9303 WARN("Cannot open file: %s", ml_filename);
9304 }
9305 return 0;
9306 }
9307
9308 /* Get handles for model level data... */
9309 int ml_num_messages = 0, err = 0;
9310 ECC(codes_count_in_file(0, ml_file, &ml_num_messages));
9311 codes_handle **ml_handles =
9312 (codes_handle **) malloc(sizeof(codes_handle *) *
9313 (size_t) ml_num_messages);
9314 for (int i = 0; i < ml_num_messages; i++) {
9315 codes_handle *h = NULL;
9316 if ((h = codes_grib_handle_new_from_file(0, ml_file, &err)) != NULL)
9317 ml_handles[i] = h;
9318 }
9319
9320 /* Get handles for surface data... */
9321 int sf_num_messages = 0;
9322 ECC(codes_count_in_file(0, sf_file, &sf_num_messages));
9323 codes_handle **sf_handles =
9324 (codes_handle **) malloc(sizeof(codes_handle *) *
9325 (size_t) sf_num_messages);
9326 for (int i = 0; i < sf_num_messages; i++) {
9327 codes_handle *h = NULL;
9328 if ((h = codes_grib_handle_new_from_file(0, sf_file, &err)) != NULL)
9329 sf_handles[i] = h;
9330 }
9331
9332 /* Close files... */
9333 fclose(ml_file);
9334 fclose(sf_file);
9335
9336 /* Read grid data... */
9337 read_met_grib_grid(ml_handles, ml_num_messages, met);
9338
9339 /* Read surface data... */
9340 read_met_grib_surface(sf_handles, sf_num_messages, ctl, met);
9341 for (int i = 0; i < sf_num_messages; i++)
9342 codes_handle_delete(sf_handles[i]);
9343 free(sf_handles);
9344
9345 /* Compute 3D pressure field... */
9346 size_t value_count = 0;
9347 ECC(codes_get_size(ml_handles[0], "pv", &value_count));
9348 if (value_count % 2 != 0)
9349 ERRMSG("Unexpected pv array length!");
9350 size_t nlevels = value_count / 2 - 1; /* number of full model levels */
9351 double *values;
9352 ALLOC(values, double,
9353 value_count);
9354 ECC(codes_get_double_array(ml_handles[0], "pv", values, &value_count));
9355 double *a_vals = values;
9356 double *b_vals = values + nlevels;
9357 if (met->npl > (int) nlevels)
9358 ERRMSG("met->npl exceeds number of pressure levels in GRIB!");
9359 for (int nx = 0; nx < met->nx; nx++)
9360 for (int ny = 0; ny < met->ny; ny++)
9361 for (int level = 0; level <= met->npl; level++) {
9362 const float p1 = (float) (a_vals[level] * 0.01f +
9363 met->ps[nx][ny] * b_vals[level]);
9364 const float p2 = (float) (a_vals[level + 1] * 0.01f +
9365 met->ps[nx][ny] * b_vals[level + 1]);
9366 met->pl[nx][ny][level] = 0.5f * (p1 + p2);
9367 }
9368 free(values);
9369
9370 /* Read model level data... */
9371 read_met_grib_levels(ml_handles, ml_num_messages, ctl, met);
9372 for (int i = 0; i < ml_num_messages; i++)
9373 codes_handle_delete(ml_handles[i]);
9374 free(ml_handles);
9375
9376 /* Return success... */
9377 return 1;
9378}
9379#endif
9380
9381/*****************************************************************************/
9382
9383#ifdef ECCODES
9385 codes_handle **handles,
9386 int count_handles,
9387 met_t *met) {
9388
9389 /* Set timer... */
9390 SELECT_TIMER("READ_MET_GRIB_GRID", "INPUT", NVTX_READ);
9391 LOG(2, "Read meteo grid information...");
9392
9393 /* Read date and time... */
9394 char datestr[LEN], timestr[LEN];
9395 size_t s_date = sizeof(datestr);
9396 ECC(codes_get_string(handles[0], "dataDate", datestr, &s_date));
9397 size_t s_time = sizeof(timestr);
9398 ECC(codes_get_string(handles[0], "dataTime", timestr, &s_time));
9399 int year, month, day, hour;
9400 if (sscanf(datestr, "%4d%2d%2d", &year, &month, &day) != 3)
9401 ERRMSG("Failed to parse dataDate: %s", datestr);
9402 if (sscanf(timestr, "%2d", &hour) != 1)
9403 ERRMSG("Failed to parse dataTime: %s", timestr);
9404 time2jsec(year, month, day, hour, 0, 0, 0, &(met->time));
9405 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)", met->time, year, month,
9406 day, hour, 0);
9407
9408 /* Read grid information... */
9409 long count_lat = 0, count_lon = 0;
9410 ECC(codes_get_long(handles[0], "Nj", &count_lat));
9411 ECC(codes_get_long(handles[0], "Ni", &count_lon));
9412 met->ny = (int) count_lat;
9413 met->nx = (int) count_lon;
9414
9415 /* Check grid dimensions... */
9416 LOG(2, "Number of longitudes: %d", met->nx);
9417 if (met->nx < 2 || met->nx > EX)
9418 ERRMSG("Number of longitudes out of range!");
9419 LOG(2, "Number of latitudes: %d", met->ny);
9420 if (met->ny < 2 || met->ny > EY)
9421 ERRMSG("Number of latitudes out of range!");
9422
9423 double first_lon, last_lon, first_lat, last_lat, inc_lon, inc_lat;
9424 ECC(codes_get_double
9425 (handles[0], "longitudeOfFirstGridPointInDegrees", &first_lon));
9426 ECC(codes_get_double
9427 (handles[0], "latitudeOfFirstGridPointInDegrees", &first_lat));
9428 ECC(codes_get_double
9429 (handles[0], "longitudeOfLastGridPointInDegrees", &last_lon));
9430 ECC(codes_get_double
9431 (handles[0], "latitudeOfLastGridPointInDegrees", &last_lat));
9432 ECC(codes_get_double(handles[0], "iDirectionIncrementInDegrees", &inc_lon));
9433 ECC(codes_get_double(handles[0], "jDirectionIncrementInDegrees", &inc_lat));
9434
9435 long jscanpos, iscanneg;
9436 ECC(codes_get_long(handles[0], "iScansNegatively", &iscanneg));
9437 ECC(codes_get_long(handles[0], "jScansPositively", &jscanpos));
9438
9439 /* Compute longitude-latitude grid... */
9440 int counter = 0;
9441 if (iscanneg == 0)
9442 for (double i = first_lon; i <= last_lon + 1e-6; i += inc_lon) {
9443 met->lon[counter] = i;
9444 counter++;
9445 } else
9446 for (double i = first_lon; i > last_lon - 1e-6; i -= inc_lon) {
9447 met->lon[counter] = i;
9448 counter++;
9449 }
9450
9451 counter = 0;
9452 if (jscanpos == 0)
9453 for (double i = first_lat; i > last_lat - 1e-6; i -= inc_lat) {
9454 met->lat[counter] = i;
9455 counter++;
9456 } else
9457 for (double i = first_lat; i <= last_lat + 1e-6; i += inc_lat) {
9458 met->lat[counter] = i;
9459 counter++;
9460 }
9461
9462 /* Write info... */
9463 LOG(2, "Longitudes: %g, %g ... %g deg",
9464 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9465 LOG(2, "Latitudes: %g, %g ... %g deg",
9466 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9467
9468 /* Read vertical levels... */
9469 int max_level = 0;
9470 for (int i = 0; i < count_handles; i++) {
9471 long level;
9472 ECC(codes_get_long(handles[i], "level", &level));
9473 if (level > max_level)
9474 max_level = (int) level;
9475 }
9476 met->npl = max_level;
9477
9478 /* Check number of levels... */
9479 LOG(2, "Number of levels: %d", met->npl);
9480 if (met->npl < 2 || met->npl > EP)
9481 ERRMSG("Number of levels out of range!");
9482}
9483#endif
9484
9485/*****************************************************************************/
9486
9487#ifdef ECCODES
9489 codes_handle **handles,
9490 const int num_messages,
9491 const ctl_t *ctl,
9492 met_t *met) {
9493
9494 /* Set timer... */
9495 SELECT_TIMER("READ_MET_GRIB_LEVELS", "INPUT", NVTX_READ);
9496 LOG(2, "Read level data...");
9497
9498 /* Init... */
9499 int t_flag = 0, u_flag = 0, v_flag = 0, w_flag = 0, o3_flag = 0, h2o_flag =
9500 0, lwc_flag = 0, rwc_flag = 0, iwc_flag = 0, swc_flag = 0, cc_flag = 0;
9501
9502 /* Iterate over all messages... */
9503 for (int i = 0; i < num_messages; i++) {
9504
9505 size_t max_size = LEN;
9506 char short_name[max_size];
9507 size_t value_count;
9508 double *values;
9509
9510 /* Get the current level */
9511 long current_level;
9512 ECC(codes_get_long(handles[i], "level", &current_level));
9513 current_level -= 1;
9514
9515 /* Retrieve data from current message */
9516 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
9517 ECC(codes_get_size(handles[i], "values", &value_count));
9518 ALLOC(values, double,
9519 value_count);
9520 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
9521
9522 /* Read temperature... */
9523 ECC_READ_3D("t", current_level, met->t, 1.0, t_flag);
9524
9525 /* Read horizontal wind and vertical velocity... */
9526 ECC_READ_3D("u", current_level, met->u, 1.0, u_flag);
9527 ECC_READ_3D("v", current_level, met->v, 1.0, v_flag);
9528 ECC_READ_3D("w", current_level, met->w, 0.01f, w_flag);
9529
9530 /* Read water vapor and ozone... */
9531 ECC_READ_3D("q", current_level, met->h2o, (float) (MA / MH2O), h2o_flag);
9532 ECC_READ_3D("o3", current_level, met->o3, (float) (MA / MO3), o3_flag);
9533
9534 /* Read cloud data... */
9535 ECC_READ_3D("clwc", current_level, met->lwc, 1.0, lwc_flag);
9536 ECC_READ_3D("crwc", current_level, met->rwc, 1.0, rwc_flag);
9537 ECC_READ_3D("ciwc", current_level, met->iwc, 1.0, iwc_flag);
9538 ECC_READ_3D("cswc", current_level, met->swc, 1.0, swc_flag);
9539 ECC_READ_3D("cc", current_level, met->cc, 1.0, cc_flag);
9540
9541 /*Free allocated array */
9542 free(values);
9543 }
9544
9545 /* Check whether data were found... */
9546 if (t_flag != met->npl)
9547 ERRMSG("Cannot read temperature!");
9548 if (u_flag != met->npl)
9549 ERRMSG("Cannot read zonal wind!");
9550 if (v_flag != met->npl)
9551 ERRMSG("Cannot read meridional wind!");
9552 if (w_flag != met->npl)
9553 WARN("Cannot read vertical velocity!");
9554 if (h2o_flag != met->npl)
9555 WARN("Cannot read specific humidity!");
9556 if (o3_flag != met->npl)
9557 WARN("Cannot read ozone data!");
9558 if (lwc_flag != met->npl)
9559 WARN("Cannot read cloud liquid water content!");
9560 if (rwc_flag != met->npl)
9561 WARN("Cannot read cloud rain water content!");
9562 if (iwc_flag != met->npl)
9563 WARN("Cannot read cloud ice water content!");
9564 if (swc_flag != met->npl)
9565 WARN("Cannot read cloud snow water content!");
9566 if (cc_flag != met->npl)
9567 WARN("Cannot read cloud cover!");
9568
9569 /* Check ordering of pressure levels... */
9570 for (int ix = 0; ix < met->nx; ix++)
9571 for (int iy = 0; iy < met->ny; iy++)
9572 for (int ip = 1; ip < met->np; ip++)
9573 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
9574 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
9575 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
9576 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip])) {
9577 LOG(1, "%f %f %f %f", met->pl[ix][iy][0], met->pl[ix][iy][1],
9578 met->pl[ix][iy][ip - 1], met->pl[ix][iy][ip]);
9579 ERRMSG("Pressure profiles are not monotonic!");
9580 }
9581
9582 /* Interpolate from model levels to pressure levels... */
9583 if (ctl->met_np > 0) {
9584 met->np = ctl->met_np;
9585
9586 /* Interpolate variables... */
9587 read_met_ml2pl(ctl, met, met->t, "T");
9588 read_met_ml2pl(ctl, met, met->u, "U");
9589 read_met_ml2pl(ctl, met, met->v, "V");
9590 read_met_ml2pl(ctl, met, met->w, "W");
9591 read_met_ml2pl(ctl, met, met->h2o, "H2O");
9592 read_met_ml2pl(ctl, met, met->o3, "O3");
9593 read_met_ml2pl(ctl, met, met->lwc, "LWC");
9594 read_met_ml2pl(ctl, met, met->rwc, "RWC");
9595 read_met_ml2pl(ctl, met, met->iwc, "IWC");
9596 read_met_ml2pl(ctl, met, met->swc, "SWC");
9597 read_met_ml2pl(ctl, met, met->cc, "CC");
9598
9599 /* Set new pressure levels... */
9600 for (int ip = 0; ip < met->np; ip++)
9601 met->p[ip] = ctl->met_p[ip];
9602 }
9603
9604 /* Check ordering of pressure levels... */
9605 for (int ip = 1; ip < met->np; ip++)
9606 if (met->p[ip - 1] < met->p[ip])
9607 ERRMSG("Pressure levels must be descending!");
9608}
9609#endif
9610
9611/*****************************************************************************/
9612
9613#ifdef ECCODES
9615 codes_handle **handles,
9616 const int num_messages,
9617 const ctl_t *ctl,
9618 met_t *met) {
9619
9620 /* Set timer... */
9621 SELECT_TIMER("READ_MET_GRIB_SURFACE", "INPUT", NVTX_READ);
9622 LOG(2, "Read surface data...");
9623
9624 /* Init... */
9625 int sp_flag = 0, z_flag = 0, t_flag = 0, u_flag = 0, v_flag = 0, lsm_flag =
9626 0, sst_flag = 0, cape_flag = 0, cin_flag = 0, pbl_flag = 0;
9627
9628 /* Iterate over all messages... */
9629 for (int i = 0; i < num_messages; i++) {
9630
9631 size_t max_size = LEN, value_count;
9632
9633 char short_name[max_size];
9634
9635 /* Store values with shortname... */
9636 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
9637 ECC(codes_get_size(handles[i], "values", &value_count));
9638 double *values = (double *) malloc(value_count * sizeof(double));
9639 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
9640
9641 /*Read surface pressure... */
9642 ECC_READ_2D("sp", met->ps, 0.01f, sp_flag);
9643
9644 /*Read geopotential height at the surface... */
9645 ECC_READ_2D("z", met->zs, (float) (1. / (1000. * G0)), z_flag);
9646
9647 /* Read temperature at the surface... */
9648 ECC_READ_2D("2t", met->ts, 1.0f, t_flag);
9649
9650 /* Read zonal wind at the surface... */
9651 ECC_READ_2D("10u", met->us, 1.0f, u_flag);
9652
9653 /* Read meridional wind at the surface... */
9654 ECC_READ_2D("10v", met->vs, 1.0f, v_flag);
9655
9656 /* Read land-sea mask... */
9657 ECC_READ_2D("lsm", met->lsm, 1.0f, lsm_flag);
9658
9659 /* Read sea surface temperature... */
9660 ECC_READ_2D("sst", met->sst, 1.0f, sst_flag);
9661 if (ctl->met_cape == 0) {
9662
9663 /* Read CAPE... */
9664 ECC_READ_2D("cape", met->cape, 1.0f, cape_flag);
9665
9666 /* Read CIN... */
9667 ECC_READ_2D("cin", met->cin, 1.0f, cin_flag);
9668 }
9669
9670 /* Read PBL... */
9671 if (ctl->met_pbl == 0)
9672 ECC_READ_2D("blh", met->pbl, 0.0001f, pbl_flag);
9673 }
9674
9675 /* Check whether data have been read... */
9676 if (sp_flag == 0)
9677 WARN("Cannot read surface pressure data!");
9678 if (z_flag == 0)
9679 WARN("Cannot read surface geopotential height!");
9680 if (t_flag == 0)
9681 WARN("Cannot read surface temperature!");
9682 if (u_flag == 0)
9683 WARN("Cannot read surface zonal wind!");
9684 if (v_flag == 0)
9685 WARN("Cannot read surface meridional wind!");
9686 if (lsm_flag == 0)
9687 WARN("Cannot read land-sea mask!");
9688 if (sst_flag == 0)
9689 WARN("Cannot read sea surface temperature!");
9690 if (ctl->met_cape == 0) {
9691 if (cape_flag == 0)
9692 WARN("Cannot read CAPE!");
9693 if (cin_flag == 0)
9694 WARN("Cannot read convective inhibition!");
9695 }
9696 if (ctl->met_pbl == 0 && pbl_flag == 0)
9697 WARN("Cannot read planetary boundary layer!");
9698}
9699#endif
9700
9701/*****************************************************************************/
9702
9704 const ctl_t *ctl,
9705 const met_t *met,
9706 float var[EX][EY][EP],
9707 const char *varname) {
9708
9709 double aux[EP], p[EP];
9710
9711 /* Set timer... */
9712 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
9713 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
9714
9715 /* Loop over columns... */
9716#pragma omp parallel for default(shared) private(aux,p) collapse(2)
9717 for (int ix = 0; ix < met->nx; ix++)
9718 for (int iy = 0; iy < met->ny; iy++) {
9719
9720 /* Copy pressure profile... */
9721 for (int ip = 0; ip < met->np; ip++)
9722 p[ip] = met->pl[ix][iy][ip];
9723
9724 /* Interpolate... */
9725 for (int ip = 0; ip < ctl->met_np; ip++) {
9726 double pt = ctl->met_p[ip];
9727 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
9728 pt = p[0];
9729 else if ((pt > p[met->np - 1] && p[1] > p[0])
9730 || (pt < p[met->np - 1] && p[1] < p[0]))
9731 pt = p[met->np - 1];
9732 const int ip2 = locate_irr(p, met->np, pt);
9733 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
9734 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
9735 }
9736
9737 /* Copy data... */
9738 for (int ip = 0; ip < ctl->met_np; ip++)
9739 var[ix][iy][ip] = (float) aux[ip];
9740 }
9741}
9742
9743/*****************************************************************************/
9744
9746 const ctl_t *ctl,
9747 met_t *met) {
9748
9749 /* Check parameters... */
9750 if (ctl->advect_vert_coord != 1)
9751 return;
9752
9753 /* Set timer... */
9754 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
9755 LOG(2, "Make zeta profiles monotone...");
9756
9757 /* Create monotone zeta profiles... */
9758#pragma omp parallel for default(shared) collapse(2)
9759 for (int i = 0; i < met->nx; i++)
9760 for (int j = 0; j < met->ny; j++) {
9761 int k = 1;
9762
9763 while (k < met->npl) { /* Check if there is an inversion at level k... */
9764 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
9765 /* Find the upper level k+l over the inversion... */
9766 int l = 0;
9767 do {
9768 l++;
9769 }
9770 while ((met->zetal[i][j][k - 1] >=
9771 met->zetal[i][j][k + l]) & (k + l < met->npl));
9772
9773 /* Interpolate linear between the top and bottom
9774 of the inversion... */
9775 float s =
9776 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
9777 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9778
9779 for (int m = k; m < k + l; m++) {
9780 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9781 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
9782 }
9783
9784 /* Search for more inversions above the last inversion ... */
9785 k = k + l;
9786 } else {
9787 k++;
9788 }
9789 }
9790 }
9791
9792 /* Create monotone pressure profiles... */
9793#pragma omp parallel for default(shared) collapse(2)
9794 for (int i = 0; i < met->nx; i++)
9795 for (int j = 0; j < met->ny; j++) {
9796 int k = 1;
9797
9798 while (k < met->npl) { /* Check if there is an inversion at level k... */
9799 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
9800
9801 /* Find the upper level k+l over the inversion... */
9802 int l = 0;
9803 do {
9804 l++;
9805 }
9806 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
9807 met->npl));
9808
9809 /* Interpolate linear between the top and bottom
9810 of the inversion... */
9811 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
9812 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9813
9814 for (int m = k; m < k + l; m++) {
9815 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9816 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
9817 }
9818
9819 /* Search for more inversions above the last inversion ... */
9820 k += l;
9821 } else {
9822 k++;
9823 }
9824 }
9825 }
9826}
9827
9828/*****************************************************************************/
9829
9831 const char *filename,
9832 const ctl_t *ctl,
9833 met_t *met,
9834 dd_t *dd) {
9835
9836 int ncid;
9837
9838 /* Open file... */
9839#ifdef DD
9840 if (ctl->dd) {
9841 NC(nc_open_par
9842 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
9843 &ncid))
9844 }
9845#else
9846 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
9847 WARN("Cannot open file!");
9848 return 0;
9849 }
9850#endif
9851
9852 /* Read coordinates of meteo data... */
9853 read_met_nc_grid(filename, ncid, ctl, met, dd);
9854
9855 /* Read surface data... */
9856 read_met_nc_surface(ncid, ctl, met, dd);
9857
9858 /* Read meteo data on vertical levels... */
9859 read_met_nc_levels(ncid, ctl, met, dd);
9860
9861 /* Close file... */
9862 NC(nc_close(ncid));
9863
9864 /* Return success... */
9865 return 1;
9866}
9867
9868/*****************************************************************************/
9869
9871 dd_t *dd,
9872 const ctl_t *ctl,
9873 met_t *met,
9874 const int ncid) {
9875
9876 int varid;
9877
9878 /* Get the MPI information... */
9879#ifdef MPI
9880 MPI_Comm_rank(MPI_COMM_WORLD, &dd->rank);
9881 MPI_Comm_size(MPI_COMM_WORLD, &dd->size);
9882#endif
9883
9884 int help_nx_glob;
9885 int help_ny_glob;
9886
9887 /* Get grid dimensions... */
9888 NC_INQ_DIM("lon", &help_nx_glob, 0, 0, 0);
9889 LOG(2, "Number of longitudes: %d", help_nx_glob);
9890 met->nx = (int) floor(help_nx_glob / ctl->dd_subdomains_zonal);
9891
9892 NC_INQ_DIM("lat", &help_ny_glob, 0, 0, 0);
9893 LOG(2, "Number of latitudes: %d", help_ny_glob);
9894 met->ny = (int) floor(help_ny_glob / ctl->dd_subdomains_meridional);
9895
9896 double *help_lon_glob;
9897 double *help_lat_glob;
9898 ALLOC(help_lon_glob, double,
9899 help_nx_glob);
9900 ALLOC(help_lat_glob, double,
9901 help_ny_glob);
9902
9903 /* Read global longitudes and latitudes... */
9904 NC_GET_DOUBLE("lon", help_lon_glob, 1);
9905 LOG(2, "Longitudes: %g, %g ... %g deg",
9906 help_lon_glob[0], help_lon_glob[1], help_lon_glob[help_nx_glob - 1]);
9907 NC_GET_DOUBLE("lat", help_lat_glob, 1);
9908 LOG(2, "Latitudes: %g, %g ... %g deg",
9909 help_lat_glob[0], help_lat_glob[1], help_lat_glob[help_ny_glob - 1]);
9910
9911 /* Determine hyperslabs for reading the data in parallel... */
9912
9913 /* Check for edge cases... */
9914 int left = (dd->rank <= ctl->dd_subdomains_meridional - 1);
9915 int right = (dd->rank >= dd->size - ctl->dd_subdomains_meridional);
9916 int top = (dd->rank % ctl->dd_subdomains_meridional == 0);
9917 int bottom =
9918 (dd->rank % ctl->dd_subdomains_meridional ==
9919 ctl->dd_subdomains_meridional - 1);
9920
9921 /* Set the hyperslab for the subdomain... */
9922 dd->subdomain_start[0] = 0;
9923 dd->subdomain_start[1] = 0;
9924 dd->subdomain_start[2] =
9925 (size_t) ((dd->rank % ctl->dd_subdomains_meridional) * met->ny);
9926 dd->subdomain_start[3] =
9927 (size_t) (floor(dd->rank / ctl->dd_subdomains_meridional) * met->nx);
9928
9929 /* Extend subdomains at the right and bottom to fit the full domain. */
9930 if (right) {
9931 int gap = help_nx_glob - ctl->dd_subdomains_zonal * met->nx;
9932 if (gap > 0) {
9933 met->nx = met->nx + gap;
9934 WARN("Extended subdomains at the right to fit to full domain.");
9935 }
9936 }
9937 if (bottom) {
9938 int gap = help_ny_glob - ctl->dd_subdomains_meridional * met->ny;
9939 if (gap > 0) {
9940 met->ny = met->ny + gap;
9941 WARN("Extended subdomains at the bottom to fit to full domain.");
9942 }
9943 }
9944
9945 /* Block-size, i.e. count */
9946 dd->subdomain_count[0] = 1;
9947 dd->subdomain_count[1] = (size_t) met->np;
9948 dd->subdomain_count[2] = (size_t) met->ny;
9949 dd->subdomain_count[3] = (size_t) met->nx;
9950
9951 /* Create halos and include them into the subdomain... */
9952 if (!left && !right) {
9953 // If we are not at the left or right edge extend in zonal direction...
9954 // Move the start one point to the left...
9955 dd->subdomain_count[3] =
9956 dd->subdomain_count[3] + (size_t) (ctl->dd_halos_size * 2);
9957 dd->subdomain_start[3] =
9958 dd->subdomain_start[3] - (size_t) ctl->dd_halos_size;
9959 } else {
9960 // If we are at the left or right edge, extend only in one zonal direction...
9961 dd->subdomain_count[3] =
9962 dd->subdomain_count[3] + (size_t) ctl->dd_halos_size;
9963 if (!left)
9964 // If we are not at the left edge, move the start to the left...
9965 dd->subdomain_start[3] =
9966 dd->subdomain_start[3] - (size_t) ctl->dd_halos_size;
9967 }
9968
9969 if (!top && !bottom) {
9970 // If we are not at the upper or lower edge extend in meridional direction...
9971 // Move the start point one point down...
9972 dd->subdomain_count[2] =
9973 dd->subdomain_count[2] + (size_t) (ctl->dd_halos_size * 2);
9974 dd->subdomain_start[2] =
9975 dd->subdomain_start[2] - (size_t) ctl->dd_halos_size;
9976 } else {
9977 // If we are at the top or the lower edge only extend in one mer. direction...
9978 dd->subdomain_count[2] =
9979 dd->subdomain_count[2] + (size_t) ctl->dd_halos_size;
9980 if (!top)
9981 // If we are not at the top, move the start one upward...
9982 dd->subdomain_start[2] =
9983 dd->subdomain_start[2] - (size_t) ctl->dd_halos_size;
9984 }
9985
9986 /* Set boundary halo hyperslabs ... */
9987 double lon_shift = 0;
9988 if (left || right) {
9989
9990 met->nx = met->nx + ctl->dd_halos_size;
9991
9992 dd->halo_bnd_start[0] = 0;
9993 dd->halo_bnd_start[1] = 0;
9994 dd->halo_bnd_start[3] = (size_t) (left ? (help_nx_glob - ctl->dd_halos_size) : (0)); //x
9995 dd->halo_bnd_start[2] = dd->subdomain_start[2]; //y
9996
9997 dd->halo_bnd_count[0] = 1;
9998 dd->halo_bnd_count[1] = (size_t) met->np;
9999 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
10000 dd->halo_bnd_count[2] =
10001 (size_t) met->ny +
10002 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
10003
10004 dd->halo_offset_start = (left ? (int) dd->halo_bnd_count[3] : 0);
10005 dd->halo_offset_end = (left ? 0 : (int) dd->subdomain_count[3]);
10006 lon_shift = (left ? -360 : 360);
10007
10008 } else {
10009
10010 dd->halo_bnd_start[0] = 0;
10011 dd->halo_bnd_start[1] = 0;
10012 dd->halo_bnd_start[3] = 0;
10013 dd->halo_bnd_start[2] = 0;
10014
10015 dd->halo_bnd_count[0] = 0;
10016 dd->halo_bnd_count[1] = 0;
10017 dd->halo_bnd_count[3] = 0;
10018 dd->halo_bnd_count[2] = 0;
10019 }
10020
10021 /* Get the range of the entire meteodata... */
10022 /* Handle both periodic (global) and non-periodic (regional) longitude grids */
10023 double lon_range = 360;
10024 //if (dd_is_periodic_longitude(met, help_nx_glob)) {
10025 /* For global grids with periodic boundaries, use full 360 degrees */
10026 //lon_range = 360.0;
10027 //LOG(3, "Detected periodic longitude boundaries, using lon_range = 360.0");
10028 //} else {
10029 /* For regional grids, use the actual data range */
10030 //lon_range = help_lon_glob[help_nx_glob - 1] - help_lon_glob[0];
10031 //LOG(3, "Detected non-periodic longitude boundaries, using lon_range = %g", lon_range);
10032 //}
10033
10034 double lat_range = help_lat_glob[help_ny_glob - 1] - help_lat_glob[0];
10035
10036 /* Focus on subdomain latitudes and longitudes... */
10037 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10038 met->lat[iy] = help_lat_glob[(int) dd->subdomain_start[2] + iy];
10039
10040 /* Focus on subdomain longitudes... */
10041 /* Keep space at the beginning or end of the array for halo... */
10042 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
10043 met->lon[ix + dd->halo_offset_start] =
10044 help_lon_glob[(int) dd->subdomain_start[3] + ix];
10045
10046 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
10047 met->lon[ix + dd->halo_offset_end] =
10048 help_lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
10049
10050 /* Reset the grid dimensions... */
10051 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
10052 met->ny = (int) dd->subdomain_count[2];
10053
10054 /* Determine subdomain edges... */
10055 dd->subdomain_lon_min = floor(dd->rank / ctl->dd_subdomains_meridional)
10056 * (lon_range) / (double) ctl->dd_subdomains_zonal;
10058 + (lon_range) / (double) ctl->dd_subdomains_zonal;
10059
10060 /* Latitudes in descending order (90 to -90) */
10061 if (lat_range < 0) {
10062 dd->subdomain_lat_max = 90 + (dd->rank % ctl->dd_subdomains_meridional)
10063 * (lat_range) / (double) ctl->dd_subdomains_meridional;
10065 + (lat_range) / (double) ctl->dd_subdomains_meridional;
10066 } else {
10067 WARN
10068 ("lat_range > 0, but is expected to be negative, i.e. latitudes should range from 90 to -90")
10069 dd->subdomain_lat_min = -90 + (dd->rank % ctl->dd_subdomains_meridional)
10070 * (lat_range) / (double) ctl->dd_subdomains_meridional;
10072 + (lat_range) / (double) ctl->dd_subdomains_meridional;
10073 }
10074
10075 LOG(2, "Total longitude range: %g deg", lon_range);
10076 LOG(2, "Total latitude range: %g deg", lat_range);
10077
10078 LOG(2, "Define subdomain properties.");
10079 LOG(2, "MPI information: Rank %d, Size %d", dd->rank, dd->size);
10080 LOG(2, "Edge position: l=%d,r=%d,t=%d, b=%d", (int) left, (int) right,
10081 (int) top, (int) bottom);
10082 LOG(2, "Sizes for limits: EX %d EY %d EP %d", EX, EY, EP);
10083 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d", met->nx,
10084 met->ny, met->np);
10085 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
10086 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
10087 (int) dd->halo_bnd_count[1]);
10088 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
10089 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
10090 (int) dd->subdomain_count[1]);
10091 LOG(2, "Subdomain start: nx %ld ny %ld np %ld", dd->subdomain_start[3],
10092 dd->subdomain_start[2], dd->subdomain_start[1]);
10093 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld", dd->halo_bnd_start[3],
10094 dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
10095 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
10096
10097 LOG(2, " %d Subdomain longitudes: %g, %g ... %g deg (edges: %g to %g)",
10098 dd->rank, met->lon[0], met->lon[1], met->lon[met->nx - 1],
10100 LOG(2, " %d Subdomain latitudes: %g, %g ... %g deg (edges: %g to %g)",
10101 dd->rank, met->lat[0], met->lat[1], met->lat[met->ny - 1],
10103
10104 free(help_lon_glob);
10105 free(help_lat_glob);
10106}
10107
10108/*****************************************************************************/
10109
10111 const ctl_t *ctl,
10112 met_t *met) {
10113
10114 /* Set timer... */
10115 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
10116 LOG(2, "Calculate planetary boundary layer...");
10117
10118 /* Convert PBL height from meteo file to pressure... */
10119 if (ctl->met_pbl == 1) {
10120
10121 /* Loop over grid points... */
10122#pragma omp parallel for default(shared) collapse(2)
10123 for (int ix = 0; ix < met->nx; ix++)
10124 for (int iy = 0; iy < met->ny; iy++) {
10125
10126 /* Get pressure at top of PBL... */
10127 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
10128 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
10129 met->pbl[ix][iy] =
10130 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
10131 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
10132 }
10133 }
10134
10135 /* Determine PBL based on Richardson number... */
10136 else if (ctl->met_pbl == 2) {
10137
10138 /* Parameters used to estimate the height of the PBL
10139 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
10140 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
10141
10142 /* Loop over grid points... */
10143#pragma omp parallel for default(shared) collapse(2)
10144 for (int ix = 0; ix < met->nx; ix++)
10145 for (int iy = 0; iy < met->ny; iy++) {
10146
10147 /* Set bottom level of PBL... */
10148 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
10149
10150 /* Find lowest level near the bottom... */
10151 int ip;
10152 for (ip = 1; ip < met->np; ip++)
10153 if (met->p[ip] < pbl_bot)
10154 break;
10155
10156 /* Get near surface data... */
10157 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
10158 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
10159 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
10160
10161 /* Init... */
10162 double rib_old = 0;
10163
10164 /* Loop over levels... */
10165 for (; ip < met->np; ip++) {
10166
10167 /* Get squared horizontal wind speed... */
10168 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
10169 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
10170 vh2 = MAX(vh2, SQR(umin));
10171
10172 /* Calculate bulk Richardson number... */
10173 const double rib =
10174 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
10175 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
10176 met->h2o[ix][iy][ip]) - tvs) / vh2;
10177
10178 /* Check for critical value... */
10179 if (rib >= rib_crit) {
10180 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
10181 rib, met->p[ip], rib_crit));
10182 if (met->pbl[ix][iy] > pbl_bot)
10183 met->pbl[ix][iy] = (float) pbl_bot;
10184 break;
10185 }
10186
10187 /* Save Richardson number... */
10188 rib_old = rib;
10189 }
10190 }
10191 }
10192
10193 /* Determine PBL based on potential temperature... */
10194 if (ctl->met_pbl == 3) {
10195
10196 /* Parameters used to estimate the height of the PBL
10197 (following HYSPLIT model)... */
10198 const double dtheta = 2.0, zmin = 0.1;
10199
10200 /* Loop over grid points... */
10201#pragma omp parallel for default(shared) collapse(2)
10202 for (int ix = 0; ix < met->nx; ix++)
10203 for (int iy = 0; iy < met->ny; iy++) {
10204
10205 /* Potential temperature at the surface... */
10206 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
10207
10208 /* Find topmost level where theta exceeds surface value by 2 K... */
10209 int ip;
10210 for (ip = met->np - 2; ip > 0; ip--)
10211 if (met->p[ip] >= 300.)
10212 if (met->p[ip] > met->ps[ix][iy]
10213 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
10214 break;
10215
10216 /* Interpolate... */
10217 met->pbl[ix][iy]
10218 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
10219 met->p[ip + 1],
10220 THETA(met->p[ip], met->t[ix][iy][ip]),
10221 met->p[ip], theta0 + dtheta));
10222
10223 /* Check minimum value... */
10224 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
10225 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
10226 met->pbl[ix][iy] = (float) pbl_min;
10227 }
10228 }
10229
10230 /* Loop over grid points... */
10231#pragma omp parallel for default(shared) collapse(2)
10232 for (int ix = 0; ix < met->nx; ix++)
10233 for (int iy = 0; iy < met->ny; iy++) {
10234
10235 /* Check minimum value... */
10236 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
10237 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
10238
10239 /* Check maximum value... */
10240 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
10241 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
10242 }
10243}
10244
10245/*****************************************************************************/
10246
10248 met_t *met) {
10249
10250 /* Set timer... */
10251 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
10252 LOG(2, "Apply periodic boundary conditions...");
10253
10254 /* Check longitudes... */
10255 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
10256 + met->lon[1] - met->lon[0] - 360) < 0.01))
10257 return;
10258
10259 /* Increase longitude counter... */
10260 if ((++met->nx) >= EX)
10261 ERRMSG("Cannot create periodic boundary conditions!");
10262
10263 /* Set longitude... */
10264 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
10265
10266 /* Loop over latitudes and pressure levels... */
10267#pragma omp parallel for default(shared)
10268 for (int iy = 0; iy < met->ny; iy++) {
10269 met->ps[met->nx - 1][iy] = met->ps[0][iy];
10270 met->zs[met->nx - 1][iy] = met->zs[0][iy];
10271 met->ts[met->nx - 1][iy] = met->ts[0][iy];
10272 met->us[met->nx - 1][iy] = met->us[0][iy];
10273 met->vs[met->nx - 1][iy] = met->vs[0][iy];
10274 met->ess[met->nx - 1][iy] = met->ess[0][iy];
10275 met->nss[met->nx - 1][iy] = met->nss[0][iy];
10276 met->shf[met->nx - 1][iy] = met->shf[0][iy];
10277 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
10278 met->sst[met->nx - 1][iy] = met->sst[0][iy];
10279 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
10280 met->cape[met->nx - 1][iy] = met->cape[0][iy];
10281 met->cin[met->nx - 1][iy] = met->cin[0][iy];
10282 for (int ip = 0; ip < met->np; ip++) {
10283 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
10284 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
10285 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
10286 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
10287 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
10288 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
10289 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
10290 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
10291 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
10292 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
10293 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
10294 }
10295 for (int ip = 0; ip < met->npl; ip++) {
10296 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
10297 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
10298 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
10299 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
10300 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
10301 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
10302 }
10303 }
10304}
10305
10306/*****************************************************************************/
10307
10309 met_t *met) {
10310
10311 /* Set timer... */
10312 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
10313 LOG(2, "Apply fix for polar winds...");
10314
10315 /* Check latitudes... */
10316 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
10317 return;
10318
10319 /* Loop over hemispheres... */
10320 for (int ihem = 0; ihem < 2; ihem++) {
10321
10322 /* Set latitude indices... */
10323 int i89 = 1, i90 = 0, sign = 1;
10324 if (ihem == 1) {
10325 i89 = met->ny - 2;
10326 i90 = met->ny - 1;
10327 }
10328 if (met->lat[i90] < 0)
10329 sign = -1;
10330
10331 /* Look-up table of cosinus and sinus... */
10332 double clon[EX], slon[EX];
10333#pragma omp parallel for default(shared)
10334 for (int ix = 0; ix < met->nx; ix++) {
10335 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
10336 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
10337 }
10338
10339 /* Loop over levels... */
10340#pragma omp parallel for default(shared)
10341 for (int ip = 0; ip < met->np; ip++) {
10342
10343 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
10344 double vel89x = 0, vel89y = 0;
10345 for (int ix = 0; ix < met->nx; ix++) {
10346 vel89x +=
10347 (met->u[ix][i89][ip] * clon[ix] -
10348 met->v[ix][i89][ip] * slon[ix]) / met->nx;
10349 vel89y +=
10350 (met->u[ix][i89][ip] * slon[ix] +
10351 met->v[ix][i89][ip] * clon[ix]) / met->nx;
10352 }
10353
10354 /* Replace 90 degree winds by 89 degree mean... */
10355 for (int ix = 0; ix < met->nx; ix++) {
10356 met->u[ix][i90][ip]
10357 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
10358 met->v[ix][i90][ip]
10359 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
10360 }
10361 }
10362 }
10363}
10364
10365/*****************************************************************************/
10366
10368 met_t *met) {
10369
10370 double pows[EP];
10371
10372 /* Set timer... */
10373 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
10374 LOG(2, "Calculate potential vorticity...");
10375
10376 /* Set powers... */
10377#pragma omp parallel for default(shared)
10378 for (int ip = 0; ip < met->np; ip++)
10379 pows[ip] = pow(1000. / met->p[ip], 0.286);
10380
10381 /* Loop over grid points... */
10382#pragma omp parallel for default(shared)
10383 for (int ix = 0; ix < met->nx; ix++) {
10384
10385 /* Set indices... */
10386 const int ix0 = MAX(ix - 1, 0);
10387 const int ix1 = MIN(ix + 1, met->nx - 1);
10388
10389 /* Loop over grid points... */
10390 for (int iy = 0; iy < met->ny; iy++) {
10391
10392 /* Set indices... */
10393 const int iy0 = MAX(iy - 1, 0);
10394 const int iy1 = MIN(iy + 1, met->ny - 1);
10395
10396 /* Set auxiliary variables... */
10397 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
10398 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
10399 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
10400 const double c0 = cos(DEG2RAD(met->lat[iy0]));
10401 const double c1 = cos(DEG2RAD(met->lat[iy1]));
10402 const double cr = cos(DEG2RAD(latr));
10403 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
10404
10405 /* Loop over grid points... */
10406 for (int ip = 0; ip < met->np; ip++) {
10407
10408 /* Get gradients in longitude... */
10409 const double dtdx
10410 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
10411 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
10412
10413 /* Get gradients in latitude... */
10414 const double dtdy
10415 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
10416 const double dudy
10417 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
10418
10419 /* Set indices... */
10420 const int ip0 = MAX(ip - 1, 0);
10421 const int ip1 = MIN(ip + 1, met->np - 1);
10422
10423 /* Get gradients in pressure... */
10424 double dtdp, dudp, dvdp;
10425 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
10426 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
10427 if (ip != ip0 && ip != ip1) {
10428 double denom = dp0 * dp1 * (dp0 + dp1);
10429 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
10430 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
10431 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
10432 / denom;
10433 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
10434 - dp1 * dp1 * met->u[ix][iy][ip0]
10435 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
10436 / denom;
10437 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
10438 - dp1 * dp1 * met->v[ix][iy][ip0]
10439 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
10440 / denom;
10441 } else {
10442 const double denom = dp0 + dp1;
10443 dtdp =
10444 (met->t[ix][iy][ip1] * pows[ip1] -
10445 met->t[ix][iy][ip0] * pows[ip0]) / denom;
10446 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
10447 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
10448 }
10449
10450 /* Calculate PV... */
10451 met->pv[ix][iy][ip] = (float)
10452 (1e6 * G0 *
10453 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
10454 }
10455 }
10456 }
10457
10458 /* Fix for polar regions... */
10459#pragma omp parallel for default(shared)
10460 for (int ix = 0; ix < met->nx; ix++)
10461 for (int ip = 0; ip < met->np; ip++) {
10462 met->pv[ix][0][ip]
10463 = met->pv[ix][1][ip]
10464 = met->pv[ix][2][ip];
10465 met->pv[ix][met->ny - 1][ip]
10466 = met->pv[ix][met->ny - 2][ip]
10467 = met->pv[ix][met->ny - 3][ip];
10468 }
10469}
10470
10471/*****************************************************************************/
10472
10474 met_t *met) {
10475
10476 /* Set timer... */
10477 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
10478 LOG(2, "Calculate total column ozone...");
10479
10480 /* Loop over columns... */
10481#pragma omp parallel for default(shared) collapse(2)
10482 for (int ix = 0; ix < met->nx; ix++)
10483 for (int iy = 0; iy < met->ny; iy++) {
10484
10485 /* Integrate... */
10486 double cd = 0;
10487 for (int ip = 1; ip < met->np; ip++)
10488 if (met->p[ip - 1] <= met->ps[ix][iy]) {
10489 const double vmr =
10490 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
10491 const double dp = met->p[ip - 1] - met->p[ip];
10492 cd += vmr * MO3 / MA * dp * 1e2 / G0;
10493 }
10494
10495 /* Convert to Dobson units... */
10496 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
10497 }
10498}
10499
10500/*****************************************************************************/
10501
10503 const ctl_t *ctl,
10504 met_t *met) {
10505
10506 met_t *help;
10507
10508 /* Check parameters... */
10509 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
10510 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
10511 return;
10512
10513 /* Set timer... */
10514 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
10515 LOG(2, "Downsampling of meteo data...");
10516
10517 /* Allocate... */
10518 ALLOC(help, met_t, 1);
10519
10520 /* Copy data... */
10521 help->nx = met->nx;
10522 help->ny = met->ny;
10523 help->np = met->np;
10524 memcpy(help->lon, met->lon, sizeof(met->lon));
10525 memcpy(help->lat, met->lat, sizeof(met->lat));
10526 memcpy(help->p, met->p, sizeof(met->p));
10527
10528 /* Smoothing... */
10529 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
10530 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
10531 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
10532 help->ps[ix][iy] = 0;
10533 help->zs[ix][iy] = 0;
10534 help->ts[ix][iy] = 0;
10535 help->us[ix][iy] = 0;
10536 help->vs[ix][iy] = 0;
10537 help->ess[ix][iy] = 0;
10538 help->nss[ix][iy] = 0;
10539 help->shf[ix][iy] = 0;
10540 help->lsm[ix][iy] = 0;
10541 help->sst[ix][iy] = 0;
10542 help->pbl[ix][iy] = 0;
10543 help->cape[ix][iy] = 0;
10544 help->cin[ix][iy] = 0;
10545 help->t[ix][iy][ip] = 0;
10546 help->u[ix][iy][ip] = 0;
10547 help->v[ix][iy][ip] = 0;
10548 help->w[ix][iy][ip] = 0;
10549 help->h2o[ix][iy][ip] = 0;
10550 help->o3[ix][iy][ip] = 0;
10551 help->lwc[ix][iy][ip] = 0;
10552 help->rwc[ix][iy][ip] = 0;
10553 help->iwc[ix][iy][ip] = 0;
10554 help->swc[ix][iy][ip] = 0;
10555 help->cc[ix][iy][ip] = 0;
10556 float wsum = 0;
10557 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
10558 ix2++) {
10559 int ix3 = ix2;
10560 if (ix3 < 0)
10561 ix3 += met->nx;
10562 else if (ix3 >= met->nx)
10563 ix3 -= met->nx;
10564
10565 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
10566 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
10567 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
10568 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
10569 const float w =
10570 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
10571 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
10572 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
10573 help->ps[ix][iy] += w * met->ps[ix3][iy2];
10574 help->zs[ix][iy] += w * met->zs[ix3][iy2];
10575 help->ts[ix][iy] += w * met->ts[ix3][iy2];
10576 help->us[ix][iy] += w * met->us[ix3][iy2];
10577 help->vs[ix][iy] += w * met->vs[ix3][iy2];
10578 help->ess[ix][iy] += w * met->ess[ix3][iy2];
10579 help->nss[ix][iy] += w * met->nss[ix3][iy2];
10580 help->shf[ix][iy] += w * met->shf[ix3][iy2];
10581 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
10582 help->sst[ix][iy] += w * met->sst[ix3][iy2];
10583 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
10584 help->cape[ix][iy] += w * met->cape[ix3][iy2];
10585 help->cin[ix][iy] += w * met->cin[ix3][iy2];
10586 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
10587 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
10588 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
10589 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
10590 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
10591 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
10592 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
10593 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
10594 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
10595 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
10596 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
10597 wsum += w;
10598 }
10599 }
10600 help->ps[ix][iy] /= wsum;
10601 help->zs[ix][iy] /= wsum;
10602 help->ts[ix][iy] /= wsum;
10603 help->us[ix][iy] /= wsum;
10604 help->vs[ix][iy] /= wsum;
10605 help->ess[ix][iy] /= wsum;
10606 help->nss[ix][iy] /= wsum;
10607 help->shf[ix][iy] /= wsum;
10608 help->lsm[ix][iy] /= wsum;
10609 help->sst[ix][iy] /= wsum;
10610 help->pbl[ix][iy] /= wsum;
10611 help->cape[ix][iy] /= wsum;
10612 help->cin[ix][iy] /= wsum;
10613 help->t[ix][iy][ip] /= wsum;
10614 help->u[ix][iy][ip] /= wsum;
10615 help->v[ix][iy][ip] /= wsum;
10616 help->w[ix][iy][ip] /= wsum;
10617 help->h2o[ix][iy][ip] /= wsum;
10618 help->o3[ix][iy][ip] /= wsum;
10619 help->lwc[ix][iy][ip] /= wsum;
10620 help->rwc[ix][iy][ip] /= wsum;
10621 help->iwc[ix][iy][ip] /= wsum;
10622 help->swc[ix][iy][ip] /= wsum;
10623 help->cc[ix][iy][ip] /= wsum;
10624 }
10625 }
10626 }
10627
10628 /* Downsampling... */
10629 met->nx = 0;
10630 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
10631 met->lon[met->nx] = help->lon[ix];
10632 met->ny = 0;
10633 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
10634 met->lat[met->ny] = help->lat[iy];
10635 met->ps[met->nx][met->ny] = help->ps[ix][iy];
10636 met->zs[met->nx][met->ny] = help->zs[ix][iy];
10637 met->ts[met->nx][met->ny] = help->ts[ix][iy];
10638 met->us[met->nx][met->ny] = help->us[ix][iy];
10639 met->vs[met->nx][met->ny] = help->vs[ix][iy];
10640 met->ess[met->nx][met->ny] = help->ess[ix][iy];
10641 met->nss[met->nx][met->ny] = help->nss[ix][iy];
10642 met->shf[met->nx][met->ny] = help->shf[ix][iy];
10643 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
10644 met->sst[met->nx][met->ny] = help->sst[ix][iy];
10645 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
10646 met->cape[met->nx][met->ny] = help->cape[ix][iy];
10647 met->cin[met->nx][met->ny] = help->cin[ix][iy];
10648 met->np = 0;
10649 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
10650 met->p[met->np] = help->p[ip];
10651 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
10652 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
10653 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
10654 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
10655 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
10656 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
10657 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
10658 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
10659 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
10660 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
10661 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
10662 met->np++;
10663 }
10664 met->ny++;
10665 }
10666 met->nx++;
10667 }
10668
10669 /* Free... */
10670 free(help);
10671}
10672
10673/*****************************************************************************/
10674
10676 const ctl_t *ctl,
10677 const clim_t *clim,
10678 met_t *met) {
10679
10680 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
10681 th2[200], z[EP], z2[200];
10682
10683 /* Set timer... */
10684 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
10685 LOG(2, "Calculate tropopause...");
10686
10687 /* Get altitude and pressure profiles... */
10688#pragma omp parallel for default(shared)
10689 for (int iz = 0; iz < met->np; iz++)
10690 z[iz] = Z(met->p[iz]);
10691#pragma omp parallel for default(shared)
10692 for (int iz = 0; iz <= 190; iz++) {
10693 z2[iz] = 4.5 + 0.1 * iz;
10694 p2[iz] = P(z2[iz]);
10695 }
10696
10697 /* Do not calculate tropopause... */
10698 if (ctl->met_tropo == 0)
10699#pragma omp parallel for default(shared) collapse(2)
10700 for (int ix = 0; ix < met->nx; ix++)
10701 for (int iy = 0; iy < met->ny; iy++)
10702 met->pt[ix][iy] = NAN;
10703
10704 /* Use tropopause climatology... */
10705 else if (ctl->met_tropo == 1) {
10706#pragma omp parallel for default(shared) collapse(2)
10707 for (int ix = 0; ix < met->nx; ix++)
10708 for (int iy = 0; iy < met->ny; iy++)
10709 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
10710 }
10711
10712 /* Use cold point... */
10713 else if (ctl->met_tropo == 2) {
10714
10715 /* Loop over grid points... */
10716#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10717 for (int ix = 0; ix < met->nx; ix++)
10718 for (int iy = 0; iy < met->ny; iy++) {
10719
10720 /* Interpolate temperature profile... */
10721 for (int iz = 0; iz < met->np; iz++)
10722 t[iz] = met->t[ix][iy][iz];
10723 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
10724
10725 /* Find minimum... */
10726 int iz = (int) gsl_stats_min_index(t2, 1, 171);
10727 if (iz > 0 && iz < 170)
10728 met->pt[ix][iy] = (float) p2[iz];
10729 else
10730 met->pt[ix][iy] = NAN;
10731 }
10732 }
10733
10734 /* Use WMO definition... */
10735 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
10736
10737 /* Loop over grid points... */
10738#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10739 for (int ix = 0; ix < met->nx; ix++)
10740 for (int iy = 0; iy < met->ny; iy++) {
10741
10742 /* Interpolate temperature profile... */
10743 int iz;
10744 for (iz = 0; iz < met->np; iz++)
10745 t[iz] = met->t[ix][iy][iz];
10746 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
10747
10748 /* Find 1st tropopause... */
10749 met->pt[ix][iy] = NAN;
10750 for (iz = 0; iz <= 170; iz++) {
10751 int found = 1;
10752 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10753 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10754 found = 0;
10755 break;
10756 }
10757 if (found) {
10758 if (iz > 0 && iz < 170)
10759 met->pt[ix][iy] = (float) p2[iz];
10760 break;
10761 }
10762 }
10763
10764 /* Find 2nd tropopause... */
10765 if (ctl->met_tropo == 4) {
10766 met->pt[ix][iy] = NAN;
10767 for (; iz <= 170; iz++) {
10768 int found = 1;
10769 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
10770 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
10771 found = 0;
10772 break;
10773 }
10774 if (found)
10775 break;
10776 }
10777 for (; iz <= 170; iz++) {
10778 int found = 1;
10779 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10780 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10781 found = 0;
10782 break;
10783 }
10784 if (found) {
10785 if (iz > 0 && iz < 170)
10786 met->pt[ix][iy] = (float) p2[iz];
10787 break;
10788 }
10789 }
10790 }
10791 }
10792 }
10793
10794 /* Use dynamical tropopause... */
10795 else if (ctl->met_tropo == 5) {
10796
10797 /* Loop over grid points... */
10798#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
10799 for (int ix = 0; ix < met->nx; ix++)
10800 for (int iy = 0; iy < met->ny; iy++) {
10801
10802 /* Interpolate potential vorticity profile... */
10803 for (int iz = 0; iz < met->np; iz++)
10804 pv[iz] = met->pv[ix][iy][iz];
10805 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
10806
10807 /* Interpolate potential temperature profile... */
10808 for (int iz = 0; iz < met->np; iz++)
10809 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
10810 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
10811
10812 /* Find dynamical tropopause... */
10813 met->pt[ix][iy] = NAN;
10814 for (int iz = 0; iz <= 170; iz++)
10815 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
10816 || th2[iz] >= ctl->met_tropo_theta) {
10817 if (iz > 0 && iz < 170)
10818 met->pt[ix][iy] = (float) p2[iz];
10819 break;
10820 }
10821 }
10822 }
10823
10824 else
10825 ERRMSG("Cannot calculate tropopause!");
10826
10827 /* Interpolate temperature, geopotential height, and water vapor... */
10828#pragma omp parallel for default(shared) collapse(2)
10829 for (int ix = 0; ix < met->nx; ix++)
10830 for (int iy = 0; iy < met->ny; iy++) {
10831 double h2ot, tt, zt;
10833 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
10834 met->lat[iy], &tt, ci, cw, 1);
10835 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
10836 met->lat[iy], &zt, ci, cw, 0);
10837 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
10838 met->lat[iy], &h2ot, ci, cw, 0);
10839 met->tt[ix][iy] = (float) tt;
10840 met->zt[ix][iy] = (float) zt;
10841 met->h2ot[ix][iy] = (float) h2ot;
10842 }
10843}
10844
10845/*****************************************************************************/
10846
10848 const char *filename,
10849 const ctl_t *ctl,
10850 double *rt,
10851 double *rz,
10852 double *rlon,
10853 double *rlat,
10854 double *robs,
10855 int *nobs) {
10856
10857 /* Write info... */
10858 LOG(1, "Read observation data: %s", filename);
10859
10860 /* Read data... */
10861 if (ctl->obs_type == 0)
10862 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
10863 else if (ctl->obs_type == 1)
10864 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
10865 else
10866 ERRMSG("Set OBS_TYPE to 0 or 1!");
10867
10868 /* Check time... */
10869 for (int i = 1; i < *nobs; i++)
10870 if (rt[i] < rt[i - 1])
10871 ERRMSG("Time must be ascending!");
10872
10873 /* Write info... */
10874 int n = *nobs;
10875 double mini, maxi;
10876 LOG(2, "Number of observations: %d", *nobs);
10877 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
10878 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
10879 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
10880 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
10881 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
10882 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
10883 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
10884 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
10885 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
10886 LOG(2, "Observation range: %g ... %g", mini, maxi);
10887}
10888
10889/*****************************************************************************/
10890
10892 const char *filename,
10893 double *rt,
10894 double *rz,
10895 double *rlon,
10896 double *rlat,
10897 double *robs,
10898 int *nobs) {
10899
10900 /* Open observation data file... */
10901 FILE *in;
10902 if (!(in = fopen(filename, "r")))
10903 ERRMSG("Cannot open file!");
10904
10905 /* Read observations... */
10906 char line[LEN];
10907 while (fgets(line, LEN, in))
10908 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
10909 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
10910 if ((++(*nobs)) >= NOBS)
10911 ERRMSG("Too many observations!");
10912
10913 /* Close observation data file... */
10914 fclose(in);
10915}
10916
10917/*****************************************************************************/
10918
10920 const char *filename,
10921 double *rt,
10922 double *rz,
10923 double *rlon,
10924 double *rlat,
10925 double *robs,
10926 int *nobs) {
10927
10928 int ncid, varid;
10929
10930 /* Open netCDF file... */
10931 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
10932 ERRMSG("Cannot open file!");
10933
10934 /* Read the observations from the NetCDF file... */
10935 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
10936 NC_GET_DOUBLE("time", rt, 1);
10937 NC_GET_DOUBLE("alt", rz, 1);
10938 NC_GET_DOUBLE("lon", rlon, 1);
10939 NC_GET_DOUBLE("lat", rlat, 1);
10940 NC_GET_DOUBLE("obs", robs, 1);
10941
10942 /* Close file... */
10943 NC(nc_close(ncid));
10944}
10945
10946/*****************************************************************************/
10947
10949 const char *filename,
10950 int argc,
10951 char *argv[],
10952 const char *varname,
10953 const int arridx,
10954 const char *defvalue,
10955 char *value) {
10956
10957 FILE *in = NULL;
10958
10959 char fullname1[LEN], fullname2[LEN], rval[LEN];
10960
10961 int contain = 0, i;
10962
10963 /* Open file... */
10964 if (filename[strlen(filename) - 1] != '-')
10965 if (!(in = fopen(filename, "r")))
10966 ERRMSG("Cannot open file!");
10967
10968 /* Set full variable name... */
10969 if (arridx >= 0) {
10970 sprintf(fullname1, "%s[%d]", varname, arridx);
10971 sprintf(fullname2, "%s[*]", varname);
10972 } else {
10973 sprintf(fullname1, "%s", varname);
10974 sprintf(fullname2, "%s", varname);
10975 }
10976
10977 /* Read data... */
10978 if (in != NULL) {
10979 char dummy[LEN], line[LEN], rvarname[LEN];
10980 while (fgets(line, LEN, in)) {
10981 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
10982 if (strcasecmp(rvarname, fullname1) == 0 ||
10983 strcasecmp(rvarname, fullname2) == 0) {
10984 contain = 1;
10985 break;
10986 }
10987 }
10988 }
10989 for (i = 1; i < argc - 1; i++)
10990 if (strcasecmp(argv[i], fullname1) == 0 ||
10991 strcasecmp(argv[i], fullname2) == 0) {
10992 sprintf(rval, "%s", argv[i + 1]);
10993 contain = 1;
10994 break;
10995 }
10996
10997 /* Close file... */
10998 if (in != NULL)
10999 fclose(in);
11000
11001 /* Check for missing variables... */
11002 if (!contain) {
11003 if (strlen(defvalue) > 0)
11004 sprintf(rval, "%s", defvalue);
11005 else
11006 ERRMSG("Missing variable %s!\n", fullname1);
11007 }
11008
11009 /* Write info... */
11010 LOG(1, "%s = %s", fullname1, rval);
11011
11012 /* Return values... */
11013 if (value != NULL)
11014 sprintf(value, "%s", rval);
11015 return atof(rval);
11016}
11017
11018/*****************************************************************************/
11019
11020double sedi(
11021 const double p,
11022 const double T,
11023 const double rp,
11024 const double rhop) {
11025
11026 /* Convert particle radius from microns to m... */
11027 const double rp_help = rp * 1e-6;
11028
11029 /* Density of dry air [kg / m^3]... */
11030 const double rho = RHO(p, T);
11031
11032 /* Dynamic viscosity of air [kg / (m s)]... */
11033 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
11034
11035 /* Thermal velocity of an air molecule [m / s]... */
11036 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
11037
11038 /* Mean free path of an air molecule [m]... */
11039 const double lambda = 2. * eta / (rho * v);
11040
11041 /* Knudsen number for air (dimensionless)... */
11042 const double K = lambda / rp_help;
11043
11044 /* Cunningham slip-flow correction (dimensionless)... */
11045 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
11046
11047 /* Sedimentation velocity [m / s]... */
11048 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
11049}
11050
11051/*****************************************************************************/
11052
11054 const double *x,
11055 const double *y,
11056 const int n,
11057 const double *x2,
11058 double *y2,
11059 const int n2,
11060 const int method) {
11061
11062 /* Cubic spline interpolation... */
11063 if (method == 1) {
11064
11065 /* Allocate... */
11066 gsl_interp_accel *acc = gsl_interp_accel_alloc();
11067 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
11068
11069 /* Interpolate profile... */
11070 gsl_spline_init(s, x, y, (size_t) n);
11071 for (int i = 0; i < n2; i++)
11072 if (x2[i] <= x[0])
11073 y2[i] = y[0];
11074 else if (x2[i] >= x[n - 1])
11075 y2[i] = y[n - 1];
11076 else
11077 y2[i] = gsl_spline_eval(s, x2[i], acc);
11078
11079 /* Free... */
11080 gsl_spline_free(s);
11081 gsl_interp_accel_free(acc);
11082 }
11083
11084 /* Linear interpolation... */
11085 else {
11086 for (int i = 0; i < n2; i++)
11087 if (x2[i] <= x[0])
11088 y2[i] = y[0];
11089 else if (x2[i] >= x[n - 1])
11090 y2[i] = y[n - 1];
11091 else {
11092 const int idx = locate_irr(x, n, x2[i]);
11093 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
11094 }
11095 }
11096}
11097
11098/*****************************************************************************/
11099
11101 const float *data,
11102 const int n) {
11103
11104 if (n <= 0)
11105 return 0;
11106
11107 float mean = 0, var = 0;
11108
11109 for (int i = 0; i < n; ++i) {
11110 mean += data[i];
11111 var += SQR(data[i]);
11112 }
11113
11114 var = var / (float) n - SQR(mean / (float) n);
11115
11116 return (var > 0 ? sqrtf(var) : 0);
11117}
11118
11119/*****************************************************************************/
11120
11122 const int year,
11123 const int mon,
11124 const int day,
11125 const int hour,
11126 const int min,
11127 const int sec,
11128 const double remain,
11129 double *jsec) {
11130
11131 struct tm t0, t1;
11132
11133 t0.tm_year = 100;
11134 t0.tm_mon = 0;
11135 t0.tm_mday = 1;
11136 t0.tm_hour = 0;
11137 t0.tm_min = 0;
11138 t0.tm_sec = 0;
11139
11140 t1.tm_year = year - 1900;
11141 t1.tm_mon = mon - 1;
11142 t1.tm_mday = day;
11143 t1.tm_hour = hour;
11144 t1.tm_min = min;
11145 t1.tm_sec = sec;
11146
11147 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
11148}
11149
11150/*****************************************************************************/
11151
11153 const char *name,
11154 const char *group,
11155 const int output) {
11156
11157 static char names[NTIMER][100], groups[NTIMER][100];
11158
11159 static double rt_name[NTIMER], rt_group[NTIMER],
11160 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
11161
11162 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
11163
11164 /* Get time... */
11165 t1 = omp_get_wtime();
11166 dt = t1 - t0;
11167
11168 /* Add elapsed time to current timers... */
11169 if (iname >= 0) {
11170 rt_name[iname] += dt;
11171 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
11172 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
11173 ct_name[iname]++;
11174 }
11175 if (igroup >= 0)
11176 rt_group[igroup] += t1 - t0;
11177
11178 /* Report timers... */
11179 if (output) {
11180 for (int i = 0; i < nname; i++)
11181 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
11182 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
11183 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
11184 for (int i = 0; i < ngroup; i++)
11185 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
11186 double total = 0.0;
11187 for (int i = 0; i < nname; i++)
11188 total += rt_name[i];
11189 LOG(1, "TIMER_TOTAL = %.3f s", total);
11190 }
11191
11192 /* Identify IDs of next timer... */
11193 for (iname = 0; iname < nname; iname++)
11194 if (strcasecmp(name, names[iname]) == 0)
11195 break;
11196 for (igroup = 0; igroup < ngroup; igroup++)
11197 if (strcasecmp(group, groups[igroup]) == 0)
11198 break;
11199
11200 /* Check whether this is a new timer... */
11201 if (iname >= nname) {
11202 sprintf(names[iname], "%s", name);
11203 if ((++nname) >= NTIMER)
11204 ERRMSG("Too many timers!");
11205 }
11206
11207 /* Check whether this is a new group... */
11208 if (igroup >= ngroup) {
11209 sprintf(groups[igroup], "%s", group);
11210 if ((++ngroup) >= NTIMER)
11211 ERRMSG("Too many groups!");
11212 }
11213
11214 /* Save starting time... */
11215 t0 = t1;
11216}
11217
11218/*****************************************************************************/
11219
11221 const char *filename,
11222 const int offset) {
11223
11224 char tstr[10];
11225
11226 double t;
11227
11228 /* Get time from filename... */
11229 int len = (int) strlen(filename);
11230 sprintf(tstr, "%.4s", &filename[len - offset]);
11231 int year = atoi(tstr);
11232 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
11233 int mon = atoi(tstr);
11234 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
11235 int day = atoi(tstr);
11236 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
11237 int hour = atoi(tstr);
11238 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
11239 int min = atoi(tstr);
11240
11241 /* Check time... */
11242 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
11243 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
11244 ERRMSG("Cannot read time from filename!");
11245
11246 /* Convert time to Julian seconds... */
11247 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
11248
11249 /* Return time... */
11250 return t;
11251}
11252
11253/*****************************************************************************/
11254
11256 const clim_t *clim,
11257 const atm_t *atm,
11258 const int ip) {
11259
11260 /* Get tropopause pressure... */
11261 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
11262
11263 /* Get pressure range... */
11264 const double p1 = pt * 0.866877899;
11265 const double p0 = pt / 0.866877899;
11266
11267 /* Get weighting factor... */
11268 if (atm->p[ip] > p0)
11269 return 1;
11270 else if (atm->p[ip] < p1)
11271 return 0;
11272 else
11273 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
11274}
11275
11276/*****************************************************************************/
11277
11279 const char *filename,
11280 const ctl_t *ctl,
11281 const atm_t *atm,
11282 const double t) {
11283
11284 FILE *out;
11285
11286 /* Set time interval for output... */
11287 const double t0 = t - 0.5 * ctl->dt_mod;
11288 const double t1 = t + 0.5 * ctl->dt_mod;
11289
11290 /* Check if gnuplot output is requested... */
11291 if (ctl->atm_gpfile[0] != '-') {
11292
11293 /* Create gnuplot pipe... */
11294 if (!(out = popen("gnuplot", "w")))
11295 ERRMSG("Cannot create pipe to gnuplot!");
11296
11297 /* Set plot filename... */
11298 fprintf(out, "set out \"%s.png\"\n", filename);
11299
11300 /* Set time string... */
11301 double r;
11302 int year, mon, day, hour, min, sec;
11303 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11304 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
11305 year, mon, day, hour, min);
11306
11307 /* Dump gnuplot file to pipe... */
11308 FILE *in;
11309 if (!(in = fopen(ctl->atm_gpfile, "r")))
11310 ERRMSG("Cannot open file!");
11311 char line[LEN];
11312 while (fgets(line, LEN, in))
11313 fprintf(out, "%s", line);
11314 fclose(in);
11315 }
11316
11317 else {
11318
11319 /* Create file... */
11320 if (!(out = fopen(filename, "w")))
11321 ERRMSG("Cannot create file!");
11322 }
11323
11324 /* Write header... */
11325 fprintf(out,
11326 "# $1 = time [s]\n"
11327 "# $2 = altitude [km]\n"
11328 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11329 for (int iq = 0; iq < ctl->nq; iq++)
11330 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
11331 ctl->qnt_unit[iq]);
11332 fprintf(out, "\n");
11333
11334 /* Write data... */
11335 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
11336
11337 /* Check time... */
11338 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11339 continue;
11340
11341 /* Write output... */
11342 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
11343 atm->lon[ip], atm->lat[ip]);
11344 for (int iq = 0; iq < ctl->nq; iq++) {
11345 fprintf(out, " ");
11346 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11347 fprintf(out, ctl->qnt_format[iq], NAN);
11348 else
11349 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11350 }
11351 fprintf(out, "\n");
11352 }
11353
11354 /* Close file... */
11355 fclose(out);
11356}
11357
11358/*****************************************************************************/
11359
11361 const char *filename,
11362 const ctl_t *ctl,
11363 const atm_t *atm) {
11364
11365 FILE *out;
11366
11367 /* Create file... */
11368 if (!(out = fopen(filename, "w")))
11369 ERRMSG("Cannot create file!");
11370
11371 /* Write version of binary data... */
11372 int version = 100;
11373 FWRITE(&version, int,
11374 1,
11375 out);
11376
11377 /* Write data... */
11378 FWRITE(&atm->np, int,
11379 1,
11380 out);
11381 FWRITE(atm->time, double,
11382 (size_t) atm->np,
11383 out);
11384 FWRITE(atm->p, double,
11385 (size_t) atm->np,
11386 out);
11387 FWRITE(atm->lon, double,
11388 (size_t) atm->np,
11389 out);
11390 FWRITE(atm->lat, double,
11391 (size_t) atm->np,
11392 out);
11393 for (int iq = 0; iq < ctl->nq; iq++)
11394 FWRITE(atm->q[iq], double,
11395 (size_t) atm->np,
11396 out);
11397
11398 /* Write final flag... */
11399 int final = 999;
11400 FWRITE(&final, int,
11401 1,
11402 out);
11403
11404 /* Close file... */
11405 fclose(out);
11406}
11407
11408/*****************************************************************************/
11409
11411 const char *filename,
11412 const ctl_t *ctl,
11413 const atm_t *atm) {
11414
11415 int tid, pid, ncid, varid;
11416 size_t start[2], count[2];
11417
11418 /* Create file... */
11419 NC(nc_create(filename, NC_NETCDF4, &ncid));
11420
11421 /* Define dimensions... */
11422 NC(nc_def_dim(ncid, "time", 1, &tid));
11423 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11424
11425 /* Define variables and their attributes... */
11426 int dim_ids[2] = { tid, pid };
11427 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11428 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11429 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11430 ctl->atm_nc_level, 0);
11431 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11432 ctl->atm_nc_level, 0);
11433 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11434 ctl->atm_nc_level, 0);
11435 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11436 for (int iq = 0; iq < ctl->nq; iq++)
11437 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11438 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11439 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11440
11441 /* Define global attributes... */
11442 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11443 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11444
11445 /* End definitions... */
11446 NC(nc_enddef(ncid));
11447
11448 /* Write data... */
11449 NC_PUT_DOUBLE("time", atm->time, 0);
11450 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11451 NC_PUT_DOUBLE("LON", atm->lon, 0);
11452 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11453 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11454 for (int iq = 0; iq < ctl->nq; iq++)
11455 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11456
11457 /* Close file... */
11458 NC(nc_close(ncid));
11459}
11460
11461/*****************************************************************************/
11462
11464 const char *dirname,
11465 const ctl_t *ctl,
11466 const atm_t *atm,
11467 const double t) {
11468
11469 /* Global Counter... */
11470 static size_t out_cnt = 0;
11471
11472 double r, r_start, r_stop;
11473 int year, mon, day, hour, min, sec;
11474 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
11475 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
11476 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
11477
11478 int ncid, varid, tid, pid, cid;
11479 int dim_ids[2];
11480
11481 /* time, nparc */
11482 size_t start[2];
11483 size_t count[2];
11484
11485 /* Determine start and stop times of calculation... */
11486 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11487 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
11488 &min_start, &sec_start, &r_start);
11489 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
11490 &min_stop, &sec_stop, &r_stop);
11491
11492 sprintf(filename_out,
11493 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
11494 year_start % 100, mon_start, day_start, hour_start,
11495 year_stop % 100, mon_stop, day_stop, hour_stop);
11496 LOG(1, "Write traj file: %s", filename_out);
11497
11498 /* Define hyperslap for the traj_file... */
11499 start[0] = out_cnt;
11500 start[1] = 0;
11501 count[0] = 1;
11502 count[1] = (size_t) atm->np;
11503
11504 /* Create the file at the first timestep... */
11505 if (out_cnt == 0) {
11506
11507 /* Create file... */
11508 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
11509
11510 /* Define dimensions... */
11511 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
11512 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11513 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
11514 dim_ids[0] = tid;
11515 dim_ids[1] = pid;
11516
11517 /* Define variables and their attributes... */
11518 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11519 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11520 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
11521 ctl->atm_nc_level, 0);
11522 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
11523 ctl->atm_nc_level, 0);
11524 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
11525 ctl->atm_nc_level, 0);
11526 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
11527 ctl->atm_nc_level, 0);
11528 for (int iq = 0; iq < ctl->nq; iq++)
11529 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11530 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11531 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11532
11533 /* Define global attributes... */
11534 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11535 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11536
11537 /* End definitions... */
11538 NC(nc_enddef(ncid));
11539 NC(nc_close(ncid));
11540 }
11541
11542 /* Increment global counter to change hyperslap... */
11543 out_cnt++;
11544
11545 /* Open file... */
11546 NC(nc_open(filename_out, NC_WRITE, &ncid));
11547
11548 /* Write data... */
11549 NC_PUT_DOUBLE("time", atm->time, 1);
11550 NC_PUT_DOUBLE("LAT", atm->lat, 1);
11551 NC_PUT_DOUBLE("LON", atm->lon, 1);
11552 NC_PUT_DOUBLE("PRESS", atm->p, 1);
11553 if (ctl->advect_vert_coord == 1) {
11554 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
11555 } else if (ctl->qnt_zeta >= 0) {
11556 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
11557 }
11558 for (int iq = 0; iq < ctl->nq; iq++)
11559 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
11560
11561 /* Close file... */
11562 NC(nc_close(ncid));
11563
11564 /* At the last time step create the init_fix_YYYYMMDDHH file... */
11565 if ((year == year_stop) && (mon == mon_stop)
11566 && (day == day_stop) && (hour == hour_stop)) {
11567
11568 /* Set filename... */
11569 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
11570 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
11571 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
11572 LOG(1, "Write init file: %s", filename_init);
11573
11574 /* Create file... */
11575 NC(nc_create(filename_init, NC_NETCDF4, &ncid));
11576
11577 /* Define dimensions... */
11578 NC(nc_def_dim(ncid, "time", 1, &tid));
11579 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11580 dim_ids[0] = tid;
11581 dim_ids[1] = pid;
11582
11583 /* Define variables and their attributes... */
11584 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11585 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11586 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11587 ctl->atm_nc_level, 0);
11588 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11589 ctl->atm_nc_level, 0);
11590 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11591 ctl->atm_nc_level, 0);
11592 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11593 for (int iq = 0; iq < ctl->nq; iq++)
11594 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11595 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11596 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11597
11598 /* Define global attributes... */
11599 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11600 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11601
11602 /* End definitions... */
11603 NC(nc_enddef(ncid));
11604
11605 /* Write data... */
11606 NC_PUT_DOUBLE("time", atm->time, 0);
11607 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11608 NC_PUT_DOUBLE("LON", atm->lon, 0);
11609 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11610 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11611 for (int iq = 0; iq < ctl->nq; iq++)
11612 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11613
11614 /* Close file... */
11615 NC(nc_close(ncid));
11616 }
11617}
11618
11619/*****************************************************************************/
11620
11622 const char *filename,
11623 const ctl_t *ctl,
11624 const atm_t *atm) {
11625
11626 int ncid, obsid, varid;
11627
11628 size_t start[2], count[2];
11629
11630 /* Create file... */
11631 NC(nc_create(filename, NC_NETCDF4, &ncid));
11632
11633 /* Define dimensions... */
11634 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
11635
11636 /* Define variables and their attributes... */
11637 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
11638 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11639 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
11640 ctl->atm_nc_level, 0);
11641 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
11642 ctl->atm_nc_level, 0);
11643 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
11644 ctl->atm_nc_level, 0);
11645 for (int iq = 0; iq < ctl->nq; iq++)
11646 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
11647 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
11648 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11649
11650 /* Define global attributes... */
11651 NC_PUT_ATT_GLOBAL("featureType", "point");
11652
11653 /* End definitions... */
11654 NC(nc_enddef(ncid));
11655
11656 /* Write data... */
11657 NC_PUT_DOUBLE("time", atm->time, 0);
11658 NC_PUT_DOUBLE("press", atm->p, 0);
11659 NC_PUT_DOUBLE("lon", atm->lon, 0);
11660 NC_PUT_DOUBLE("lat", atm->lat, 0);
11661 for (int iq = 0; iq < ctl->nq; iq++)
11662 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11663
11664 /* Close file... */
11665 NC(nc_close(ncid));
11666}
11667
11668/*****************************************************************************/
11669
11671 const char *filename,
11672 const ctl_t *ctl,
11673 const atm_t *atm,
11674 const double t) {
11675
11676 static FILE *out;
11677
11678 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
11679 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
11680
11681 static int *obscount, nobs, nk;
11682
11683 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
11684
11685 const int ensemble = (ctl->nens > 0);
11686
11687 /* Set timer */
11688 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
11689
11690 /* Check quantities... */
11691 if (ctl->qnt_m < 0)
11692 ERRMSG("Need quantity mass!");
11693 if (ensemble) {
11694 if (ctl->qnt_ens < 0)
11695 ERRMSG("Missing ensemble IDs!");
11696 if (ctl->nens > NENS)
11697 ERRMSG("Too many ensembles!");
11698 }
11699
11700 /* Init... */
11701 if (t == ctl->t_start) {
11702
11703 /* Allocate.. */
11704 ALLOC(area, double,
11705 ctl->csi_ny);
11706 ALLOC(rt, double,
11707 NOBS);
11708 ALLOC(rz, double,
11709 NOBS);
11710 ALLOC(rlon, double,
11711 NOBS);
11712 ALLOC(rlat, double,
11713 NOBS);
11714 ALLOC(robs, double,
11715 NOBS);
11716
11717 /* Read observation data... */
11718 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11719
11720 /* Read kernel data... */
11721 if (ctl->csi_kernel[0] != '-')
11722 read_kernel(ctl->csi_kernel, kz, kw, &nk);
11723
11724 /* Create new file... */
11725 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
11726 if (!(out = fopen(filename, "w")))
11727 ERRMSG("Cannot create file!");
11728
11729 /* Write header... */
11730 fprintf(out,
11731 "# $1 = time [s]\n"
11732 "# $2 = ensemble ID\n"
11733 "# $3 = number of hits (cx)\n"
11734 "# $4 = number of misses (cy)\n"
11735 "# $5 = number of false alarms (cz)\n"
11736 "# $6 = number of observations (cx + cy)\n"
11737 "# $7 = number of forecasts (cx + cz)\n"
11738 "# $8 = bias (%%)\n"
11739 "# $9 = POD (%%)\n"
11740 "# $10 = FAR (%%)\n"
11741 "# $11 = CSI (%%)\n"
11742 "# $12 = hits by random chance\n"
11743 "# $13 = ETS (%%)\n"
11744 "# $14 = Pearson R\n"
11745 "# $15 = Spearman R\n"
11746 "# $16 = mean error [kg/m²]\n"
11747 "# $17 = RMSE [kg/m²]\n"
11748 "# $18 = MAE [kg/m²]\n"
11749 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
11750
11751 /* Set grid box size... */
11752 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
11753 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
11754 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
11755
11756 /* Set horizontal coordinates... */
11757 for (int iy = 0; iy < ctl->csi_ny; iy++) {
11758 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
11759 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
11760 }
11761 }
11762
11763 /* Set time interval... */
11764 const double t0 = t - 0.5 * ctl->dt_mod;
11765 const double t1 = t + 0.5 * ctl->dt_mod;
11766
11767 /* Allocate... */
11768 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
11769 ALLOC(modmean, double,
11770 (ensemble ? ctl->nens : 1) * grid_size);
11771 ALLOC(obsmean, double,
11772 grid_size);
11773 ALLOC(obscount, int,
11774 grid_size);
11775 ALLOC(obsstd, double,
11776 grid_size);
11777
11778 /* Init... */
11779 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
11780 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
11781
11782 /* Loop over observations... */
11783 for (int i = 0; i < nobs; i++) {
11784 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
11785 continue;
11786
11787 /* Calculate indices... */
11788 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
11789 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
11790 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
11791 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11792 || iz >= ctl->csi_nz)
11793 continue;
11794
11795 /* Get mean observation index... */
11796 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11797 obsmean[idx] += robs[i];
11798 obsstd[idx] += SQR(robs[i]);
11799 obscount[idx]++;
11800 }
11801
11802 /* Analyze model data... */
11803 for (int ip = 0; ip < atm->np; ip++) {
11804
11805 /* Check time... */
11806 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11807 continue;
11808
11809 /* Get ensemble ID... */
11810 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
11811 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
11812 ERRMSG("Ensemble ID out of range!");
11813
11814 /* Get indices... */
11815 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
11816 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
11817 const int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
11818 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11819 || iz >= ctl->csi_nz)
11820 continue;
11821
11822 /* Get total mass in grid cell... */
11823 const int idx =
11824 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11825 modmean[idx] +=
11826 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11827 }
11828 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11829 /* Analyze all grid cells... */
11830 for (int ix = 0; ix < ctl->csi_nx; ix++)
11831 for (int iy = 0; iy < ctl->csi_ny; iy++)
11832 for (int iz = 0; iz < ctl->csi_nz; iz++) {
11833
11834 /* Calculate mean observation index... */
11835 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11836 if (e == 0)
11837 if (obscount[idx]) {
11838 obsmean[idx] /= obscount[idx];
11839 obsstd[idx] =
11840 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
11841 }
11842
11843 /* Calculate model mean per ensemble... */
11844 const int midx = e * grid_size + idx;
11845 if (modmean[midx] > 0)
11846 modmean[midx] /= (1e6 * area[iy]);
11847
11848 /* Check number of observations... */
11849 if (obscount[idx]) {
11850
11851 /* Calculate CSI... */
11852 ct[e]++;
11853 if (obsmean[idx] >= ctl->csi_obsmin
11854 && modmean[midx] >= ctl->csi_modmin)
11855 cx[e]++;
11856 else if (obsmean[idx] >= ctl->csi_obsmin)
11857 cy[e]++;
11858 else if (modmean[midx] >= ctl->csi_modmin)
11859 cz[e]++;
11860
11861 /* Save data for other verification statistics... */
11862 if (obsmean[idx] >= ctl->csi_obsmin
11863 || modmean[midx] >= ctl->csi_modmin) {
11864 x[n[e]] = modmean[midx];
11865 y[n[e]] = obsmean[idx];
11866 if (modmean[midx] >= ctl->csi_modmin)
11867 obsstdn[n[e]] = obsstd[idx];
11868 if ((++n[e]) >= NCSI)
11869 ERRMSG("Too many points for statistics!");
11870 }
11871 }
11872 }
11873 /* Write output... */
11874 if (fmod(t, ctl->csi_dt_out) == 0) {
11875
11876 if (n[e] == 0)
11877 continue;
11878
11879 /* Calculate verification statistics
11880 (https://www.cawcr.gov.au/projects/verification/) ... */
11881 static double work[2 * NCSI], work2[2 * NCSI];
11882 const int n_obs = cx[e] + cy[e];
11883 const int n_for = cx[e] + cz[e];
11884 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
11885 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
11886 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
11887 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
11888 const double csi =
11889 (cx[e] + cy[e] + cz[e] >
11890 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
11891 const double ets =
11892 (cx[e] + cy[e] + cz[e] - cx_rd >
11893 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
11894 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
11895 const double rho_s =
11896 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
11897 for (int i = 0; i < n[e]; i++) {
11898 work[i] = x[i] - y[i];
11899 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
11900 }
11901 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
11902 const double rmse =
11903 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
11904 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
11905 const double loglikelihood =
11906 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
11907
11908 /* Write... */
11909 fprintf(out,
11910 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
11911 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
11912 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
11913 loglikelihood, n[e]);
11914
11915 /* Set counters to zero... */
11916 for (int i = 0; i < n[e]; i++)
11917 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
11918 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
11919 }
11920 }
11921 /* Free... */
11922 free(modmean);
11923 free(obsmean);
11924 free(obscount);
11925 free(obsstd);
11926
11927 /* Finalize... */
11928 if (t == ctl->t_stop) {
11929
11930 /* Close output file... */
11931 fclose(out);
11932
11933 /* Free... */
11934 free(area);
11935 free(rt);
11936 free(rz);
11937 free(rlon);
11938 free(rlat);
11939 free(robs);
11940 }
11941}
11942
11943/*****************************************************************************/
11944
11946 const char *filename,
11947 const ctl_t *ctl,
11948 const atm_t *atm,
11949 const double t) {
11950
11951 static FILE *out;
11952
11953 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
11954 x[3], zm[NENS];
11955
11956 static int n[NENS];
11957
11958 /* Set timer... */
11959 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
11960
11961 /* Check quantities... */
11962 if (ctl->qnt_ens < 0)
11963 ERRMSG("Missing ensemble IDs!");
11964
11965 /* Set time interval... */
11966 const double t0 = t - 0.5 * ctl->dt_mod;
11967 const double t1 = t + 0.5 * ctl->dt_mod;
11968
11969 /* Init... */
11970 for (int i = 0; i < NENS; i++) {
11971 for (int iq = 0; iq < ctl->nq; iq++)
11972 qm[iq][i] = qs[iq][i] = 0;
11973 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
11974 n[i] = 0;
11975 }
11976
11977 /* Loop over air parcels... */
11978 for (int ip = 0; ip < atm->np; ip++) {
11979
11980 /* Check time... */
11981 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11982 continue;
11983
11984 /* Check ensemble ID... */
11985 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
11986 ERRMSG("Ensemble ID is out of range!");
11987
11988 /* Get means... */
11989 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
11990 for (int iq = 0; iq < ctl->nq; iq++) {
11991 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
11992 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
11993 }
11994 xm[ctl->qnt_ens][0] += x[0];
11995 xm[ctl->qnt_ens][1] += x[1];
11996 xm[ctl->qnt_ens][2] += x[2];
11997 zm[ctl->qnt_ens] += Z(atm->p[ip]);
11998 n[ctl->qnt_ens]++;
11999 }
12000
12001 /* Create file... */
12002 LOG(1, "Write ensemble data: %s", filename);
12003 if (!(out = fopen(filename, "w")))
12004 ERRMSG("Cannot create file!");
12005
12006 /* Write header... */
12007 fprintf(out,
12008 "# $1 = time [s]\n"
12009 "# $2 = altitude [km]\n"
12010 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12011 for (int iq = 0; iq < ctl->nq; iq++)
12012 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
12013 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12014 for (int iq = 0; iq < ctl->nq; iq++)
12015 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
12016 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12017 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
12018
12019 /* Write data... */
12020 for (int i = 0; i < NENS; i++)
12021 if (n[i] > 0) {
12022 cart2geo(xm[i], &dummy, &lon, &lat);
12023 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
12024 for (int iq = 0; iq < ctl->nq; iq++) {
12025 fprintf(out, " ");
12026 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
12027 }
12028 for (int iq = 0; iq < ctl->nq; iq++) {
12029 fprintf(out, " ");
12030 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
12031 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
12032 }
12033 fprintf(out, " %d\n", n[i]);
12034 }
12035
12036 /* Close file... */
12037 fclose(out);
12038}
12039
12040/*****************************************************************************/
12041
12043 const char *filename,
12044 const ctl_t *ctl,
12045 met_t *met0,
12046 met_t *met1,
12047 const atm_t *atm,
12048 const double t) {
12049
12050 static double kz[EP], kw[EP];
12051
12052 static int nk;
12053
12054 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
12055
12056 int *ixs, *iys, *izs, *np;
12057
12058 /* Set timer... */
12059 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
12060
12061 /* Write info... */
12062 LOG(1, "Write grid data: %s", filename);
12063
12064 /* Init... */
12065 if (t == ctl->t_start) {
12066
12067 /* Read kernel data... */
12068 if (ctl->grid_kernel[0] != '-')
12069 read_kernel(ctl->grid_kernel, kz, kw, &nk);
12070 }
12071
12072 /* Allocate... */
12073 ALLOC(cd, double,
12074 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12075 for (int iq = 0; iq < ctl->nq; iq++) {
12076 ALLOC(mean[iq], double,
12077 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12078 ALLOC(sigma[iq], double,
12079 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12080 }
12081 ALLOC(vmr_impl, double,
12082 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12083 ALLOC(z, double,
12084 ctl->grid_nz);
12085 ALLOC(lon, double,
12086 ctl->grid_nx);
12087 ALLOC(lat, double,
12088 ctl->grid_ny);
12089 ALLOC(area, double,
12090 ctl->grid_ny);
12091 ALLOC(press, double,
12092 ctl->grid_nz);
12093 ALLOC(np, int,
12094 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12095 ALLOC(ixs, int,
12096 atm->np);
12097 ALLOC(iys, int,
12098 atm->np);
12099 ALLOC(izs, int,
12100 atm->np);
12101
12102 /* Set grid box size... */
12103 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
12104 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
12105 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
12106
12107 /* Set vertical coordinates... */
12108#pragma omp parallel for default(shared)
12109 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12110 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
12111 press[iz] = P(z[iz]);
12112 }
12113
12114 /* Set horizontal coordinates... */
12115 for (int ix = 0; ix < ctl->grid_nx; ix++)
12116 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
12117#pragma omp parallel for default(shared)
12118 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12119 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
12120 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
12121 }
12122
12123 /* Set time interval for output... */
12124 const double t0 = t - 0.5 * ctl->dt_mod;
12125 const double t1 = t + 0.5 * ctl->dt_mod;
12126
12127 /* Get grid box indices... */
12128#pragma omp parallel for default(shared)
12129 for (int ip = 0; ip < atm->np; ip++) {
12130 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
12131 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
12132 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
12133 if (atm->time[ip] < t0 || atm->time[ip] > t1
12134 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
12135 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
12136 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
12137 izs[ip] = -1;
12138 }
12139
12140 /* Average data... */
12141 for (int ip = 0; ip < atm->np; ip++)
12142 if (izs[ip] >= 0) {
12143 const int idx =
12144 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
12145 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
12146 np[idx]++;
12147 for (int iq = 0; iq < ctl->nq; iq++) {
12148 mean[iq][idx] += kernel * atm->q[iq][ip];
12149 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
12150 }
12151 }
12152
12153 /* Calculate column density and volume mixing ratio... */
12154#pragma omp parallel for default(shared)
12155 for (int ix = 0; ix < ctl->grid_nx; ix++)
12156 for (int iy = 0; iy < ctl->grid_ny; iy++)
12157 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12158
12159 /* Get grid index... */
12160 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12161
12162 /* Calculate column density... */
12163 cd[idx] = NAN;
12164 if (ctl->qnt_m >= 0)
12165 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
12166
12167 /* Calculate volume mixing ratio (implicit)... */
12168 vmr_impl[idx] = NAN;
12169 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
12170 && met1 != NULL) {
12171 vmr_impl[idx] = 0;
12172 if (mean[ctl->qnt_m][idx] > 0) {
12173
12174 /* Get temperature... */
12175 double temp;
12177 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
12178 lon[ix], lat[iy], &temp, ci, cw, 1);
12179
12180 /* Calculate volume mixing ratio... */
12181 vmr_impl[idx] =
12182 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
12183 }
12184 }
12185
12186 /* Calculate mean... */
12187 if (np[idx] > 0)
12188 for (int iq = 0; iq < ctl->nq; iq++) {
12189 mean[iq][idx] /= np[idx];
12190 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
12191 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
12192 } else
12193 for (int iq = 0; iq < ctl->nq; iq++) {
12194 mean[iq][idx] = NAN;
12195 sigma[iq][idx] = NAN;
12196 }
12197 }
12198
12199 /* Write ASCII data... */
12200 if (ctl->grid_type == 0)
12201 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
12202 t, z, lon, lat, area, dz, np);
12203
12204 /* Write netCDF data... */
12205 else if (ctl->grid_type == 1)
12206 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
12207 t, z, lon, lat, area, dz, np);
12208
12209 /* Error message... */
12210 else
12211 ERRMSG("Grid data format GRID_TYPE unknown!");
12212
12213 /* Free... */
12214 free(cd);
12215 for (int iq = 0; iq < ctl->nq; iq++) {
12216 free(mean[iq]);
12217 free(sigma[iq]);
12218 }
12219 free(vmr_impl);
12220 free(z);
12221 free(lon);
12222 free(lat);
12223 free(area);
12224 free(press);
12225 free(np);
12226 free(ixs);
12227 free(iys);
12228 free(izs);
12229}
12230
12231/*****************************************************************************/
12232
12234 const char *filename,
12235 const ctl_t *ctl,
12236 const double *cd,
12237 double *mean[NQ],
12238 double *sigma[NQ],
12239 const double *vmr_impl,
12240 const double t,
12241 const double *z,
12242 const double *lon,
12243 const double *lat,
12244 const double *area,
12245 const double dz,
12246 const int *np) {
12247
12248 FILE *out;
12249
12250 /* Check if gnuplot output is requested... */
12251 if (ctl->grid_gpfile[0] != '-') {
12252
12253 /* Create gnuplot pipe... */
12254 if (!(out = popen("gnuplot", "w")))
12255 ERRMSG("Cannot create pipe to gnuplot!");
12256
12257 /* Set plot filename... */
12258 fprintf(out, "set out \"%s.png\"\n", filename);
12259
12260 /* Set time string... */
12261 double r;
12262 int year, mon, day, hour, min, sec;
12263 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12264 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12265 year, mon, day, hour, min);
12266
12267 /* Dump gnuplot file to pipe... */
12268 FILE *in;
12269 char line[LEN];
12270 if (!(in = fopen(ctl->grid_gpfile, "r")))
12271 ERRMSG("Cannot open file!");
12272 while (fgets(line, LEN, in))
12273 fprintf(out, "%s", line);
12274 fclose(in);
12275 }
12276
12277 else {
12278
12279 /* Create file... */
12280 if (!(out = fopen(filename, "w")))
12281 ERRMSG("Cannot create file!");
12282 }
12283
12284 /* Write header... */
12285 fprintf(out,
12286 "# $1 = time [s]\n"
12287 "# $2 = altitude [km]\n"
12288 "# $3 = longitude [deg]\n"
12289 "# $4 = latitude [deg]\n"
12290 "# $5 = surface area [km^2]\n"
12291 "# $6 = layer depth [km]\n"
12292 "# $7 = column density (implicit) [kg/m^2]\n"
12293 "# $8 = volume mixing ratio (implicit) [ppv]\n"
12294 "# $9 = number of particles [1]\n");
12295 for (int iq = 0; iq < ctl->nq; iq++)
12296 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
12297 ctl->qnt_unit[iq]);
12298 if (ctl->grid_stddev)
12299 for (int iq = 0; iq < ctl->nq; iq++)
12300 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
12301 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12302 fprintf(out, "\n");
12303
12304 /* Write data... */
12305 for (int ix = 0; ix < ctl->grid_nx; ix++) {
12306 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
12307 fprintf(out, "\n");
12308 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12309 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
12310 fprintf(out, "\n");
12311 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12312 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12313 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
12314 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
12315 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
12316 for (int iq = 0; iq < ctl->nq; iq++) {
12317 fprintf(out, " ");
12318 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
12319 }
12320 if (ctl->grid_stddev)
12321 for (int iq = 0; iq < ctl->nq; iq++) {
12322 fprintf(out, " ");
12323 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
12324 }
12325 fprintf(out, "\n");
12326 }
12327 }
12328 }
12329 }
12330
12331 /* Close file... */
12332 fclose(out);
12333}
12334
12335/*****************************************************************************/
12336
12338 const char *filename,
12339 const ctl_t *ctl,
12340 const double *cd,
12341 double *mean[NQ],
12342 double *sigma[NQ],
12343 const double *vmr_impl,
12344 const double t,
12345 const double *z,
12346 const double *lon,
12347 const double *lat,
12348 const double *area,
12349 const double dz,
12350 const int *np) {
12351
12352 char longname[2 * LEN], varname[2 * LEN];
12353
12354 double *help;
12355
12356 int *help2, ncid, dimid[10], varid;
12357
12358 size_t start[2], count[2];
12359
12360 /* Allocate... */
12361 ALLOC(help, double,
12362 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12363 ALLOC(help2, int,
12364 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12365
12366 /* Create file... */
12367 NC(nc_create(filename, NC_NETCDF4, &ncid));
12368
12369 /* Define dimensions... */
12370 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
12371 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
12372 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
12373 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
12374 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
12375
12376 /* Define variables and their attributes... */
12377 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
12378 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12379 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
12380 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
12381 0);
12382 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
12383 0);
12384 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
12385 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
12386
12387 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
12388 ctl->grid_nc_level, 0);
12389 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
12390 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
12391 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
12392 for (int iq = 0; iq < ctl->nq; iq++) {
12393 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12394 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
12395 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12396 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12397 if (ctl->grid_stddev) {
12398 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12399 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
12400 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12401 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12402 }
12403 }
12404 /* End definitions... */
12405 NC(nc_enddef(ncid));
12406
12407 /* Write data... */
12408 NC_PUT_DOUBLE("time", &t, 0);
12409 NC_PUT_DOUBLE("lon", lon, 0);
12410 NC_PUT_DOUBLE("lat", lat, 0);
12411 NC_PUT_DOUBLE("z", z, 0);
12412 NC_PUT_DOUBLE("area", area, 0);
12413 NC_PUT_DOUBLE("dz", &dz, 0);
12414
12415 for (int ix = 0; ix < ctl->grid_nx; ix++)
12416 for (int iy = 0; iy < ctl->grid_ny; iy++)
12417 for (int iz = 0; iz < ctl->grid_nz; iz++)
12418 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12419 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12420 NC_PUT_DOUBLE("cd", help, 0);
12421
12422 for (int ix = 0; ix < ctl->grid_nx; ix++)
12423 for (int iy = 0; iy < ctl->grid_ny; iy++)
12424 for (int iz = 0; iz < ctl->grid_nz; iz++)
12425 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12426 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12427 NC_PUT_DOUBLE("vmr_impl", help, 0);
12428
12429 for (int ix = 0; ix < ctl->grid_nx; ix++)
12430 for (int iy = 0; iy < ctl->grid_ny; iy++)
12431 for (int iz = 0; iz < ctl->grid_nz; iz++)
12432 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12433 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12434 NC_PUT_INT("np", help2, 0);
12435
12436 for (int iq = 0; iq < ctl->nq; iq++) {
12437 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12438 for (int ix = 0; ix < ctl->grid_nx; ix++)
12439 for (int iy = 0; iy < ctl->grid_ny; iy++)
12440 for (int iz = 0; iz < ctl->grid_nz; iz++)
12441 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12442 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12443 NC_PUT_DOUBLE(varname, help, 0);
12444 }
12445
12446 if (ctl->grid_stddev)
12447 for (int iq = 0; iq < ctl->nq; iq++) {
12448 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12449 for (int ix = 0; ix < ctl->grid_nx; ix++)
12450 for (int iy = 0; iy < ctl->grid_ny; iy++)
12451 for (int iz = 0; iz < ctl->grid_nz; iz++)
12452 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12453 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12454 NC_PUT_DOUBLE(varname, help, 0);
12455 }
12456
12457 /* Close file... */
12458 NC(nc_close(ncid));
12459
12460 /* Free... */
12461 free(help);
12462 free(help2);
12463}
12464
12465/*****************************************************************************/
12466
12468 const char *filename,
12469 const ctl_t *ctl,
12470 met_t *met) {
12471
12472 /* Create file... */
12473 FILE *out;
12474 if (!(out = fopen(filename, "w")))
12475 ERRMSG("Cannot create file!");
12476
12477 /* Write type of binary data... */
12478 FWRITE(&ctl->met_type, int,
12479 1,
12480 out);
12481
12482 /* Write version of binary data... */
12483 int version = 103;
12484 FWRITE(&version, int,
12485 1,
12486 out);
12487
12488 /* Write grid data... */
12489 FWRITE(&met->time, double,
12490 1,
12491 out);
12492 FWRITE(&met->nx, int,
12493 1,
12494 out);
12495 FWRITE(&met->ny, int,
12496 1,
12497 out);
12498 FWRITE(&met->np, int,
12499 1,
12500 out);
12501 FWRITE(met->lon, double,
12502 (size_t) met->nx,
12503 out);
12504 FWRITE(met->lat, double,
12505 (size_t) met->ny,
12506 out);
12507 FWRITE(met->p, double,
12508 (size_t) met->np,
12509 out);
12510
12511 /* Write surface data... */
12512 write_met_bin_2d(out, met, met->ps, "PS");
12513 write_met_bin_2d(out, met, met->ts, "TS");
12514 write_met_bin_2d(out, met, met->zs, "ZS");
12515 write_met_bin_2d(out, met, met->us, "US");
12516 write_met_bin_2d(out, met, met->vs, "VS");
12517 write_met_bin_2d(out, met, met->ess, "ESS");
12518 write_met_bin_2d(out, met, met->nss, "NSS");
12519 write_met_bin_2d(out, met, met->shf, "SHF");
12520 write_met_bin_2d(out, met, met->lsm, "LSM");
12521 write_met_bin_2d(out, met, met->sst, "SST");
12522 write_met_bin_2d(out, met, met->pbl, "PBL");
12523 write_met_bin_2d(out, met, met->pt, "PT");
12524 write_met_bin_2d(out, met, met->tt, "TT");
12525 write_met_bin_2d(out, met, met->zt, "ZT");
12526 write_met_bin_2d(out, met, met->h2ot, "H2OT");
12527 write_met_bin_2d(out, met, met->pct, "PCT");
12528 write_met_bin_2d(out, met, met->pcb, "PCB");
12529 write_met_bin_2d(out, met, met->cl, "CL");
12530 write_met_bin_2d(out, met, met->plcl, "PLCL");
12531 write_met_bin_2d(out, met, met->plfc, "PLFC");
12532 write_met_bin_2d(out, met, met->pel, "PEL");
12533 write_met_bin_2d(out, met, met->cape, "CAPE");
12534 write_met_bin_2d(out, met, met->cin, "CIN");
12535 write_met_bin_2d(out, met, met->o3c, "O3C");
12536
12537 /* Write level data... */
12538 write_met_bin_3d(out, ctl, met, met->z, "Z",
12539 ctl->met_comp_prec[0], ctl->met_comp_tol[0]);
12540 write_met_bin_3d(out, ctl, met, met->t, "T",
12541 ctl->met_comp_prec[1], ctl->met_comp_tol[1]);
12542 write_met_bin_3d(out, ctl, met, met->u, "U",
12543 ctl->met_comp_prec[2], ctl->met_comp_tol[2]);
12544 write_met_bin_3d(out, ctl, met, met->v, "V",
12545 ctl->met_comp_prec[3], ctl->met_comp_tol[3]);
12546 write_met_bin_3d(out, ctl, met, met->w, "W",
12547 ctl->met_comp_prec[4], ctl->met_comp_tol[4]);
12548 write_met_bin_3d(out, ctl, met, met->pv, "PV",
12549 ctl->met_comp_prec[5], ctl->met_comp_tol[5]);
12550 write_met_bin_3d(out, ctl, met, met->h2o, "H2O",
12551 ctl->met_comp_prec[6], ctl->met_comp_tol[6]);
12552 write_met_bin_3d(out, ctl, met, met->o3, "O3",
12553 ctl->met_comp_prec[7], ctl->met_comp_tol[7]);
12554 write_met_bin_3d(out, ctl, met, met->lwc, "LWC",
12555 ctl->met_comp_prec[8], ctl->met_comp_tol[8]);
12556 write_met_bin_3d(out, ctl, met, met->rwc, "RWC",
12557 ctl->met_comp_prec[9], ctl->met_comp_tol[9]);
12558 write_met_bin_3d(out, ctl, met, met->iwc, "IWC",
12559 ctl->met_comp_prec[10], ctl->met_comp_tol[10]);
12560 write_met_bin_3d(out, ctl, met, met->swc, "SWC",
12561 ctl->met_comp_prec[11], ctl->met_comp_tol[11]);
12562 write_met_bin_3d(out, ctl, met, met->cc, "CC",
12563 ctl->met_comp_prec[12], ctl->met_comp_tol[12]);
12564 if (METVAR != 13)
12565 ERRMSG("Number of meteo variables doesn't match!");
12566
12567 /* Write final flag... */
12568 int final = 999;
12569 FWRITE(&final, int,
12570 1,
12571 out);
12572
12573 /* Close file... */
12574 fclose(out);
12575}
12576
12577/*****************************************************************************/
12578
12580 FILE *out,
12581 met_t *met,
12582 float var[EX][EY],
12583 const char *varname) {
12584
12585 float *help;
12586
12587 /* Allocate... */
12588 ALLOC(help, float,
12589 EX * EY);
12590
12591 /* Copy data... */
12592 for (int ix = 0; ix < met->nx; ix++)
12593 for (int iy = 0; iy < met->ny; iy++)
12594 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
12595
12596 /* Write uncompressed data... */
12597 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
12598 FWRITE(help, float,
12599 (size_t) (met->nx * met->ny),
12600 out);
12601
12602 /* Free... */
12603 free(help);
12604}
12605
12606/*****************************************************************************/
12607
12609 FILE *out,
12610 const ctl_t *ctl,
12611 met_t *met,
12612 float var[EX][EY][EP],
12613 const char *varname,
12614 const int precision,
12615 const double tolerance) {
12616
12617 float *help;
12618
12619 /* Allocate... */
12620 ALLOC(help, float,
12621 EX * EY * EP);
12622
12623 /* Copy data... */
12624#pragma omp parallel for default(shared) collapse(2)
12625 for (int ix = 0; ix < met->nx; ix++)
12626 for (int iy = 0; iy < met->ny; iy++)
12627 for (int ip = 0; ip < met->np; ip++)
12628 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
12629
12630 /* Write uncompressed data... */
12631 if (ctl->met_type == 1) {
12632 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
12633 FWRITE(help, float,
12634 (size_t) (met->nx * met->ny * met->np),
12635 out);
12636 }
12637
12638 /* Write packed data... */
12639 else if (ctl->met_type == 2)
12640 compress_pck(varname, help, (size_t) (met->ny * met->nx),
12641 (size_t) met->np, 0, out);
12642
12643 /* Write ZFP data... */
12644#ifdef ZFP
12645 else if (ctl->met_type == 3) {
12646 FWRITE(&precision, int,
12647 1,
12648 out);
12649 FWRITE(&tolerance, double,
12650 1,
12651 out);
12652 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
12653 tolerance, 0, out);
12654 }
12655#endif
12656
12657 /* Write zstd data... */
12658#ifdef ZSTD
12659 else if (ctl->met_type == 4)
12660 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
12661 ctl->met_zstd_level, out);
12662#endif
12663
12664 /* Write cmultiscale data... */
12665#ifdef CMS
12666 else if (ctl->met_type == 5) {
12667 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
12668 (size_t) met->np, met->p, 0, out);
12669 }
12670#endif
12671
12672 /* Write SZ3 data... */
12673#ifdef SZ3
12674 else if (ctl->met_type == 7) {
12675 FWRITE(&precision, int,
12676 1,
12677 out);
12678 FWRITE(&tolerance, double,
12679 1,
12680 out);
12681 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
12682 tolerance, 0, out);
12683 }
12684#endif
12685
12686 /* Unknown method... */
12687 else {
12688 ERRMSG("MET_TYPE not supported!");
12689 LOG(3, "%d %g", precision, tolerance);
12690 }
12691
12692 /* Free... */
12693 free(help);
12694}
12695
12696/*****************************************************************************/
12697
12699 const char *filename,
12700 const ctl_t *ctl,
12701 met_t *met) {
12702
12703 /* Create file... */
12704 int ncid, varid;
12705 size_t start[4], count[4];
12706 NC(nc_create(filename, NC_NETCDF4, &ncid));
12707
12708 /* Define dimensions... */
12709 int tid, lonid, latid, levid;
12710 NC(nc_def_dim(ncid, "time", 1, &tid));
12711 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
12712 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
12713 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
12714
12715 /* Define grid... */
12716 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
12717 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12718 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
12719 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
12720 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
12721
12722 /* Define surface variables... */
12723 int dimid2[2] = { latid, lonid };
12724 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
12725 ctl->met_nc_level, 0);
12726 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
12727 ctl->met_nc_level, 0);
12728 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
12729 ctl->met_nc_level, 0);
12730 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
12731 "m s**-1", ctl->met_nc_level, 0);
12732 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
12733 "m s**-1", ctl->met_nc_level, 0);
12734 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
12735 "Instantaneous eastward turbulent surface stress", "N m**-2",
12736 ctl->met_nc_level, 0);
12737 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
12738 "Instantaneous northward turbulent surface stress", "N m**-2",
12739 ctl->met_nc_level, 0);
12740 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
12741 "Instantaneous surface sensible heat flux", "W m**-1",
12742 ctl->met_nc_level, 0);
12743 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
12744 ctl->met_nc_level, 0);
12745 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
12746 ctl->met_nc_level, 0);
12747 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
12748 ctl->met_nc_level, 0);
12749 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
12750 ctl->met_nc_level, 0);
12751 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
12752 ctl->met_nc_level, 0);
12753 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
12754 ctl->met_nc_level, 0);
12755 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
12756 ctl->met_nc_level, 0);
12757 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
12758 ctl->met_nc_level, 0);
12759 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
12760 ctl->met_nc_level, 0);
12761 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water",
12762 "kg m**2", ctl->met_nc_level, 0);
12763 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
12764 "Pressure at lifted condensation level (LCL)", "Pa",
12765 ctl->met_nc_level, 0);
12766 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
12767 "Pressure at level of free convection (LFC)", "Pa",
12768 ctl->met_nc_level, 0);
12769 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2,
12770 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
12771 0);
12772 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
12773 "Convective available potential energy", "J kg**-1",
12774 ctl->met_nc_level, 0);
12775 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition",
12776 "J kg**-1", ctl->met_nc_level, 0);
12777 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
12778 ctl->met_nc_level, 0);
12779
12780 /* Define level data... */
12781 int dimid3[3] = { levid, latid, lonid };
12782 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
12783 ctl->met_nc_level, ctl->met_nc_quant);
12784 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
12785 ctl->met_nc_level, ctl->met_nc_quant);
12786 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
12787 ctl->met_nc_level, ctl->met_nc_quant);
12788 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
12789 ctl->met_nc_level, ctl->met_nc_quant);
12790 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
12791 ctl->met_nc_level, ctl->met_nc_quant);
12792 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
12793 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12794 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
12795 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12796 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
12797 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12798 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
12799 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12800 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
12801 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12802 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
12803 ctl->met_nc_level, ctl->met_nc_quant);
12804
12805 /* End definitions... */
12806 NC(nc_enddef(ncid));
12807
12808 /* Write grid data... */
12809 NC_PUT_DOUBLE("time", &met->time, 0);
12810 NC_PUT_DOUBLE("lon", met->lon, 0);
12811 NC_PUT_DOUBLE("lat", met->lat, 0);
12812 double phelp[EP];
12813 for (int ip = 0; ip < met->np; ip++)
12814 phelp[ip] = 100. * met->p[ip];
12815 NC_PUT_DOUBLE("lev", phelp, 0);
12816
12817 /* Write surface data... */
12818 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
12819 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
12820 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
12821 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
12822 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
12823 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
12824 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
12825 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
12826 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
12827 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
12828 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
12829 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
12830 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
12831 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
12832 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
12833 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
12834 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
12835 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
12836 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
12837 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
12838 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
12839 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
12840 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
12841 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
12842
12843 /* Write level data... */
12844 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
12845 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
12846 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
12847 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
12848 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
12849 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
12850 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
12851 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
12852 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
12853 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
12854 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
12855
12856 /* Close file... */
12857 NC(nc_close(ncid));
12858}
12859
12860/*****************************************************************************/
12861
12863 const int ncid,
12864 const char *varname,
12865 met_t *met,
12866 float var[EX][EY],
12867 const float scl) {
12868
12869 int varid;
12870 size_t start[4], count[4];
12871
12872 /* Allocate... */
12873 float *help;
12874 ALLOC(help, float,
12875 EX * EY);
12876
12877 /* Copy data... */
12878 for (int ix = 0; ix < met->nx; ix++)
12879 for (int iy = 0; iy < met->ny; iy++)
12880 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
12881
12882 /* Write data... */
12883 NC_PUT_FLOAT(varname, help, 0);
12884
12885 /* Free... */
12886 free(help);
12887}
12888
12889/*****************************************************************************/
12890
12892 const int ncid,
12893 const char *varname,
12894 met_t *met,
12895 float var[EX][EY][EP],
12896 const float scl) {
12897
12898 int varid;
12899 size_t start[4], count[4];
12900
12901 /* Allocate... */
12902 float *help;
12903 ALLOC(help, float,
12904 EX * EY * EP);
12905
12906 /* Copy data... */
12907 for (int ix = 0; ix < met->nx; ix++)
12908 for (int iy = 0; iy < met->ny; iy++)
12909 for (int ip = 0; ip < met->np; ip++)
12910 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
12911
12912 /* Write data... */
12913 NC_PUT_FLOAT(varname, help, 0);
12914
12915 /* Free... */
12916 free(help);
12917}
12918
12919/*****************************************************************************/
12920
12922 const char *filename,
12923 const ctl_t *ctl,
12924 met_t *met0,
12925 met_t *met1,
12926 const atm_t *atm,
12927 const double t) {
12928
12929 static FILE *out;
12930
12931 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
12932 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
12933
12934 static int nobs, *obscount, ip, okay;
12935
12936 /* Set timer... */
12937 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
12938
12939 /* Init... */
12940 if (t == ctl->t_start) {
12941
12942 /* Check quantity index for mass... */
12943 if (ctl->qnt_m < 0)
12944 ERRMSG("Need quantity mass!");
12945
12946 /* Check molar mass... */
12947 if (ctl->molmass <= 0)
12948 ERRMSG("Specify molar mass!");
12949
12950 /* Allocate... */
12951 ALLOC(lon, double,
12952 ctl->prof_nx);
12953 ALLOC(lat, double,
12954 ctl->prof_ny);
12955 ALLOC(area, double,
12956 ctl->prof_ny);
12957 ALLOC(z, double,
12958 ctl->prof_nz);
12959 ALLOC(press, double,
12960 ctl->prof_nz);
12961 ALLOC(rt, double,
12962 NOBS);
12963 ALLOC(rz, double,
12964 NOBS);
12965 ALLOC(rlon, double,
12966 NOBS);
12967 ALLOC(rlat, double,
12968 NOBS);
12969 ALLOC(robs, double,
12970 NOBS);
12971
12972 /* Read observation data... */
12973 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12974
12975 /* Create new output file... */
12976 LOG(1, "Write profile data: %s", filename);
12977 if (!(out = fopen(filename, "w")))
12978 ERRMSG("Cannot create file!");
12979
12980 /* Write header... */
12981 fprintf(out,
12982 "# $1 = time [s]\n"
12983 "# $2 = altitude [km]\n"
12984 "# $3 = longitude [deg]\n"
12985 "# $4 = latitude [deg]\n"
12986 "# $5 = pressure [hPa]\n"
12987 "# $6 = temperature [K]\n"
12988 "# $7 = volume mixing ratio [ppv]\n"
12989 "# $8 = H2O volume mixing ratio [ppv]\n"
12990 "# $9 = O3 volume mixing ratio [ppv]\n"
12991 "# $10 = observed BT index [K]\n"
12992 "# $11 = number of observations\n");
12993
12994 /* Set grid box size... */
12995 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
12996 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
12997 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
12998
12999 /* Set vertical coordinates... */
13000 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13001 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
13002 press[iz] = P(z[iz]);
13003 }
13004
13005 /* Set horizontal coordinates... */
13006 for (int ix = 0; ix < ctl->prof_nx; ix++)
13007 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
13008 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13009 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
13010 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
13011 }
13012 }
13013
13014 /* Set time interval... */
13015 const double t0 = t - 0.5 * ctl->dt_mod;
13016 const double t1 = t + 0.5 * ctl->dt_mod;
13017
13018 /* Allocate... */
13019 ALLOC(mass, double,
13020 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
13021 ALLOC(obsmean, double,
13022 ctl->prof_nx * ctl->prof_ny);
13023 ALLOC(obscount, int,
13024 ctl->prof_nx * ctl->prof_ny);
13025
13026 /* Loop over observations... */
13027 for (int i = 0; i < nobs; i++) {
13028
13029 /* Check time... */
13030 if (rt[i] < t0)
13031 continue;
13032 else if (rt[i] >= t1)
13033 break;
13034
13035 /* Check observation data... */
13036 if (!isfinite(robs[i]))
13037 continue;
13038
13039 /* Calculate indices... */
13040 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
13041 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
13042
13043 /* Check indices... */
13044 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
13045 continue;
13046
13047 /* Get mean observation index... */
13048 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
13049 obsmean[idx] += robs[i];
13050 obscount[idx]++;
13051 }
13052
13053 /* Analyze model data... */
13054 for (ip = 0; ip < atm->np; ip++) {
13055
13056 /* Check time... */
13057 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13058 continue;
13059
13060 /* Get indices... */
13061 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
13062 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
13063 const int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
13064
13065 /* Check indices... */
13066 if (ix < 0 || ix >= ctl->prof_nx ||
13067 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
13068 continue;
13069
13070 /* Get total mass in grid cell... */
13071 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13072 mass[idx] += atm->q[ctl->qnt_m][ip];
13073 }
13074
13075 /* Extract profiles... */
13076 for (int ix = 0; ix < ctl->prof_nx; ix++)
13077 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13078 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
13079 if (obscount[idx2] > 0) {
13080
13081 /* Check profile... */
13082 okay = 0;
13083 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13084 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13085 if (mass[idx3] > 0) {
13086 okay = 1;
13087 break;
13088 }
13089 }
13090 if (!okay)
13091 continue;
13092
13093 /* Write output... */
13094 fprintf(out, "\n");
13095
13096 /* Loop over altitudes... */
13097 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13098
13099 /* Get temperature, water vapor, and ozone... */
13101 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
13102 lon[ix], lat[iy], &temp, ci, cw, 1);
13103 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
13104 lon[ix], lat[iy], &h2o, ci, cw, 0);
13105 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
13106 lon[ix], lat[iy], &o3, ci, cw, 0);
13107
13108 /* Calculate volume mixing ratio... */
13109 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13110 vmr = MA / ctl->molmass * mass[idx3]
13111 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
13112
13113 /* Write output... */
13114 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
13115 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
13116 obsmean[idx2] / obscount[idx2], obscount[idx2]);
13117 }
13118 }
13119 }
13120
13121 /* Free... */
13122 free(mass);
13123 free(obsmean);
13124 free(obscount);
13125
13126 /* Finalize... */
13127 if (t == ctl->t_stop) {
13128
13129 /* Close output file... */
13130 fclose(out);
13131
13132 /* Free... */
13133 free(lon);
13134 free(lat);
13135 free(area);
13136 free(z);
13137 free(press);
13138 free(rt);
13139 free(rz);
13140 free(rlon);
13141 free(rlat);
13142 free(robs);
13143 }
13144}
13145
13146/*****************************************************************************/
13147
13149 const char *filename,
13150 const ctl_t *ctl,
13151 met_t *met0,
13152 met_t *met1,
13153 const atm_t *atm,
13154 const double t) {
13155
13156 static FILE *out;
13157
13158 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
13159 kw[EP];
13160
13161 static int nobs, nk;
13162
13163 /* Set timer... */
13164 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
13165
13166 /* Init... */
13167 if (t == ctl->t_start) {
13168
13169 /* Allocate... */
13170 ALLOC(rt, double,
13171 NOBS);
13172 ALLOC(rz, double,
13173 NOBS);
13174 ALLOC(rlon, double,
13175 NOBS);
13176 ALLOC(rlat, double,
13177 NOBS);
13178 ALLOC(robs, double,
13179 NOBS);
13180
13181 /* Read observation data... */
13182 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13183
13184 /* Read kernel data... */
13185 if (ctl->sample_kernel[0] != '-')
13186 read_kernel(ctl->sample_kernel, kz, kw, &nk);
13187
13188 /* Create output file... */
13189 LOG(1, "Write sample data: %s", filename);
13190 if (!(out = fopen(filename, "w")))
13191 ERRMSG("Cannot create file!");
13192
13193 /* Write header... */
13194 fprintf(out,
13195 "# $1 = time [s]\n"
13196 "# $2 = altitude [km]\n"
13197 "# $3 = longitude [deg]\n"
13198 "# $4 = latitude [deg]\n"
13199 "# $5 = surface area [km^2]\n"
13200 "# $6 = layer depth [km]\n"
13201 "# $7 = number of particles [1]\n"
13202 "# $8 = column density [kg/m^2]\n"
13203 "# $9 = volume mixing ratio [ppv]\n"
13204 "# $10 = observed BT index [K]\n\n");
13205
13206 /* Set latitude range, squared radius, and area... */
13207 dlat = DY2DEG(ctl->sample_dx);
13208 rmax2 = SQR(ctl->sample_dx);
13209 area = M_PI * rmax2;
13210 }
13211
13212 /* Set time interval for output... */
13213 const double t0 = t - 0.5 * ctl->dt_mod;
13214 const double t1 = t + 0.5 * ctl->dt_mod;
13215
13216 /* Loop over observations... */
13217 for (int i = 0; i < nobs; i++) {
13218
13219 /* Check time... */
13220 if (rt[i] < t0)
13221 continue;
13222 else if (rt[i] >= t1)
13223 break;
13224
13225 /* Calculate Cartesian coordinates... */
13226 double x0[3];
13227 geo2cart(0, rlon[i], rlat[i], x0);
13228
13229 /* Set pressure range... */
13230 const double rp = P(rz[i]);
13231 const double ptop = P(rz[i] + ctl->sample_dz);
13232 const double pbot = P(rz[i] - ctl->sample_dz);
13233
13234 /* Init... */
13235 double mass = 0;
13236 int np = 0;
13237
13238 /* Loop over air parcels... */
13239 //#pragma omp parallel for default(shared) reduction(+:mass,np)
13240 for (int ip = 0; ip < atm->np; ip++) {
13241
13242 /* Check time... */
13243 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13244 continue;
13245
13246 /* Check latitude... */
13247 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
13248 continue;
13249
13250 /* Check horizontal distance... */
13251 double x1[3];
13252 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13253 if (DIST2(x0, x1) > rmax2)
13254 continue;
13255
13256 /* Check pressure... */
13257 if (ctl->sample_dz > 0)
13258 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
13259 continue;
13260
13261 /* Add mass... */
13262 if (ctl->qnt_m >= 0)
13263 mass +=
13264 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13265 np++;
13266 }
13267
13268 /* Calculate column density... */
13269 const double cd = mass / (1e6 * area);
13270
13271 /* Calculate volume mixing ratio... */
13272 double vmr = 0;
13273 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
13274 if (mass > 0) {
13275
13276 /* Get temperature... */
13277 double temp;
13279 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
13280 rlon[i], rlat[i], &temp, ci, cw, 1);
13281
13282 /* Calculate volume mixing ratio... */
13283 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
13284 }
13285 } else
13286 vmr = NAN;
13287
13288 /* Write output... */
13289 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
13290 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
13291 }
13292
13293 /* Finalize...... */
13294 if (t == ctl->t_stop) {
13295
13296 /* Close output file... */
13297 fclose(out);
13298
13299 /* Free... */
13300 free(rt);
13301 free(rz);
13302 free(rlon);
13303 free(rlat);
13304 free(robs);
13305 }
13306}
13307
13308/*****************************************************************************/
13309
13311 const char *filename,
13312 const ctl_t *ctl,
13313 atm_t *atm,
13314 const double t) {
13315
13316 static FILE *out;
13317
13318 static double rmax2, x0[3], x1[3];
13319
13320 /* Set timer... */
13321 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
13322
13323 /* Init... */
13324 if (t == ctl->t_start) {
13325
13326 /* Write info... */
13327 LOG(1, "Write station data: %s", filename);
13328
13329 /* Create new file... */
13330 if (!(out = fopen(filename, "w")))
13331 ERRMSG("Cannot create file!");
13332
13333 /* Write header... */
13334 fprintf(out,
13335 "# $1 = time [s]\n"
13336 "# $2 = altitude [km]\n"
13337 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13338 for (int iq = 0; iq < ctl->nq; iq++)
13339 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
13340 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13341 fprintf(out, "\n");
13342
13343 /* Set geolocation and search radius... */
13344 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
13345 rmax2 = SQR(ctl->stat_r);
13346 }
13347
13348 /* Set time interval for output... */
13349 const double t0 = t - 0.5 * ctl->dt_mod;
13350 const double t1 = t + 0.5 * ctl->dt_mod;
13351
13352 /* Loop over air parcels... */
13353 for (int ip = 0; ip < atm->np; ip++) {
13354
13355 /* Check time... */
13356 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13357 continue;
13358
13359 /* Check time range for station output... */
13360 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
13361 continue;
13362
13363 /* Check station flag... */
13364 if (ctl->qnt_stat >= 0)
13365 if ((int) atm->q[ctl->qnt_stat][ip])
13366 continue;
13367
13368 /* Get Cartesian coordinates... */
13369 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13370
13371 /* Check horizontal distance... */
13372 if (DIST2(x0, x1) > rmax2)
13373 continue;
13374
13375 /* Set station flag... */
13376 if (ctl->qnt_stat >= 0)
13377 atm->q[ctl->qnt_stat][ip] = 1;
13378
13379 /* Write data... */
13380 fprintf(out, "%.2f %g %g %g",
13381 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
13382 for (int iq = 0; iq < ctl->nq; iq++) {
13383 fprintf(out, " ");
13384 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
13385 }
13386 fprintf(out, "\n");
13387 }
13388
13389 /* Close file... */
13390 if (t == ctl->t_stop)
13391 fclose(out);
13392}
13393
13394/*****************************************************************************/
13395
13397 const char *filename,
13398 const ctl_t *ctl,
13399 const atm_t *atm,
13400 const double t) {
13401
13402 FILE *out;
13403
13404 /* Set timer... */
13405 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
13406
13407 /* Write info... */
13408 LOG(1, "Write VTK data: %s", filename);
13409
13410 /* Set time interval for output... */
13411 const double t0 = t - 0.5 * ctl->dt_mod;
13412 const double t1 = t + 0.5 * ctl->dt_mod;
13413
13414 /* Create file... */
13415 if (!(out = fopen(filename, "w")))
13416 ERRMSG("Cannot create file!");
13417
13418 /* Count data points... */
13419 int np = 0;
13420 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13421 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13422 continue;
13423 np++;
13424 }
13425
13426 /* Write header... */
13427 fprintf(out,
13428 "# vtk DataFile Version 3.0\n"
13429 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
13430
13431 /* Write point coordinates... */
13432 fprintf(out, "POINTS %d float\n", np);
13433 if (ctl->vtk_sphere) {
13434 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13435 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13436 continue;
13437 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
13438 + ctl->vtk_offset) / RE;
13439 const double coslat = cos(DEG2RAD(atm->lat[ip]));
13440 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
13441 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
13442 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
13443 fprintf(out, "%g %g %g\n", x, y, z);
13444 }
13445 } else
13446 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13447 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13448 continue;
13449 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
13450 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
13451 }
13452
13453 /* Write point data... */
13454 fprintf(out, "POINT_DATA %d\n", np);
13455 for (int iq = 0; iq < ctl->nq; iq++) {
13456 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
13457 ctl->qnt_name[iq]);
13458 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13459 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13460 continue;
13461 fprintf(out, "%g\n", atm->q[iq][ip]);
13462 }
13463 }
13464
13465 /* Close file... */
13466 fclose(out);
13467}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:8119
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:5153
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:6775
void day2doy(const int year, const int mon, const int day, int *doy)
Get day of year from date.
Definition: mptrac.c:1049
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:8079
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:11463
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:8749
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:12862
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:10502
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:12608
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:10847
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:2969
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:4869
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:4186
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:7207
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:7918
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:3572
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:11020
double cos_sza(const double sec, const double lon, const double lat)
Calculates the cosine of the solar zenith angle.
Definition: mptrac.c:1008
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:2368
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:9011
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:7174
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:10110
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:7975
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:10675
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:10891
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:3417
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:2930
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:2068
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:8552
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:9745
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:7326
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:10247
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:6515
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:4916
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:11945
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:4293
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:405
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:4364
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:7298
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:9703
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:204
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:10919
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:7668
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:2866
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:4010
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:2656
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:12233
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:6663
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:11121
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:5361
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:2426
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:1920
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:5018
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:677
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:6970
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:11053
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:3255
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:147
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:7380
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:9870
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:4737
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:9830
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:11152
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:11278
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:2310
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:3459
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:7479
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:3159
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:10948
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:3132
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:5239
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:4831
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:11100
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:2488
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:7697
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:2896
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:11220
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:12921
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:5451
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:11255
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:12698
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:4601
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:5380
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:6719
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:6879
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:10473
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:8414
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:232
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:4632
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:1977
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:13310
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
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:1890
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:2138
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:2455
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:4550
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:2949
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:12579
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:10367
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:7058
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:2044
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:3611
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:4766
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:387
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:2579
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:7520
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:11410
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:3813
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:7114
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:6406
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:13396
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:4947
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:5511
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:5206
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:10308
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:3928
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:12337
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:6994
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:3688
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:12891
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:4080
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:4466
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:1959
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:8247
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:2612
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:7016
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:2111
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:13148
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:12042
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:3865
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:12467
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:11360
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:7803
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:6835
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:2638
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:11670
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:11621
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
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 double *plev, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using a custom multiscale compression algorithm.
#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_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)
Extracts particles from an atmospheric state and prepares them for inter-domain transfer.
#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)
Computes the destination subdomain (MPI rank) for a particle based on its geographic coordinates.
#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:3297
double time[NP]
Time [s].
Definition: mptrac.h:3303
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3312
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3309
int np
Number of air parcels.
Definition: mptrac.h:3300
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3315
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3306
Cache data structure.
Definition: mptrac.h:3352
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3373
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3361
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3364
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3358
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3370
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3367
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3355
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3384
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3390
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3399
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3420
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3396
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3414
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3417
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3411
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3405
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3426
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3429
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3408
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3423
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3402
int np
Number of pressure levels.
Definition: mptrac.h:3387
int no3c
Number of total ozone columns.
Definition: mptrac.h:3393
Climatological data.
Definition: mptrac.h:3492
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3534
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3510
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3522
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3513
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3495
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3540
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3528
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3531
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3525
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3504
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3519
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3498
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3516
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3507
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3501
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3537
Climatological data in the form of time series.
Definition: mptrac.h:3440
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3449
double time[CTS]
Time [s].
Definition: mptrac.h:3446
int ntime
Number of timesteps.
Definition: mptrac.h:3443
Climatological data in the form of zonal means.
Definition: mptrac.h:3460
double time[CT]
Time [s].
Definition: mptrac.h:3472
int np
Number of pressure levels.
Definition: mptrac.h:3469
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3478
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3481
int ntime
Number of timesteps.
Definition: mptrac.h:3463
int nlat
Number of latitudes.
Definition: mptrac.h:3466
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3475
Control parameters.
Definition: mptrac.h:2264
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3158
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:3119
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3086
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:3007
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:3095
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2869
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:3285
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:3047
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2932
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2956
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:3089
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:2908
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2857
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3110
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2364
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3236
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2917
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2768
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2929
double stat_r
Search radius around station [km].
Definition: mptrac.h:3242
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:3001
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:3113
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3266
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2953
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2736
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:2971
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2821
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:2658
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:3185
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3161
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2574
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2775
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:2688
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2755
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:2866
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3104
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3116
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2803
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2733
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:2812
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3146
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3164
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3060
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2830
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3176
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:2661
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:3167
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:2752
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3221
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:2890
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2974
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2724
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3137
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2649
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2797
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:2845
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3248
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3080
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2794
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3182
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3107
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:2980
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3152
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:2962
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2863
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:2721
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2694
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:2785
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3188
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2772
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2851
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:3191
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3083
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2730
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3092
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2691
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2965
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2809
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2673
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2676
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3134
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2652
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3194
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:2836
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2746
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3200
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:2743
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:2761
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2920
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:3101
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3245
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2983
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3273
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2893
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:2878
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:3019
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2926
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:3065
int met_cms_nd0x
cmultiscale number of cells of coarsest grid in x-direction.
Definition: mptrac.h:2634
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2712
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2992
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3077
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:3028
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:3254
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2580
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2827
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3224
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:3131
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:2679
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2842
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2739
int met_dx
Stride for longitudes.
Definition: mptrac.h:2682
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:2941
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:2887
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2995
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:2788
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:3263
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:2839
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2758
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:2709
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2977
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:3209
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:3230
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2875
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3074
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3149
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2667
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:2643
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3170
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:3044
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2944
int nens
Number of ensembles.
Definition: mptrac.h:3122
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:2778
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3197
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2715
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:3053
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2989
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:2818
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3125
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2998
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:3098
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2496
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3239
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:3016
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3173
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:2700
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2815
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2590
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2854
int dd_nbr_neighbours
Domain decomposition number of neighbours to communicate with.
Definition: mptrac.h:3282
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2646
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2950
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:2833
int met_cms_nd0y
cmultiscale number of cells of coarsest grid in y-direction.
Definition: mptrac.h:2637
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2923
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:2848
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2935
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2899
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:3155
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2884
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:3128
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3218
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3056
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2727
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2947
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:3050
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2911
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3215
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2628
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:3034
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2697
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3203
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2959
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:2718
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3212
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:3037
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3206
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2670
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:2986
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:3071
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:3025
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2968
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2902
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2664
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2631
int met_cms_maxlev
cmultiscale maximum refinement level.
Definition: mptrac.h:2640
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3143
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3251
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:3031
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2343
int met_np
Number of target pressure levels.
Definition: mptrac.h:2703
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:2914
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:3260
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2905
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2655
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3013
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2791
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2824
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:2782
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:2938
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3068
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2881
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:3022
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:3010
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:3004
int met_dy
Stride for latitudes.
Definition: mptrac.h:2685
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:2806
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2860
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3276
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:2749
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:2706
int nq
Number of quantities.
Definition: mptrac.h:2271
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2872
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3227
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3257
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3233
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2800
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3179
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3279
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:3140
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2508
Domain decomposition data structure.
Definition: mptrac.h:3725
size_t halo_bnd_count[4]
Hyperslab of boundary halos count.
Definition: mptrac.h:3771
int halo_offset_end
Hyperslab of boundary halos count.
Definition: mptrac.h:3777
int rank
Rank of node.
Definition: mptrac.h:3732
int neighbours[DD_NNMAX]
Rank of neighbouring nodes.
Definition: mptrac.h:3738
double subdomain_lon_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3753
size_t halo_bnd_start[4]
Hyperslab of boundary halos start.
Definition: mptrac.h:3768
double subdomain_lat_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3756
int init
Shows if domain decomposition was initialized.
Definition: mptrac.h:3784
double subdomain_lon_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3750
int halo_offset_start
Hyperslab of boundary halos count.
Definition: mptrac.h:3774
size_t subdomain_count[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3765
size_t subdomain_start[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3762
int size
Size of node.
Definition: mptrac.h:3735
double subdomain_lat_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3759
Meteo data structure.
Definition: mptrac.h:3551
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3629
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3617
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3689
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3659
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3716
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3680
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3653
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3674
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3635
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3578
int nx
Number of longitudes.
Definition: mptrac.h:3557
int ny
Number of latitudes.
Definition: mptrac.h:3560
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3611
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3590
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3686
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3599
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3710
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3707
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3596
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3683
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3698
int np
Number of pressure levels.
Definition: mptrac.h:3563
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3665
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3593
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3668
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3605
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3704
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3638
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3650
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3656
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3644
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3569
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3623
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3626
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3620
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3602
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3662
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3671
int npl
Number of model levels.
Definition: mptrac.h:3566
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3614
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3692
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3632
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3677
double eta[EP]
Model level eta values.
Definition: mptrac.h:3587
double time
Time [s].
Definition: mptrac.h:3554
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3641
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3608
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3701
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3647
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3581
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3572
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3695
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3584
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3713
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3575
Particle data.
Definition: mptrac.h:3326
double p
Pressure [hPa].
Definition: mptrac.h:3332
double lat
Latitude [deg].
Definition: mptrac.h:3338
double time
Time [s].
Definition: mptrac.h:3329
double lon
Longitude [deg].
Definition: mptrac.h:3335
double q[NQ]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3341