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-2026 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 /* Set reference coordinates... */
101 const double lat_ref =
102 ctl->met_coord_type == 0 ? lat : ctl->met_utm_ref_lat;
103 double lon_ref = ctl->met_coord_type == 0 ? lon : ctl->met_utm_ref_lon;
104 while (lon_ref < -180.0)
105 lon_ref += 360.0;
106 while (lon_ref >= 180.0)
107 lon_ref -= 360.0;
108
109 /* Get OH data from climatology... */
110 const double oh = clim_zm(&clim->oh, t, lat_ref, p);
111
112 /* Check beta... */
113 if (ctl->oh_chem_beta <= 0)
114 return oh;
115
116 /* Apply diurnal correction... */
117 const double csza = cos_sza(t, lon_ref, lat_ref);
118 const double denom = (csza >= csza_thresh) ? csza : csza_thresh;
119 return oh * exp(-ctl->oh_chem_beta / denom);
120}
121
122/*****************************************************************************/
123
125 const ctl_t *ctl,
126 clim_t *clim) {
127
128 /* Set SZA threshold... */
129 const double sza_thresh = DEG2RAD(85.), csza_thresh = cos(sza_thresh);
130
131 /* Loop over climatology data points... */
132 for (int it = 0; it < clim->oh.ntime; it++)
133 for (int iz = 0; iz < clim->oh.np; iz++)
134 for (int iy = 0; iy < clim->oh.nlat; iy++) {
135
136 /* Init... */
137 int n = 0;
138 double sum = 0;
139
140 /* Integrate day/night correction factor over longitude... */
141 for (double lon = -180; lon < 180; lon += 1.0) {
142 const double csza =
143 cos_sza(clim->oh.time[it], lon, clim->oh.lat[iy]);
144 const double denom = (csza >= csza_thresh) ? csza : csza_thresh;
145 sum += exp(-ctl->oh_chem_beta / denom);
146 n++;
147 }
148
149 /* Apply scaling factor to OH data... */
150 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
151 }
152}
153
154/*****************************************************************************/
155
157 const double rate[CP][CSZA][CO3],
158 const clim_photo_t *photo,
159 const double p,
160 const double sza,
161 const double o3c) {
162
163 /* Check pressure range... */
164 double p_help = p;
165 if (p < photo->p[photo->np - 1])
166 p_help = photo->p[photo->np - 1];
167 else if (p > photo->p[0])
168 p_help = photo->p[0];
169
170 /* Check sza range... */
171 double sza_help = sza;
172 if (sza < photo->sza[0])
173 sza_help = photo->sza[0];
174 else if (sza > photo->sza[photo->nsza - 1])
175 sza_help = photo->sza[photo->nsza - 1];
176
177 /* Check ozone column range... */
178 double o3c_help = o3c;
179 if (o3c < photo->o3c[0])
180 o3c_help = photo->o3c[0];
181 else if (o3c > photo->o3c[photo->no3c - 1])
182 o3c_help = photo->o3c[photo->no3c - 1];
183
184 /* Get indices... */
185 const int ip = locate_irr(photo->p, photo->np, p_help);
186 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
187 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
188
189 /* Interpolate photolysis rate... */
190 const double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
191 photo->p[ip + 1], rate[ip + 1][isza][io3c],
192 p_help);
193 const double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
194 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1],
195 p_help);
196 const double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
197 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c],
198 p_help);
199 const double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
200 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
201 p_help);
202 const double aux0 =
203 LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
204 const double aux1 =
205 LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
206 const double aux =
207 LIN(photo->sza[isza], aux0, photo->sza[isza + 1], aux1, sza_help);
208 return MAX(aux, 0.0);
209}
210
211/*****************************************************************************/
212
214 const clim_t *clim,
215 const double t,
216 const double lat) {
217
218 /* Get seconds since begin of year... */
219 double sec = FMOD(t, 365.25 * 86400.);
220 while (sec < 0)
221 sec += 365.25 * 86400.;
222
223 /* Get indices... */
224 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
225 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
226
227 /* Interpolate tropopause pressure... */
228 const double p0 = LIN(clim->tropo_lat[ilat],
229 clim->tropo[isec][ilat],
230 clim->tropo_lat[ilat + 1],
231 clim->tropo[isec][ilat + 1], lat);
232 const double p1 = LIN(clim->tropo_lat[ilat],
233 clim->tropo[isec + 1][ilat],
234 clim->tropo_lat[ilat + 1],
235 clim->tropo[isec + 1][ilat + 1], lat);
236 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
237}
238
239/*****************************************************************************/
240
242 clim_t *clim) {
243
244 /* Write info... */
245 LOG(1, "Initialize tropopause data...");
246
247 /* Set time [s]... */
248 clim->tropo_ntime = 12;
249 double tropo_time[12] = {
250 1209600.00, 3888000.00, 6393600.00,
251 9072000.00, 11664000.00, 14342400.00,
252 16934400.00, 19612800.00, 22291200.00,
253 24883200.00, 27561600.00, 30153600.00
254 };
255 memcpy(clim->tropo_time, tropo_time, sizeof(clim->tropo_time));
256
257 /* Set latitudes [deg]... */
258 clim->tropo_nlat = 73;
259 const double tropo_lat[73] = {
260 -90, -87.5, -85, -82.5, -80, -77.5, -75, -72.5, -70, -67.5,
261 -65, -62.5, -60, -57.5, -55, -52.5, -50, -47.5, -45, -42.5,
262 -40, -37.5, -35, -32.5, -30, -27.5, -25, -22.5, -20, -17.5,
263 -15, -12.5, -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10, 12.5,
264 15, 17.5, 20, 22.5, 25, 27.5, 30, 32.5, 35, 37.5, 40, 42.5,
265 45, 47.5, 50, 52.5, 55, 57.5, 60, 62.5, 65, 67.5, 70, 72.5,
266 75, 77.5, 80, 82.5, 85, 87.5, 90
267 };
268 memcpy(clim->tropo_lat, tropo_lat, sizeof(clim->tropo_lat));
269
270 /* Set tropopause pressure [hPa] (NCEP/NCAR Reanalysis 1)... */
271 const double tropo[12][73] = {
272 {324.1, 325.6, 325, 324.3, 322.5, 319.7, 314, 307.2, 301.8, 299.6,
273 297.1, 292.2, 285.6, 276.1, 264, 248.9, 231.9, 213.5, 194.4,
274 175.3, 157, 140.4, 126.7, 116.3, 109.5, 105.4, 103, 101.4, 100.4,
275 99.69, 99.19, 98.84, 98.56, 98.39, 98.39, 98.42, 98.44, 98.54,
276 98.68, 98.81, 98.89, 98.96, 99.12, 99.65, 101.4, 105.4, 113.5, 128,
277 152.1, 184.7, 214, 234.1, 247.3, 255.8, 262.6, 267.7, 271.7, 275,
278 277.2, 279, 280.1, 280.4, 280.6, 280.1, 279.3, 278.3, 276.8, 275.8,
279 275.3, 275.6, 275.4, 274.1, 273.5},
280 {337.3, 338.7, 337.8, 336.4, 333, 328.8, 321.1, 312.6, 306.6, 303.7,
281 300.2, 293.8, 285.4, 273.8, 259.6, 242.7, 224.4, 205.2, 186, 167.5,
282 150.3, 135, 122.8, 113.9, 108.2, 104.7, 102.5, 101.1, 100.2, 99.42,
283 98.88, 98.52, 98.25, 98.09, 98.07, 98.1, 98.12, 98.2, 98.25, 98.27,
284 98.26, 98.27, 98.36, 98.79, 100.2, 104.2, 113.7, 131.2, 159.5, 193,
285 220.4, 238.1, 250.2, 258.1, 264.7, 269.7, 273.7, 277.3, 280.2, 282.8,
286 284.9, 286.5, 288.1, 288.8, 289, 288.5, 287.2, 286.3, 286.1, 287.2,
287 287.5, 286.2, 285.8},
288 {335, 336, 335.7, 335.1, 332.3, 328.1, 320.6, 311.8, 305.1, 301.9,
289 297.6, 290, 280.4, 268.3, 254.6, 239.6, 223.9, 207.9, 192.2, 176.9,
290 161.7, 146.4, 132.2, 120.6, 112.3, 107.2, 104.3, 102.4, 101.3,
291 100.4, 99.86, 99.47, 99.16, 98.97, 98.94, 98.97, 99, 99.09, 99.2,
292 99.31, 99.35, 99.41, 99.51, 99.86, 101.1, 104.9, 114.3, 131, 156.8,
293 186.3, 209.3, 224.6, 236.8, 246.3, 254.9, 262.3, 268.8, 274.8,
294 279.9, 284.6, 288.6, 291.6, 294.9, 297.5, 299.8, 301.8, 303.1,
295 304.3, 304.9, 306, 306.6, 306.2, 306},
296 {306.2, 306.7, 305.7, 307.1, 307.3, 306.4, 301.8, 296.2, 292.4,
297 290.3, 287.1, 280.9, 273.4, 264.3, 254.1, 242.8, 231, 219, 207.2,
298 195.5, 183.3, 169.7, 154.7, 138.7, 124.1, 113.6, 107.8, 104.7,
299 102.8, 101.7, 100.9, 100.4, 100, 99.79, 99.7, 99.66, 99.68, 99.79,
300 99.94, 100.2, 100.5, 100.9, 101.4, 102.1, 103.4, 107, 115.2, 129.1,
301 148.7, 171, 190.8, 205.6, 218.4, 229.4, 239.6, 248.6, 256.5,
302 263.7, 270.3, 276.6, 282.6, 288.1, 294.5, 300.4, 306.3, 311.4,
303 315.1, 318.3, 320.3, 322.2, 322.8, 321.5, 321.1},
304 {266.5, 264.9, 260.8, 261, 262, 263, 261.3, 259.7, 259.2, 259.8,
305 260.1, 258.6, 256.7, 253.6, 249.5, 243.9, 237.4, 230, 222.1, 213.9,
306 205, 194.4, 180.4, 161.8, 140.7, 122.9, 112.1, 106.7, 104.1, 102.7,
307 101.8, 101.4, 101.1, 101, 101, 101, 101.1, 101.2, 101.5, 101.9,
308 102.4, 103, 103.8, 104.9, 106.8, 110.1, 115.6, 124, 135.2, 148.9,
309 165.2, 181.3, 198, 211.8, 223.5, 233.8, 242.9, 251.5, 259, 266.2,
310 273.1, 279.2, 286.2, 292.8, 299.6, 306, 311.1, 315.5, 318.8, 322.6,
311 325.3, 325.8, 325.8},
312 {220.1, 218.1, 210.8, 207.2, 207.6, 210.5, 211.4, 213.5, 217.3,
313 222.4, 227.9, 232.8, 237.4, 240.8, 242.8, 243, 241.5, 238.6, 234.2,
314 228.5, 221, 210.7, 195.1, 172.9, 147.8, 127.6, 115.6, 109.9, 107.1,
315 105.7, 105, 104.8, 104.8, 104.9, 105, 105.1, 105.3, 105.5, 105.8,
316 106.4, 107, 107.6, 108.1, 108.8, 110, 111.8, 114.2, 117.4, 121.6,
317 127.9, 137.3, 151.2, 169.5, 189, 205.8, 218.9, 229.1, 237.8, 245,
318 251.5, 257.1, 262.3, 268.2, 274, 280.4, 286.7, 292.4, 297.9, 302.9,
319 308.5, 312.2, 313.1, 313.3},
320 {187.4, 184.5, 173.3, 166.1, 165.4, 167.8, 169.6, 173.6, 179.6,
321 187.9, 198.9, 210, 220.5, 229.2, 235.7, 239.9, 241.8, 241.6, 239.6,
322 235.8, 229.4, 218.6, 200.9, 175.9, 149.4, 129.4, 118.3, 113.1,
323 110.8, 109.7, 109.3, 109.4, 109.7, 110, 110.2, 110.4, 110.5, 110.7,
324 111, 111.4, 111.8, 112.1, 112.3, 112.7, 113.2, 113.9, 115, 116.4,
325 117.9, 120.4, 124.1, 130.9, 142.2, 159.6, 179.6, 198.5, 212.9,
326 224.2, 232.7, 239.1, 243.8, 247.7, 252.4, 257.3, 263.2, 269.5,
327 275.4, 281.1, 286.3, 292, 296.3, 298.2, 298.8},
328 {166, 166.4, 155.7, 148.3, 147.1, 149, 152.1, 157, 163.6, 172.4,
329 185.3, 199.2, 212.6, 224, 233.2, 239.6, 243.3, 244.6, 243.6, 240.3,
330 233.9, 222.6, 203.7, 177, 149.5, 129.7, 119, 114, 111.7, 110.7,
331 110.3, 110.3, 110.6, 110.9, 111.1, 111.3, 111.5, 111.6, 111.9,
332 112.2, 112.5, 112.6, 112.8, 113, 113.4, 114, 115.1, 116.5, 118.3,
333 120.9, 124.4, 130.2, 139.4, 154.6, 173.8, 193.1, 208.1, 220.4,
334 230.1, 238.2, 244.7, 249.5, 254.5, 259.3, 264.5, 269.4, 273.7,
335 278.2, 282.6, 287.4, 290.9, 292.5, 293},
336 {171.9, 172.8, 166.2, 162.3, 161.4, 162.5, 165.2, 169.6, 175.3,
337 183.1, 193.8, 205.9, 218.3, 229.6, 238.5, 244.3, 246.9, 246.7,
338 243.8, 238.4, 230.2, 217.9, 199.6, 174.9, 148.9, 129.8, 119.5,
339 114.8, 112.3, 110.9, 110.3, 110.1, 110.2, 110.3, 110.4, 110.5,
340 110.6, 110.8, 111, 111.4, 111.8, 112, 112.2, 112.4, 112.9, 113.6,
341 114.7, 116.3, 118.4, 121.9, 127.1, 136.1, 149.8, 168.4, 186.9,
342 203.3, 217, 229.1, 238.7, 247, 254, 259.3, 264.3, 268.3, 272.5,
343 276.6, 280.4, 284.4, 288.4, 293.3, 297.2, 298.7, 299.1},
344 {191.6, 192.2, 189, 188.1, 190.2, 193.7, 197.8, 202.9, 208.5,
345 215.6, 224.2, 233.1, 241.2, 247.3, 250.8, 251.3, 248.9, 244.2,
346 237.3, 228.4, 217.2, 202.9, 184.5, 162.5, 140.7, 124.8, 116.2,
347 111.8, 109.4, 107.9, 107, 106.7, 106.6, 106.6, 106.7, 106.7,
348 106.8, 107, 107.4, 108, 108.7, 109.3, 109.8, 110.4, 111.2,
349 112.4, 114.2, 116.9, 121.1, 127.9, 139.3, 155.2, 173.6, 190.7,
350 206.1, 220.1, 232.3, 243, 251.8, 259.2, 265.7, 270.6, 275.3,
351 279.3, 283.3, 286.9, 289.7, 292.8, 296.1, 300.5, 303.9, 304.8,
352 305.1},
353 {241.5, 239.6, 236.8, 237.4, 239.4, 242.3, 244.2, 246.4, 249.2,
354 253.6, 258.6, 262.7, 264.8, 264.2, 260.6, 254.1, 245.5, 235.3,
355 223.9, 211.7, 198.3, 183.1, 165.6, 147.1, 130.5, 118.7, 111.9,
356 108.1, 105.8, 104.3, 103.4, 102.8, 102.5, 102.4, 102.5, 102.5,
357 102.5, 102.7, 103.1, 103.8, 104.6, 105.4, 106.1, 107, 108.2,
358 109.9, 112.8, 117.5, 126, 140.4, 161, 181.9, 201.2, 216.8, 230.4,
359 241.8, 251.4, 259.9, 266.9, 272.8, 277.4, 280.4, 282.9, 284.6,
360 286.1, 287.4, 288.3, 289.5, 290.9, 294.2, 296.9, 297.5, 297.6},
361 {301.2, 300.3, 296.6, 295.4, 295, 294.3, 291.2, 287.4, 284.9, 284.7,
362 284.1, 281.5, 277.1, 270.4, 261.7, 250.6, 237.6, 223.1, 207.9, 192,
363 175.8, 158.8, 142.1, 127.6, 116.8, 109.9, 106, 103.6, 102.1, 101.1,
364 100.4, 99.96, 99.6, 99.37, 99.32, 99.32, 99.31, 99.46, 99.77, 100.2,
365 100.7, 101.3, 101.8, 102.7, 104.1, 106.8, 111.9, 121, 136.7, 160,
366 186.9, 209.9, 228.1, 241.2, 251.5, 259.5, 265.7, 270.9, 274.8, 278,
367 280.3, 281.8, 283, 283.3, 283.7, 283.8, 283, 282.2, 281.2, 281.4,
368 281.7, 281.1, 281.2}
369 };
370 memcpy(clim->tropo, tropo, sizeof(clim->tropo));
371
372 /* Get range... */
373 double tropomin = 1e99, tropomax = -1e99;
374 for (int it = 0; it < clim->tropo_ntime; it++)
375 for (int iy = 0; iy < clim->tropo_nlat; iy++) {
376 tropomin = MIN(tropomin, clim->tropo[it][iy]);
377 tropomax = MAX(tropomax, clim->tropo[it][iy]);
378 }
379
380 /* Write info... */
381 LOG(2, "Number of time steps: %d", clim->tropo_ntime);
382 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
383 clim->tropo_time[0], clim->tropo_time[1],
384 clim->tropo_time[clim->tropo_ntime - 1]);
385 LOG(2, "Number of latitudes: %d", clim->tropo_nlat);
386 LOG(2, "Latitudes: %g, %g ... %g deg",
387 clim->tropo_lat[0], clim->tropo_lat[1],
388 clim->tropo_lat[clim->tropo_nlat - 1]);
389 LOG(2, "Tropopause altitude range: %g ... %g hPa", Z(tropomax),
390 Z(tropomin));
391 LOG(2, "Tropopause pressure range: %g ... %g hPa", tropomin, tropomax);
392}
393
394/*****************************************************************************/
395
396double clim_ts(
397 const clim_ts_t *ts,
398 const double t) {
399
400 /* Interpolate... */
401 if (t <= ts->time[0])
402 return ts->vmr[0];
403 else if (t >= ts->time[ts->ntime - 1])
404 return ts->vmr[ts->ntime - 1];
405 else {
406 const int idx = locate_irr(ts->time, ts->ntime, t);
407 return LIN(ts->time[idx], ts->vmr[idx],
408 ts->time[idx + 1], ts->vmr[idx + 1], t);
409 }
410}
411
412/*****************************************************************************/
413
414double clim_zm(
415 const clim_zm_t *zm,
416 const double t,
417 const double lat,
418 const double p) {
419
420 /* Get seconds since begin of year... */
421 double sec = FMOD(t, 365.25 * 86400.);
422 while (sec < 0)
423 sec += 365.25 * 86400.;
424
425 /* Check pressure range... */
426 double p_help = p;
427 if (p < zm->p[zm->np - 1])
428 p_help = zm->p[zm->np - 1];
429 else if (p > zm->p[0])
430 p_help = zm->p[0];
431
432 /* Check latitude range... */
433 double lat_help = lat;
434 if (lat < zm->lat[0])
435 lat_help = zm->lat[0];
436 else if (lat > zm->lat[zm->nlat - 1])
437 lat_help = zm->lat[zm->nlat - 1];
438
439 /* Get indices... */
440 const int isec = locate_irr(zm->time, zm->ntime, sec);
441 const int ilat = locate_reg(zm->lat, zm->nlat, lat_help);
442 const int ip = locate_irr(zm->p, zm->np, p_help);
443
444 /* Interpolate climatology data... */
445 const double aux00 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat],
446 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat],
447 p_help);
448 const double aux01 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat + 1],
449 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat + 1],
450 p_help);
451 const double aux10 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat],
452 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat],
453 p_help);
454 const double aux11 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat + 1],
455 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat + 1],
456 p_help);
457 const double aux0 =
458 LIN(zm->lat[ilat], aux00, zm->lat[ilat + 1], aux01, lat_help);
459 const double aux1 =
460 LIN(zm->lat[ilat], aux10, zm->lat[ilat + 1], aux11, lat_help);
461 const double aux = LIN(zm->time[isec], aux0, zm->time[isec + 1], aux1, sec);
462 return MAX(aux, 0.0);
463}
464
465/*****************************************************************************/
466
467#ifdef CMS
468void compress_cms(
469 const ctl_t *ctl,
470 const met_t *met,
471 const char *varname,
472 float *array,
473 const int decompress,
474 FILE *level_log,
475 FILE *inout) {
476
477 const size_t nx = (size_t) met->nx;
478 const size_t ny = (size_t) met->ny;
479 const size_t np = (size_t) met->np;
480 const size_t nxy = nx * ny;
481
482 /* Get meteo variable... */
483 const int metvar = compress_metvar_index(varname);
484
485 /* Set lon-lat grid... */
486 double lon[EX], lat[EY];
487 for (size_t ix = 0; ix < nx; ix++)
488 lon[ix] = 360. * (double) ix / ((double) nx - 1.);
489 for (size_t iy = 0; iy < ny; iy++)
490 lat[iy] = 90. - 180. * (double) iy / ((double) ny - 1.);
491
492 /* Set multiscale parameters... */
493 const char domain[] = "[0.0, 360.0]x[-90.0, 90.0]";
494 const int Nd0_x = ctl->met_cms_nd0x;
495 const int Nd0_y = ctl->met_cms_nd0y;
496 const int max_level_grid = ctl->met_cms_maxlev;
497 cms_param_t *cms_param
498 = cms_set_parameters(nx, ny, max_level_grid, Nd0_x, Nd0_y, domain);
499
500 /* Init... */
501 double cr = 0, t_coars = 0, t_eval = 0;
502
503 /* Read compressed stream and decompress array... */
504 if (decompress) {
505 t_eval = 0;
506
507 /* Loop over levels... */
508 for (size_t ip = 0; ip < np; ip++) {
509
510 /* Initialize multiscale module... */
511 cms_module_t *cms_ptr = cms_init(cms_param);
512
513 /* Read binary data... */
514 cms_sol_t *cms_sol;
515 if (ctl->met_cms_zstd == 1)
516 cms_sol = cms_read_zstd_sol(cms_ptr, inout);
517 else
518 cms_sol = cms_read_sol(cms_ptr, inout);
519
520 /* Evaluate current level... */
521 const double t0 = omp_get_wtime();
522#pragma omp parallel for collapse(2) default(shared)
523 for (size_t ix = 0; ix < nx; ix++)
524 for (size_t iy = 0; iy < ny; iy++) {
525 double val;
526 const double x[] = { lon[ix], lat[iy] };
527 cms_eval(cms_ptr, cms_sol, x, &val);
528 array[ARRAY_3D(ix, iy, ny, ip, np)] = (float) val;
529 }
530 t_eval += omp_get_wtime() - t0;
531
532 /* Calculate harmonic mean of compression rates... */
533 cr += 1.0 / cms_compression_rate(cms_ptr, cms_sol);
534
535 /* Free... */
536 cms_delete_sol(cms_sol);
537 cms_delete_module(cms_ptr);
538 }
539
540 /* Write info... */
541 LOG(2, "Read 3-D variable: %s"
542 " (CMS, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
543 varname, (double) np / cr, 32. * cr / (double) np, t_eval,
544 COMPRESS_SPEED(nx * ny * np * sizeof(float), t_eval));
545 }
546
547 /* Compress array and output compressed stream... */
548 else {
549
550 /* Init... */
551 cms_module_t *cms_ptr[EP];
552 cms_sol_t *cms_sol[EP];
553 double ratio[EP], t_coars_level[EP], t_eval_level[EP];
554
555 /* Loop over batches... */
556 const size_t dip = (ctl->met_cms_batch <= 0
557 ? (size_t) omp_get_max_threads()
558 : (size_t) ctl->met_cms_batch);
559 for (size_t ip0 = 0; ip0 < np; ip0 += dip) {
560
561 /* Measure time... */
562 double t0 = omp_get_wtime();
563
564 /* Loop over levels... */
565#pragma omp parallel for default(shared)
566 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
567 const double t1 = omp_get_wtime();
568
569 /* Allocate... */
570 float *tmp_arr;
571 ALLOC(tmp_arr, float,
572 nxy);
573
574 /* Copy level data... */
575 for (size_t ix = 0; ix < nx; ++ix)
576 for (size_t iy = 0; iy < ny; ++iy)
577 tmp_arr[ARRAY_2D(ix, iy, ny)] =
578 array[ARRAY_3D(ix, iy, ny, ip, np)];
579
580 /* Initialize current level... */
581 cms_ptr[ip] = cms_init(cms_param);
582
583 /* Coarsening... */
584 cms_sol[ip] =
585 cms_read_arr_new(cms_ptr[ip], tmp_arr, lon, lat,
586 nx, ny, ctl->met_cms_eps[metvar]);
587 t_coars_level[ip] = omp_get_wtime() - t1;
588
589 /* Free... */
590 free(tmp_arr);
591 }
592
593 /* Measure time... */
594 t_coars += (omp_get_wtime() - t0);
595
596 /* Loop over levels... */
597 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
598
599 /* Allocate... */
600 float *tmp_cms, *tmp_org;
601 ALLOC(tmp_cms, float,
602 nxy);
603 ALLOC(tmp_org, float,
604 nxy);
605
606 /* Measure time... */
607 t0 = omp_get_wtime();
608
609 /* Evaluate... */
610#pragma omp parallel for collapse(2) default(shared)
611 for (size_t ix = 0; ix < nx; ix++)
612 for (size_t iy = 0; iy < ny; iy++) {
613 const size_t idx = ARRAY_2D(ix, iy, ny);
614 const double x[] = { lon[ix], lat[iy] };
615 double val;
616 cms_eval(cms_ptr[ip], cms_sol[ip], x, &val);
617 tmp_cms[idx] = (float) val;
618 tmp_org[idx] = array[ARRAY_3D(ix, iy, ny, ip, np)];
619 }
620
621 /* Measure time... */
622 t_eval_level[ip] = omp_get_wtime() - t0;
623 t_eval += t_eval_level[ip];
624
625 /* Calculate harmonic mean of compression rates... */
626 ratio[ip] = cms_compression_rate(cms_ptr[ip], cms_sol[ip]);
627 cr += 1.0 / ratio[ip];
628
629 /* Write per-level diagnostics... */
630 if (level_log)
631 compress_log_level(level_log, "CMS", varname, ip, met->p[ip],
632 ratio[ip], 32. / ratio[ip],
633 t_coars_level[ip], t_eval_level[ip], nxy,
634 nxy * sizeof(float), tmp_org, tmp_cms);
635
636 /* Save binary data... */
637 if (ctl->met_cms_zstd == 1)
638 cms_save_zstd_sol(cms_sol[ip], inout, 3);
639 else
640 cms_save_sol(cms_sol[ip], inout);
641
642 /* Free... */
643 cms_delete_sol(cms_sol[ip]);
644 cms_delete_module(cms_ptr[ip]);
645 free(tmp_cms);
646 free(tmp_org);
647 }
648 }
649
650 /* Write info... */
651 LOG(2, "Write 3-D variable: %s"
652 " (CMS, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
653 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
654 varname, (double) np / cr, 32. * cr / (double) np, t_coars,
655 COMPRESS_SPEED(nx * ny * np * sizeof(float), t_coars), t_eval,
656 COMPRESS_SPEED(nx * ny * np * sizeof(float), t_eval));
657 }
658
659 /* Free... */
660 cms_delete_param(cms_param);
661}
662#endif
663
664/*****************************************************************************/
665
667 FILE *out,
668 const char *codec,
669 const char *varname,
670 const size_t lev,
671 const double plev,
672 const double ratio,
673 const double bpv,
674 const double t_comp,
675 const double t_decomp,
676 const size_t n,
677 const size_t nbytes,
678 const float *org,
679 const float *cmp) {
680
681 static FILE *last_out = NULL;
682 static char last_var[LEN] = "";
683
684 /* Calculate error statistics... */
685 double mean_err = 0.0, stddev_err = 0.0;
686 double nrmse = NAN, mean_orig = 0.0, orig_range = 0.0, rho = NAN;
687
688 double sum_err = 0.0, sumsq_err = 0.0;
689 double sum_orig = 0.0, sum_cmp = 0.0;
690 double sumsq_orig = 0.0, sumsq_cmp = 0.0, sum_org_cmp = 0.0;
691
692 double min_orig = 0.0, max_orig = 0.0;
693 double min_err = 0.0, max_err = 0.0;
694
695 /* Accumulate error, signal and cross-product sums in one pass... */
696 for (size_t i = 0; i < n; i++) {
697 const double o = (double) org[i];
698 const double c = (double) cmp[i];
699 const double e = c - o;
700
701 sum_err += e;
702 sumsq_err += e * e;
703 sum_orig += o;
704 sum_cmp += c;
705
706 sumsq_orig += o * o;
707 sumsq_cmp += c * c;
708 sum_org_cmp += o * c;
709
710 if (e < min_err || i == 0)
711 min_err = e;
712 if (e > max_err || i == 0)
713 max_err = e;
714
715 if (o < min_orig || i == 0)
716 min_orig = o;
717 if (o > max_orig || i == 0)
718 max_orig = o;
719 }
720
721 /* Derive the basic error and signal summary statistics... */
722 mean_err = sum_err / (double) n;
723 mean_orig = sum_orig / (double) n;
724 orig_range = max_orig - min_orig;
725
726 /* Convert the accumulated error sums into a standard deviation... */
727 const double var_err =
728 (sumsq_err - (sum_err * sum_err) / (double) n) / (double) n;
729 stddev_err = sqrt(var_err > 0.0 ? var_err : 0.0);
730
731 /* Normalize RMSE by the original data range if available... */
732 nrmse = (orig_range > 0.0)
733 ? sqrt(sumsq_err / (double) n) / orig_range : NAN;
734
735 /* Compute the Pearson correlation from the accumulated moments... */
736 const double nn = (double) n;
737 const double cov = sum_org_cmp - sum_orig * sum_cmp / nn;
738 const double var_orig = sumsq_orig - sum_orig * sum_orig / nn;
739 const double var_cmp = sumsq_cmp - sum_cmp * sum_cmp / nn;
740 const double denom = sqrt(var_orig * var_cmp);
741 rho = denom > 0.0 ? cov / denom : NAN;
742
743 /* Reset the variable separator state when the target file changes... */
744 if (out != last_out) {
745 last_out = out;
746 last_var[0] = '\0';
747 }
748
749 /* Separate diagnostic blocks when switching to a new variable... */
750 if (last_var[0] != '\0' && strcmp(last_var, varname) != 0)
751 fprintf(out, "\n");
752 snprintf(last_var, LEN, "%s", varname);
753
754 /* Logging... */
755 fprintf(out,
756 "%s %s %lu %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n",
757 codec, varname, (unsigned long) lev, plev, ratio, bpv, rho,
758 mean_err, stddev_err, min_err, max_err, mean_orig, orig_range,
759 nrmse, t_comp, COMPRESS_SPEED(nbytes, t_comp), t_decomp,
760 COMPRESS_SPEED(nbytes, t_decomp));
761}
762
763/*****************************************************************************/
764
766 FILE *out,
767 const char *codec,
768 const char *varname,
769 const met_t *met,
770 const float *org_all,
771 const float *cmp_all,
772 const size_t nxy,
773 const size_t nz,
774 const double ratio,
775 const double bpv,
776 const double t_comp,
777 const double t_decomp,
778 const size_t nbytes) {
779
780 if (!out)
781 return;
782
783 /* Allocate temporary buffers for one level... */
784 float *tmp_org, *tmp_cmp;
785 ALLOC(tmp_org, float,
786 nxy);
787 ALLOC(tmp_cmp, float,
788 nxy);
789
790 for (size_t lev = 0; lev < nz; lev++) {
791
792 /* Extract current level... */
793#pragma omp parallel for default(shared)
794 for (size_t ixy = 0; ixy < nxy; ixy++) {
795 tmp_org[ixy] = org_all[ixy * nz + lev];
796 tmp_cmp[ixy] = cmp_all[ixy * nz + lev];
797 }
798
799 /* Write diagnostics for the extracted level... */
800 compress_log_level(out, codec, varname, lev, met->p[lev], ratio, bpv,
801 t_comp, t_decomp, nxy, nbytes, tmp_org, tmp_cmp);
802 }
803
804 /* Free... */
805 free(tmp_org);
806 free(tmp_cmp);
807}
808
809/*****************************************************************************/
810
812 float *array,
813 const size_t nxy,
814 const size_t nz,
815 double *off,
816 double *scl) {
817
818 /* Initialize per-level minima and maxima from the first sample... */
819 for (size_t iz = 0; iz < nz; iz++) {
820 off[iz] = array[iz];
821 scl[iz] = array[iz];
822 }
823
824 /* Scan the remaining samples to get per-level minima and maxima... */
825 for (size_t ixy = 1; ixy < nxy; ixy++)
826 for (size_t iz = 0; iz < nz; iz++) {
827 const double value = array[ixy * nz + iz];
828 if (value < off[iz])
829 off[iz] = value;
830 if (value > scl[iz])
831 scl[iz] = value;
832 }
833
834 /* Convert maxima into ranges and suppress numerically flat levels... */
835 for (size_t iz = 0; iz < nz; iz++) {
836 const double range = scl[iz] - off[iz];
837 const double ref = fmax(1.0, fmax(fabs(off[iz]), fabs(scl[iz])));
838 scl[iz] = !(range > 1e-12 * ref) ? 0.0 : range;
839 }
840
841 /* Scale each level independently to the unit interval... */
842#pragma omp parallel for default(shared)
843 for (size_t ixy = 0; ixy < nxy; ixy++)
844 for (size_t iz = 0; iz < nz; iz++)
845 if (scl[iz] > 0.0)
846 array[ixy * nz + iz] =
847 (float) ((array[ixy * nz + iz] - off[iz]) / scl[iz]);
848 else
849 array[ixy * nz + iz] = 0.0f;
850}
851
852/*****************************************************************************/
853
855 float *array,
856 const size_t nxy,
857 const size_t nz,
858 const double *off,
859 const double *scl) {
860
861 /* Restore each level from unit space back to its original range... */
862#pragma omp parallel for default(shared)
863 for (size_t ixy = 0; ixy < nxy; ixy++)
864 for (size_t iz = 0; iz < nz; iz++)
865 if (scl[iz] > 0.0)
866 array[ixy * nz + iz] =
867 (float) (array[ixy * nz + iz] * scl[iz] + off[iz]);
868 else
869 array[ixy * nz + iz] = (float) off[iz];
870}
871
872/*****************************************************************************/
873
875 FILE *in,
876 const size_t nz,
877 double **off,
878 double **scl) {
879
880 int enabled;
881 *off = NULL;
882 *scl = NULL;
883
884 /* Read input... */
885 FREAD(&enabled, int,
886 1,
887 in);
888 if (enabled < 0 || enabled > 1)
889 ERRMSG("Invalid stored MET_LOSSY_SCALE flag!");
890
891 if (enabled > 0) {
892 ALLOC(*off, double,
893 nz);
894 ALLOC(*scl, double,
895 nz);
896 FREAD(*off, double,
897 nz,
898 in);
899 FREAD(*scl, double,
900 nz,
901 in);
902 }
903
904 return enabled;
905}
906
907/*****************************************************************************/
908
910 FILE *out,
911 const int enabled,
912 float *array,
913 const size_t nxy,
914 const size_t nz,
915 double **off,
916 double **scl) {
917
918 *off = NULL;
919 *scl = NULL;
920
921 /* Write output... */
922 FWRITE(&enabled, int,
923 1,
924 out);
925 if (enabled <= 0)
926 return;
927
928 /* Derive per-level scaling data... */
929 ALLOC(*off, double,
930 nz);
931 ALLOC(*scl, double,
932 nz);
933
934 compress_scale_to_unit(array, nxy, nz, *off, *scl);
935
936 FWRITE(*off, double,
937 nz,
938 out);
939 FWRITE(*scl, double,
940 nz,
941 out);
942}
943
944/*****************************************************************************/
945
946#ifdef ZSTD
947ZSTD_CCtx *compress_zstd_create_cctx(
948 const int level,
949 const int nworkers) {
950
951 /* Create and configure the ZSTD context... */
952 ZSTD_CCtx *cctx = ZSTD_createCCtx();
953 if (!cctx)
954 ERRMSG("Cannot create ZSTD context!");
955
956 if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel,
957 level)))
958 ERRMSG("Cannot set ZSTD compression level!");
959
960 if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, nworkers)))
961 ERRMSG("Cannot set ZSTD worker count!");
962
963 return cctx;
964}
965#endif
966
967/*****************************************************************************/
968
970 const char *varname) {
971
972 static const char *const names[] = {
973 "Z", "T", "U", "V", "W", "PV", "H2O", "O3",
974 "LWC", "RWC", "IWC", "SWC", "CC"
975 };
976
977 for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); i++)
978 if (strcasecmp(varname, names[i]) == 0)
979 return (int) i;
980
981 ERRMSG("Unknown meteorological variable name!");
982}
983
984/*****************************************************************************/
985
987 const ctl_t *ctl,
988 const met_t *met,
989 const char *varname,
990 float *array,
991 const int decompress,
992 FILE *level_log,
993 FILE *inout) {
994
995 const size_t nxy = (size_t) met->nx * (size_t) met->ny;
996 const size_t nz = (size_t) met->np;
997 const size_t n = nxy * nz;
998 const size_t nbytes = n * sizeof(float);
999 const size_t pck_bytes = n * sizeof(uint16_t);
1000
1001 double vmin[EP], vmax[EP], off[EP], scl[EP];
1002 uint16_t *sarray;
1003
1004 /* PCK+ZSTD payload = scale + offset + packed 16-bit samples... */
1005 const size_t payload_len = 2 * nz * sizeof(double) + pck_bytes;
1006 size_t stored_len = payload_len;
1007 const char *codec_info = ctl->met_pck_zstd ? "PCK+ZSTD" : "PCK";
1008
1009 /* Allocate packed sample buffer... */
1010 ALLOC(sarray, uint16_t, n);
1011
1012 /* Read compressed stream and decompress array... */
1013 if (decompress) {
1014 double t_zstd = 0.0;
1015
1016 /* Read packed data... */
1017 if (ctl->met_pck_zstd) {
1018#ifdef ZSTD
1019 uint64_t magic, pck_zstd_magic = UINT64_C(0x50434b5a53544431);
1020 unsigned char *compr = NULL, *payload = NULL;
1021
1022 /* Read input... */
1023 FREAD(&magic, uint64_t, 1, inout);
1024 if (magic != pck_zstd_magic)
1025 ERRMSG("PCK+ZSTD magic mismatch! Check MET_PCK_ZSTD and file type.");
1026
1027 /* Read and decompress the outer ZSTD payload... */
1028 FREAD(&stored_len, size_t,
1029 1,
1030 inout);
1031 ALLOC(compr, unsigned char,
1032 stored_len);
1033 FREAD(compr, unsigned char,
1034 stored_len,
1035 inout);
1036 ALLOC(payload, unsigned char,
1037 payload_len);
1038 const double t0_decomp = omp_get_wtime();
1039 const size_t out_len =
1040 ZSTD_decompress(payload, payload_len, compr, stored_len);
1041 t_zstd = omp_get_wtime() - t0_decomp;
1042 if (ZSTD_isError(out_len) || out_len != payload_len)
1043 ERRMSG("PCK ZSTD decompression failed or size mismatch!");
1044
1045 /* Split payload into scale, offset and packed samples... */
1046 memcpy(scl, payload, nz * sizeof(double));
1047 memcpy(off, payload + nz * sizeof(double), nz * sizeof(double));
1048 memcpy(sarray, payload + 2 * nz * sizeof(double), pck_bytes);
1049
1050 /* Free... */
1051 free(payload);
1052 free(compr);
1053#else
1054 ERRMSG("MPTRAC was compiled without ZSTD compression!");
1055#endif
1056 } else {
1057 /* Read input... */
1058 FREAD(&scl, double,
1059 nz,
1060 inout);
1061 FREAD(&off, double,
1062 nz,
1063 inout);
1064 FREAD(sarray, uint16_t, n, inout);
1065 }
1066
1067 /* Measure the scalar unpacking step separately from optional ZSTD... */
1068 const double t0 = omp_get_wtime();
1069
1070 /* Convert packed 16-bit samples back to floating-point values... */
1071#pragma omp parallel for default(shared)
1072 for (size_t ixy = 0; ixy < nxy; ixy++)
1073 for (size_t iz = 0; iz < nz; iz++)
1074 array[ixy * nz + iz]
1075 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
1076
1077 /* Add optional ZSTD time to the scalar unpacking time... */
1078 const double t_decomp = t_zstd + omp_get_wtime() - t0;
1079
1080 /* Logging... */
1081 LOG(2, "Read 3-D variable: %s"
1082 " (%s, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1083 varname, codec_info, COMPRESS_RATIO(nbytes, stored_len),
1084 COMPRESS_BPV(n, stored_len), t_decomp, COMPRESS_SPEED(nbytes,
1085 t_decomp));
1086 }
1087
1088 /* Compress array and output compressed stream... */
1089 else {
1090 float *tmp_org, *tmp_pck;
1091 double t_comp_sum = 0, t_decomp_sum = 0, t_zstd = 0, t_zstd_decomp = 0;
1092 double t_comp_level[EP], t_decomp_level[EP];
1093
1094 /* Allocate temporary buffers for one level... */
1095 ALLOC(tmp_org, float,
1096 nxy);
1097 ALLOC(tmp_pck, float,
1098 nxy);
1099
1100 /* Derive per-level minima and maxima for the 16-bit quantization... */
1101 for (size_t iz = 0; iz < nz; iz++) {
1102 vmin[iz] = array[iz];
1103 vmax[iz] = array[iz];
1104 }
1105 for (size_t ixy = 1; ixy < nxy; ixy++)
1106 for (size_t iz = 0; iz < nz; iz++) {
1107 if (array[ixy * nz + iz] < vmin[iz])
1108 vmin[iz] = array[ixy * nz + iz];
1109 if (array[ixy * nz + iz] > vmax[iz])
1110 vmax[iz] = array[ixy * nz + iz];
1111 }
1112
1113 /* Derive per-level offset and scaling factor... */
1114 for (size_t iz = 0; iz < nz; iz++) {
1115 scl[iz] = (vmax[iz] - vmin[iz]) / 65533.;
1116 off[iz] = vmin[iz];
1117 }
1118
1119 /* Quantize each level and time encode/decode diagnostics on the fly... */
1120 for (size_t iz = 0; iz < nz; iz++) {
1121 const double t0 = omp_get_wtime();
1122
1123#pragma omp parallel for default(shared)
1124 for (size_t ixy = 0; ixy < nxy; ixy++)
1125 if (scl[iz] != 0)
1126 sarray[ixy * nz + iz] =
1127 (uint16_t) ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
1128 else
1129 sarray[ixy * nz + iz] = 0;
1130
1131 t_comp_level[iz] = omp_get_wtime() - t0;
1132 t_comp_sum += t_comp_level[iz];
1133
1134 const double t1 = omp_get_wtime();
1135
1136#pragma omp parallel for default(shared)
1137 for (size_t ixy = 0; ixy < nxy; ixy++) {
1138 tmp_org[ixy] = array[ixy * nz + iz];
1139 tmp_pck[ixy] = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
1140 }
1141
1142 t_decomp_level[iz] = omp_get_wtime() - t1;
1143 t_decomp_sum += t_decomp_level[iz];
1144 }
1145
1146 /* Write packed data, optionally wrapped in ZSTD... */
1147 if (ctl->met_pck_zstd) {
1148#ifdef ZSTD
1149 uint64_t pck_zstd_magic = UINT64_C(0x50434b5a53544431);
1150 unsigned char *payload = NULL, *payload_chk = NULL;
1151 void *stored_data = NULL;
1152
1153 /* Pack plain PCK data into one ZSTD payload... */
1154 ALLOC(payload, unsigned char,
1155 payload_len);
1156 memcpy(payload, scl, nz * sizeof(double));
1157 memcpy(payload + nz * sizeof(double), off, nz * sizeof(double));
1158 memcpy(payload + 2 * nz * sizeof(double), sarray, pck_bytes);
1159 const size_t dst_cap = ZSTD_compressBound(payload_len);
1160 ALLOC(stored_data, char,
1161 dst_cap);
1162 ZSTD_CCtx *cctx = compress_zstd_create_cctx(ctl->met_zstd_level,
1163 ctl->met_zstd_nworkers);
1164 const double t0_comp = omp_get_wtime();
1165 stored_len =
1166 ZSTD_compress2(cctx, stored_data, dst_cap, payload, payload_len);
1167 t_zstd = omp_get_wtime() - t0_comp;
1168 ZSTD_freeCCtx(cctx);
1169 if (ZSTD_isError(stored_len))
1170 ERRMSG("PCK ZSTD compression failed!");
1171
1172 /* Decompress once for validation and timing... */
1173 ALLOC(payload_chk, unsigned char,
1174 payload_len);
1175 const double t0_decomp2 = omp_get_wtime();
1176 const size_t out_len2 =
1177 ZSTD_decompress(payload_chk, payload_len, stored_data, stored_len);
1178 t_zstd_decomp = omp_get_wtime() - t0_decomp2;
1179 if (ZSTD_isError(out_len2) || out_len2 != payload_len)
1180 ERRMSG("PCK ZSTD decompression failed or size mismatch!");
1181
1182 /* Free... */
1183 free(payload_chk);
1184 free(payload);
1185
1186 /* Write output... */
1187 FWRITE(&pck_zstd_magic, uint64_t, 1, inout);
1188 FWRITE(&stored_len, size_t,
1189 1,
1190 inout);
1191 FWRITE(stored_data, unsigned char,
1192 stored_len,
1193 inout);
1194
1195 /* Free... */
1196 free(stored_data);
1197#else
1198 ERRMSG("MPTRAC was compiled without ZSTD compression!");
1199#endif
1200 } else {
1201
1202 /* Write output... */
1203 FWRITE(&scl, double,
1204 nz,
1205 inout);
1206 FWRITE(&off, double,
1207 nz,
1208 inout);
1209 FWRITE(sarray, uint16_t, n, inout);
1210 }
1211
1212 /* Combine PCK and optional ZSTD timing and size metrics... */
1213 const double ratio_out = COMPRESS_RATIO(nbytes, stored_len);
1214 const double bpv_out = COMPRESS_BPV(n, stored_len);
1215 const double t_comp = t_comp_sum + t_zstd;
1216 const double t_decomp = t_decomp_sum + t_zstd_decomp;
1217
1218 /* Logging... */
1219 LOG(2, "Write 3-D variable: %s"
1220 " (%s, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
1221 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1222 varname, codec_info, ratio_out, bpv_out, t_comp,
1223 COMPRESS_SPEED(nbytes, t_comp), t_decomp,
1224 COMPRESS_SPEED(nbytes, t_decomp));
1225
1226 /* Distribute optional ZSTD cost across levels for diagnostics... */
1227 if (level_log) {
1228 const double t_zstd_level = t_zstd / (double) nz;
1229 const double t_zstd_decomp_level = t_zstd_decomp / (double) nz;
1230 const char *codec = ctl->met_pck_zstd ? "PCKZSTD" : "PCK";
1231 for (size_t iz = 0; iz < nz; iz++) {
1232#pragma omp parallel for default(shared)
1233
1234 /* Rebuild one decoded level for diagnostics... */
1235 for (size_t ixy = 0; ixy < nxy; ixy++) {
1236 tmp_org[ixy] = array[ixy * nz + iz];
1237 tmp_pck[ixy] = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
1238 }
1239
1240 /* Logging... */
1241 compress_log_level(level_log, codec, varname, iz, met->p[iz],
1242 ratio_out, bpv_out,
1243 t_comp_level[iz] + t_zstd_level,
1244 t_decomp_level[iz] + t_zstd_decomp_level,
1245 nxy, nxy * sizeof(float), tmp_org, tmp_pck);
1246 }
1247 }
1248
1249 /* Free... */
1250 free(tmp_org);
1251 free(tmp_pck);
1252 }
1253
1254 /* Free... */
1255 free(sarray);
1256}
1257
1258/*****************************************************************************/
1259
1260#ifdef SZ3
1261void compress_sz3(
1262 const ctl_t *ctl,
1263 const met_t *met,
1264 const char *varname,
1265 float *array,
1266 const int decompress,
1267 FILE *level_log,
1268 FILE *inout) {
1269
1270 /* Get meteo variable... */
1271 const int metvar = compress_metvar_index(varname);
1272
1273 /* Check compression settings... */
1274 if ((ctl->met_sz3_prec[metvar] > 0) == (ctl->met_sz3_tol[metvar] > 0.0))
1275 ERRMSG("Exactly one of precision or tolerance must be set for SZ3!");
1276
1277 size_t r1 = (size_t) met->np, r2 = (size_t) met->ny, r3 = (size_t) met->nx,
1278 outSize = 0, total_elems = r1 * r2 * r3;
1279
1280 unsigned char *bytes = NULL;
1281 double *scale_off = NULL, *scale_scl = NULL;
1282 float *orig_all = NULL;
1283 char codec_info[LEN];
1284
1285 /* Read compressed stream and decompress array... */
1286 if (decompress) {
1287
1288 /* Read optional scaling metadata before the SZ3 byte stream... */
1289 const int stored_lossy_scale =
1290 compress_read_lossy_scale(inout, r1, &scale_off, &scale_scl);
1291
1292 size_t sz3size;
1293
1294 /* Read input... */
1295 FREAD(&sz3size, size_t,
1296 1,
1297 inout);
1298 ALLOC(bytes, char,
1299 sz3size);
1300 FREAD(bytes, unsigned char,
1301 sz3size,
1302 inout);
1303
1304 /* Let SZ3 rebuild the scaled field in its native 3-D layout... */
1305 const double t0 = omp_get_wtime();
1306 void *outData = SZ_decompress(SZ_FLOAT, bytes, sz3size, 0, 0, r3, r2, r1);
1307 if (!outData)
1308 ERRMSG("Decompression failed!");
1309
1310 memcpy(array, outData, total_elems * sizeof(float));
1311
1312 /* Restore the original value range after lossy unit scaling... */
1313 if (stored_lossy_scale > 0)
1314 compress_unscale_from_unit(array, r2 * r3, r1, scale_off, scale_scl);
1315 const double t_decomp = omp_get_wtime() - t0;
1316
1317 /* Free... */
1318 free(outData);
1319 free(bytes);
1320
1321 const double ratio = COMPRESS_RATIO(total_elems * sizeof(float), sz3size);
1322 const double bpv = COMPRESS_BPV(total_elems, sz3size);
1323 snprintf(codec_info, LEN, "SZ3, PREC=%d, TOL=%g, SCALE=%d",
1324 ctl->met_sz3_prec[metvar], ctl->met_sz3_tol[metvar],
1325 stored_lossy_scale);
1326
1327 /* Logging... */
1328 LOG(2, "Read 3-D variable: %s"
1329 " (%s, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1330 varname, codec_info, ratio, bpv, t_decomp,
1331 COMPRESS_SPEED(total_elems * sizeof(float), t_decomp));
1332 }
1333
1334 /* Compress array and output compressed stream... */
1335 else {
1336
1337 /* Translate MPTRAC settings into the SZ3 absolute/relative error mode... */
1338 const int errBoundMode = (ctl->met_sz3_prec[metvar] > 0) ? REL : ABS;
1339 const double absBound =
1340 (errBoundMode == ABS) ? ctl->met_sz3_tol[metvar] : 0.0;
1341 const double relBound =
1342 (errBoundMode == REL) ? pow(2.0, -(double) ctl->met_sz3_prec[metvar])
1343 : 0.0;
1344 const size_t raw_size = total_elems * sizeof(float);
1345
1346 /* Preserve the unscaled input only if diagnostics need it later... */
1347 if (ctl->met_lossy_scale[metvar] > 0 && level_log) {
1348 ALLOC(orig_all, float,
1349 total_elems);
1350 memcpy(orig_all, array, total_elems * sizeof(float));
1351 }
1352
1353 /* Optionally scale each vertical level to unit space before SZ3... */
1354 compress_write_lossy_scale(inout, ctl->met_lossy_scale[metvar], array,
1355 r2 * r3, r1, &scale_off, &scale_scl);
1356
1357 /* Compress the possibly scaled field with the selected SZ3 error mode... */
1358 const double t0 = omp_get_wtime();
1359 bytes = SZ_compress_args(SZ_FLOAT, array, &outSize,
1360 errBoundMode, absBound, relBound, 0.0,
1361 0, 0, r3, r2, r1);
1362 const double t_comp = omp_get_wtime() - t0;
1363 if (!bytes || outSize == 0)
1364 ERRMSG("Compression failed!");
1365
1366 /* Write output... */
1367 FWRITE(&outSize, size_t,
1368 1,
1369 inout);
1370 FWRITE(bytes, unsigned char,
1371 outSize,
1372 inout);
1373
1374 snprintf(codec_info, LEN, "SZ3, PREC=%d, TOL=%g, SCALE=%d",
1375 ctl->met_sz3_prec[metvar], ctl->met_sz3_tol[metvar],
1376 ctl->met_lossy_scale[metvar]);
1377
1378 /* Reconstruct once more only when per-level diagnostics are requested... */
1379 double t_decomp = NAN;
1380 if (level_log) {
1381 unsigned char *bytes_copy;
1382 float *tmp_all;
1383 const size_t nxy = r2 * r3;
1384
1385 /* Reconstruct data for per-level diagnostics... */
1386 ALLOC(bytes_copy, unsigned char,
1387 outSize);
1388 memcpy(bytes_copy, bytes, outSize);
1389
1390 const double t1 = omp_get_wtime();
1391 void *decData = SZ_decompress(SZ_FLOAT, bytes_copy, outSize, 0, 0, r3,
1392 r2, r1);
1393 t_decomp = omp_get_wtime() - t1;
1394 if (!decData)
1395 ERRMSG("Decompression failed!");
1396
1397 /* Rebuild the decoded field so diagnostics compare like with like... */
1398 ALLOC(tmp_all, float,
1399 total_elems);
1400 memcpy(tmp_all, decData, total_elems * sizeof(float));
1401 if (ctl->met_lossy_scale[metvar] > 0)
1402 compress_unscale_from_unit(tmp_all, r2 * r3, r1, scale_off,
1403 scale_scl);
1404
1405 const double ratio = COMPRESS_RATIO(raw_size, outSize);
1406 const double bpv = COMPRESS_BPV(total_elems, outSize);
1407 compress_log_levels_3d(level_log, "SZ3", varname, met,
1408 (orig_all ? orig_all : array), tmp_all, nxy, r1,
1409 ratio, bpv, t_comp, t_decomp, raw_size);
1410
1411 /* Free... */
1412 free(tmp_all);
1413 free(decData);
1414 free(bytes_copy);
1415
1416 /* Logging... */
1417 LOG(2, "Write 3-D variable: %s"
1418 " (%s, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
1419 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1420 varname, codec_info, ratio, bpv, t_comp,
1421 COMPRESS_SPEED(raw_size, t_comp), t_decomp,
1422 COMPRESS_SPEED(raw_size, t_decomp));
1423 } else {
1424 const double ratio = COMPRESS_RATIO(raw_size, outSize);
1425 const double bpv = COMPRESS_BPV(total_elems, outSize);
1426
1427 /* Logging... */
1428 LOG(2, "Write 3-D variable: %s"
1429 " (%s, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s)",
1430 varname, codec_info, ratio, bpv, t_comp,
1431 COMPRESS_SPEED(raw_size, t_comp));
1432 }
1433 /* Free... */
1434 free(bytes);
1435 free(orig_all);
1436 }
1437
1438 /* Free... */
1439 free(scale_off);
1440 free(scale_scl);
1441}
1442#endif
1443
1444/*****************************************************************************/
1445
1446#ifdef ZFP
1447void compress_zfp(
1448 const ctl_t *ctl,
1449 const met_t *met,
1450 const char *varname,
1451 float *array,
1452 const int decompress,
1453 FILE *level_log,
1454 FILE *inout) {
1455
1456 /* Get meteo variable... */
1457 const int metvar = compress_metvar_index(varname);
1458
1459 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
1460 const size_t snx = (size_t) met->np;
1461 const size_t sny = (size_t) met->ny;
1462 const size_t snz = (size_t) met->nx;
1463 const size_t n = snx * sny * snz;
1464 const size_t raw_size = n * sizeof(float);
1465 const zfp_type type = zfp_type_float;
1466 zfp_field *field = zfp_field_3d(array, type, snx, sny, snz);
1467
1468 /* Allocate meta data for a compressed stream... */
1469 zfp_stream *zfp = zfp_stream_open(NULL);
1470 if (!field || !zfp)
1471 ERRMSG("Failed to allocate zfp structures!");
1472
1473 /* Set compression mode... */
1474 int actual_prec = 0;
1475 double actual_tol = 0;
1476 if ((ctl->met_zfp_prec[metvar] > 0 && ctl->met_zfp_tol[metvar] > 0)
1477 || (ctl->met_zfp_prec[metvar] <= 0 && ctl->met_zfp_tol[metvar] <= 0)) {
1478 ERRMSG("Exactly one of precision or tolerance must be set for zfp!");
1479 } else if (ctl->met_zfp_prec[metvar] > 0)
1480 actual_prec = (int) zfp_stream_set_precision(zfp, (unsigned int)
1481 ctl->met_zfp_prec[metvar]);
1482 else if (ctl->met_zfp_tol[metvar] > 0)
1483 actual_tol = zfp_stream_set_accuracy(zfp, ctl->met_zfp_tol[metvar]);
1484
1485 /* Allocate buffer for compressed data... */
1486 const size_t bufsize = zfp_stream_maximum_size(zfp, field);
1487 void *buffer;
1488 ALLOC(buffer, char,
1489 bufsize);
1490
1491 /* Associate bit stream with allocated buffer... */
1492 bitstream *stream = stream_open(buffer, bufsize);
1493 zfp_stream_set_bit_stream(zfp, stream);
1494 zfp_stream_rewind(zfp);
1495
1496 /* Read compressed stream and decompress array... */
1497 size_t zfpsize;
1498 double *scale_off = NULL, *scale_scl = NULL;
1499 char codec_info[LEN];
1500 if (decompress) {
1501
1502 /* Read optional scaling metadata before the ZFP bit stream... */
1503 const int stored_lossy_scale =
1504 compress_read_lossy_scale(inout, snx, &scale_off, &scale_scl);
1505 /* Read input... */
1506 FREAD(&zfpsize, size_t,
1507 1,
1508 inout);
1509 if (zfpsize > bufsize)
1510 ERRMSG("Compressed data size exceeds allocated buffer!");
1511 FREAD(buffer, unsigned char,
1512 zfpsize,
1513 inout);
1514
1515 /* Decode the bit stream directly into the caller-provided field... */
1516 const double t0 = omp_get_wtime();
1517 if (!zfp_decompress(zfp, field))
1518 ERRMSG("Decompression failed!");
1519
1520 /* Restore the original value range after lossy unit scaling... */
1521 if (stored_lossy_scale > 0)
1522 compress_unscale_from_unit(array, sny * snz, snx, scale_off, scale_scl);
1523 const double t_decomp = omp_get_wtime() - t0;
1524 const double ratio = COMPRESS_RATIO(raw_size, zfpsize);
1525 const double bpv = COMPRESS_BPV(n, zfpsize);
1526 snprintf(codec_info, LEN, "ZFP, PREC=%d, TOL=%g, SCALE=%d",
1527 actual_prec, actual_tol, stored_lossy_scale);
1528
1529 /* Logging... */
1530 LOG(2, "Read 3-D variable: %s"
1531 " (%s, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1532 varname, codec_info, ratio, bpv, t_decomp, COMPRESS_SPEED(raw_size,
1533 t_decomp));
1534 }
1535
1536 /* Compress array and output compressed stream... */
1537 else {
1538 float *tmp_all, *orig_all = NULL;
1539 const size_t nxy = sny * snz;
1540
1541 /* Preserve the unscaled input only if diagnostics need it later... */
1542 if (ctl->met_lossy_scale[metvar] > 0 && level_log) {
1543 ALLOC(orig_all, float,
1544 n);
1545 memcpy(orig_all, array, raw_size);
1546 }
1547
1548 /* Optionally scale each vertical level to unit space before ZFP... */
1549 compress_write_lossy_scale(inout, ctl->met_lossy_scale[metvar], array,
1550 nxy, snx, &scale_off, &scale_scl);
1551
1552 /* Keep a temporary decode buffer for the shared diagnostics path... */
1553 ALLOC(tmp_all, float,
1554 n);
1555
1556 /* Compress the field into the configured ZFP bit stream... */
1557 const double t0 = omp_get_wtime();
1558 zfpsize = zfp_compress(zfp, field);
1559 const double t_comp = omp_get_wtime() - t0;
1560 if (!zfpsize) {
1561 ERRMSG("Compression failed!");
1562 } else {
1563 /* Write output... */
1564 FWRITE(&zfpsize, size_t,
1565 1,
1566 inout);
1567 FWRITE(buffer, unsigned char,
1568 zfpsize,
1569 inout);
1570 }
1571
1572 /* Decode once into a temporary field for the shared diagnostics... */
1573 zfp_field *dec_field = zfp_field_3d(tmp_all, type, snx, sny, snz);
1574 if (!dec_field)
1575 ERRMSG("Failed to allocate zfp structures!");
1576
1577 /* Rewind the bit stream and decode once for diagnostics and timing... */
1578 const double t1 = omp_get_wtime();
1579 zfp_stream_rewind(zfp);
1580 if (!zfp_decompress(zfp, dec_field))
1581 ERRMSG("Decompression failed!");
1582 if (ctl->met_lossy_scale[metvar] > 0)
1583 compress_unscale_from_unit(tmp_all, nxy, snx, scale_off, scale_scl);
1584 const double t_decomp = omp_get_wtime() - t1;
1585
1586 const double ratio = COMPRESS_RATIO(raw_size, zfpsize);
1587 const double bpv = COMPRESS_BPV(n, zfpsize);
1588 compress_log_levels_3d(level_log, "ZFP", varname, met,
1589 (orig_all ? orig_all : array), tmp_all, nxy, snx,
1590 ratio, bpv, t_comp, t_decomp, raw_size);
1591
1592 snprintf(codec_info, LEN, "ZFP, PREC=%d, TOL=%g, SCALE=%d",
1593 actual_prec, actual_tol, ctl->met_lossy_scale[metvar]);
1594
1595 /* Logging... */
1596 LOG(2, "Write 3-D variable: %s"
1597 " (%s, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
1598 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1599 varname, codec_info, ratio, bpv, t_comp, COMPRESS_SPEED(raw_size,
1600 t_comp),
1601 t_decomp, COMPRESS_SPEED(raw_size, t_decomp));
1602
1603 /* Free... */
1604 free(tmp_all);
1605 free(orig_all);
1606 zfp_field_free(dec_field);
1607 }
1608
1609 /* Free... */
1610 free(scale_off);
1611 free(scale_scl);
1612
1613 /* Free... */
1614 zfp_field_free(field);
1615 stream_close(stream);
1616 zfp_stream_close(zfp);
1617 free(buffer);
1618}
1619#endif
1620
1621/*****************************************************************************/
1622
1623#ifdef ZSTD
1624void compress_zstd(
1625 const ctl_t *ctl,
1626 const met_t *met,
1627 const char *varname,
1628 float *array,
1629 const int decompress,
1630 FILE *level_log,
1631 FILE *inout) {
1632
1633 /* Get buffer sizes... */
1634 const size_t nxy = (size_t) met->nx * (size_t) met->ny;
1635 const size_t nz = (size_t) met->np;
1636 const size_t n = nxy * nz, uncomprLen = n * sizeof(float);
1637 size_t compsize, comprLen = ZSTD_compressBound(uncomprLen);
1638
1639 /* Allocate... */
1640 char *compr, *uncompr = (char *) array;
1641 char codec_info[LEN];
1642 ALLOC(compr, char,
1643 comprLen);
1644
1645 /* Read compressed stream and decompress array... */
1646 if (decompress) {
1647
1648 /* Read input... */
1649 FREAD(&comprLen, size_t,
1650 1,
1651 inout);
1652 FREAD(compr, unsigned char,
1653 comprLen,
1654 inout);
1655
1656 /* Decode one full frame and validate the restored byte count... */
1657 const double t0 = omp_get_wtime();
1658 compsize = ZSTD_decompress(uncompr, uncomprLen, compr, comprLen);
1659 const double t_decomp = omp_get_wtime() - t0;
1660 if (ZSTD_isError(compsize) || compsize != uncomprLen)
1661 ERRMSG("Decompression failed or size mismatch!");
1662 const double ratio = COMPRESS_RATIO(uncomprLen, comprLen);
1663 const double bpv = COMPRESS_BPV(n, comprLen);
1664 snprintf(codec_info, LEN, "ZSTD, LEVEL=%d", ctl->met_zstd_level);
1665
1666 /* Logging... */
1667 LOG(2, "Read 3-D variable: %s"
1668 " (%s, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1669 varname, codec_info, ratio, bpv, t_decomp, COMPRESS_SPEED(uncomprLen,
1670 t_decomp));
1671 }
1672
1673 /* Compress array and output compressed stream... */
1674 else {
1675 ZSTD_CCtx *cctx;
1676 float *tmp_all;
1677
1678 /* Keep one temporary decode buffer for the shared diagnostics path... */
1679 ALLOC(tmp_all, float,
1680 n);
1681
1682 cctx = compress_zstd_create_cctx(ctl->met_zstd_level,
1683 ctl->met_zstd_nworkers);
1684
1685 /* Compress one full field with the preconfigured ZSTD context... */
1686 const double t0 = omp_get_wtime();
1687 compsize = ZSTD_compress2(cctx, compr, comprLen, uncompr, uncomprLen);
1688 const double t_comp = omp_get_wtime() - t0;
1689 if (ZSTD_isError(compsize)) {
1690 ZSTD_freeCCtx(cctx);
1691 ERRMSG("Compression failed!");
1692 } else {
1693
1694 /* Write output... */
1695 FWRITE(&compsize, size_t,
1696 1,
1697 inout);
1698 FWRITE(compr, unsigned char,
1699 compsize,
1700 inout);
1701 }
1702
1703 /* Decode once more so the common diagnostics see the reconstructed field... */
1704 const double t1 = omp_get_wtime();
1705 const size_t decomp_size = ZSTD_decompress(tmp_all, uncomprLen, compr,
1706 compsize);
1707 const double t_decomp = omp_get_wtime() - t1;
1708 if (ZSTD_isError(decomp_size) || decomp_size != uncomprLen)
1709 ERRMSG("Decompression failed or size mismatch!");
1710
1711 const double ratio = COMPRESS_RATIO(uncomprLen, compsize);
1712 const double bpv = COMPRESS_BPV(n, compsize);
1713 compress_log_levels_3d(level_log, "ZSTD", varname, met, array, tmp_all,
1714 nxy, nz, ratio, bpv, t_comp, t_decomp, uncomprLen);
1715
1716 snprintf(codec_info, LEN, "ZSTD, LEVEL=%d, NWORKERS=%d",
1718
1719 /* Logging... */
1720 LOG(2, "Write 3-D variable: %s"
1721 " (%s, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
1722 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1723 varname, codec_info, ratio, bpv, t_comp, COMPRESS_SPEED(uncomprLen,
1724 t_comp),
1725 t_decomp, COMPRESS_SPEED(uncomprLen, t_decomp));
1726
1727 /* Free... */
1728 ZSTD_freeCCtx(cctx);
1729 free(tmp_all);
1730 }
1731
1732 /* Free... */
1733 free(compr);
1734}
1735#endif
1736
1737/*****************************************************************************/
1738
1739#ifdef LZ4
1740void compress_lz4(
1741 const ctl_t *ctl,
1742 const met_t *met,
1743 const char *varname,
1744 float *array,
1745 const int decompress,
1746 FILE *level_log,
1747 FILE *inout) {
1748
1749 /* Get buffer sizes... */
1750 const size_t nxy = (size_t) met->nx * (size_t) met->ny;
1751 const size_t nz = (size_t) met->np;
1752 const size_t n = nxy * nz;
1753 const size_t uncomprLen = n * sizeof(float);
1754 if (uncomprLen > (size_t) INT_MAX)
1755 ERRMSG("LZ4 input buffer exceeds INT_MAX!");
1756 const int uncomprLenInt = (int) uncomprLen;
1757 const int accel = ctl->met_lz4_accel > 0 ? ctl->met_lz4_accel : 1;
1758 const int comprCapInt = LZ4_compressBound(uncomprLenInt);
1759 if (comprCapInt <= 0)
1760 ERRMSG("Cannot determine LZ4 compression bound!");
1761 size_t comprLen = (size_t) comprCapInt;
1762
1763 /* Allocate... */
1764 char *compr, *uncompr = (char *) array;
1765 char codec_info[LEN];
1766 ALLOC(compr, char,
1767 comprLen);
1768 snprintf(codec_info, LEN, "LZ4, ACCEL=%d", accel);
1769
1770 /* Read compressed stream and decompress array... */
1771 if (decompress) {
1772
1773 /* Read input... */
1774 FREAD(&comprLen, size_t,
1775 1,
1776 inout);
1777 if (comprLen > (size_t) INT_MAX)
1778 ERRMSG("LZ4 compressed buffer exceeds INT_MAX!");
1779 FREAD(compr, unsigned char,
1780 comprLen,
1781 inout);
1782
1783 /* Decode one full frame and validate the restored byte count... */
1784 const double t0 = omp_get_wtime();
1785 const int decomp_size =
1786 LZ4_decompress_safe(compr, uncompr, (int) comprLen, uncomprLenInt);
1787 const double t_decomp = omp_get_wtime() - t0;
1788 if (decomp_size != uncomprLenInt)
1789 ERRMSG("Decompression failed or size mismatch!");
1790 const double ratio = COMPRESS_RATIO(uncomprLen, comprLen);
1791 const double bpv = COMPRESS_BPV(n, comprLen);
1792
1793 /* Logging... */
1794 LOG(2, "Read 3-D variable: %s"
1795 " (%s, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1796 varname, codec_info, ratio, bpv, t_decomp, COMPRESS_SPEED(uncomprLen,
1797 t_decomp));
1798 }
1799
1800 /* Compress array and output compressed stream... */
1801 else {
1802 float *tmp_all;
1803
1804 /* Keep one temporary decode buffer for the shared diagnostics path... */
1805 ALLOC(tmp_all, float,
1806 n);
1807
1808 /* Compress one full field with the configured LZ4 acceleration... */
1809 const double t0 = omp_get_wtime();
1810 const int compsizeInt =
1811 LZ4_compress_fast(uncompr, compr, uncomprLenInt, comprCapInt, accel);
1812 const double t_comp = omp_get_wtime() - t0;
1813 if (compsizeInt <= 0)
1814 ERRMSG("Compression failed!");
1815 const size_t compsize = (size_t) compsizeInt;
1816
1817 /* Write output... */
1818 FWRITE(&compsize, size_t,
1819 1,
1820 inout);
1821 FWRITE(compr, unsigned char,
1822 compsize,
1823 inout);
1824
1825 /* Decode once more so the common diagnostics see the reconstructed field... */
1826 const double t1 = omp_get_wtime();
1827 const int decomp_size =
1828 LZ4_decompress_safe(compr, (char *) tmp_all, compsizeInt,
1829 uncomprLenInt);
1830 const double t_decomp = omp_get_wtime() - t1;
1831 if (decomp_size != uncomprLenInt)
1832 ERRMSG("Decompression failed or size mismatch!");
1833
1834 const double ratio = COMPRESS_RATIO(uncomprLen, compsize);
1835 const double bpv = COMPRESS_BPV(n, compsize);
1836 compress_log_levels_3d(level_log, "LZ4", varname, met, array, tmp_all,
1837 nxy, nz, ratio, bpv, t_comp, t_decomp, uncomprLen);
1838
1839 /* Logging... */
1840 LOG(2, "Write 3-D variable: %s"
1841 " (%s, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
1842 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1843 varname, codec_info, ratio, bpv, t_comp, COMPRESS_SPEED(uncomprLen,
1844 t_comp),
1845 t_decomp, COMPRESS_SPEED(uncomprLen, t_decomp));
1846
1847 free(tmp_all);
1848 }
1849
1850 /* Free... */
1851 free(compr);
1852}
1853#endif
1854
1855/*****************************************************************************/
1856
1857double cos_sza(
1858 const double sec,
1859 const double lon,
1860 const double lat) {
1861
1862 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
1863 const double D = sec / 86400 - 0.5;
1864
1865 /* Geocentric apparent ecliptic longitude [rad]... */
1866 const double g = DEG2RAD(357.529 + 0.98560028 * D);
1867 const double q = 280.459 + 0.98564736 * D;
1868 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
1869
1870 /* Mean obliquity of the ecliptic [rad]... */
1871 const double e = DEG2RAD(23.439 - 0.00000036 * D);
1872
1873 /* Declination [rad]... */
1874 const double sindec = sin(e) * sin(L);
1875
1876 /* Right ascension [rad]... */
1877 const double ra = atan2(cos(e) * sin(L), cos(L));
1878
1879 /* Greenwich Mean Sidereal Time [h]... */
1880 const double GMST = 18.697374558 + 24.06570982441908 * D;
1881
1882 /* Local Sidereal Time [h]... */
1883 const double LST = GMST + lon / 15;
1884
1885 /* Hour angle [rad]... */
1886 const double h = LST / 12 * M_PI - ra;
1887
1888 /* Convert latitude... */
1889 const double lat_help = DEG2RAD(lat);
1890
1891 /* Return cosine of solar zenith angle... */
1892 return sin(lat_help) * sindec + cos(lat_help) * sqrt(1 -
1893 SQR(sindec)) * cos(h);
1894}
1895
1896/*****************************************************************************/
1897
1899 const int year,
1900 const int mon,
1901 const int day,
1902 int *doy) {
1903
1904 const int
1905 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1906 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1907
1908 /* Get day of year... */
1909 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
1910 *doy = d0l[mon - 1] + day - 1;
1911 else
1912 *doy = d0[mon - 1] + day - 1;
1913}
1914
1915/*****************************************************************************/
1916
1917#ifdef DD
1919 const ctl_t *ctl,
1920 const dd_t *dd,
1921 atm_t *atm,
1922 const int init) {
1923
1924 /* Set timer... */
1925 SELECT_TIMER("DD_ASSIGN_SUBDOMAINS", "DD");
1926
1927 /* Get MPI rank... */
1928 int rank;
1929 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
1930
1931 /* Determine owned core subdomain in index space... */
1932 const int zonal_rank = rank / ctl->dd_subdomains_meridional;
1933 const int merid_rank = rank % ctl->dd_subdomains_meridional;
1934
1935 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
1936 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
1937
1938 const int ix0 = zonal_rank * nx_block;
1939 const int iy0 = merid_rank * ny_block;
1940
1941 const int ix1 = ix0 + nx_block
1942 + (zonal_rank == ctl->dd_subdomains_zonal - 1 ?
1943 dd->nx_glob - ctl->dd_subdomains_zonal * nx_block : 0);
1944
1945 const int iy1 = iy0 + ny_block
1946 + (merid_rank == ctl->dd_subdomains_meridional - 1 ?
1947 dd->ny_glob - ctl->dd_subdomains_meridional * ny_block : 0);
1948
1949 /* Loop over particles... */
1950#ifdef _OPENACC
1951#pragma acc update device(dd->nx_glob, dd->ny_glob, \
1952 dd->lon_glob[:dd->nx_glob], \
1953 dd->lat_glob[:dd->ny_glob])
1954#pragma acc data present(atm, ctl, dd)
1955#pragma acc parallel loop independent gang vector
1956#endif
1957 for (int ip = 0; ip < atm->np; ip++) {
1958
1959 /* Skip already invalid particles... */
1960 if (!init && (int) atm->q[ctl->qnt_current_subdomain][ip] == -1)
1961 continue;
1962
1963 /* Normalize coordinates... */
1964 double lon = atm->lon[ip];
1965 double lat = atm->lat[ip];
1966 dd_normalize_lon_lat(dd, &lon, &lat);
1967
1968 /* Check whether particle is inside owned core subdomain... */
1969 const int ix = locate_reg(dd->lon_glob, dd->nx_glob, lon);
1970 const int iy = locate_irr(dd->lat_glob, dd->ny_glob, lat);
1971 const int inside = (ix >= ix0 && ix < ix1 && iy >= iy0 && iy < iy1);
1972
1973 /* Init... */
1974 if (init) {
1975 atm->q[ctl->qnt_current_subdomain][ip] = inside ? rank : -1;
1976 atm->q[ctl->qnt_target_subdomain][ip] = inside ? rank : -1;
1977 }
1978
1979 /* Reassign... */
1980 else {
1981 atm->q[ctl->qnt_target_subdomain][ip] =
1982 inside ? rank : dd_calc_subdomain_from_coords(ctl, dd, lon, lat);
1983 }
1984 }
1985}
1986#endif
1987
1988/*****************************************************************************/
1989
1990#ifdef DD
1991void dd_atm2particles(
1992 const ctl_t *ctl,
1993 cache_t *cache,
1994 atm_t *atm,
1995 particle_t *particles,
1996 const int npart) {
1997
1998 /* Set timer... */
1999 SELECT_TIMER("DD_ATM2PARTICLES", "DD");
2000
2001 /* Check if particles are present... */
2002 if (npart == 0)
2003 return;
2004
2005 int rank;
2006 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
2007
2008 /* Select the particles that will be send... */
2009#ifdef _OPENACC
2010#pragma acc enter data create(npart, particles[:npart])
2011#pragma acc update device(npart, particles[:npart])
2012#pragma acc parallel loop present(atm, ctl, particles, cache, npart)
2013#endif
2014 for (int ip = atm->np; ip < atm->np + npart; ip++)
2015 if (((int) (atm->q[ctl->qnt_target_subdomain][ip]) != rank)
2016 && ((int) (atm->q[ctl->qnt_target_subdomain][ip]) >= 0)
2017 && ((int) atm->q[ctl->qnt_current_subdomain][ip] >= 0)) {
2018
2019 particles[ip - atm->np].time = atm->time[ip];
2020 particles[ip - atm->np].lon = atm->lon[ip];
2021 particles[ip - atm->np].lat = atm->lat[ip];
2022 particles[ip - atm->np].p = atm->p[ip];
2023 for (int iq = 0; iq < ctl->nq; iq++)
2024 particles[ip - atm->np].q[iq] = atm->q[iq][ip];
2025
2026 atm->q[ctl->qnt_current_subdomain][ip] = -1;
2027 cache->dt[ip] = 0;
2028 }
2029#ifdef _OPENACC
2030#pragma acc update host( particles[:npart])
2031#pragma acc exit data delete(npart, particles)
2032#endif
2033}
2034#endif
2035
2036/*****************************************************************************/
2037
2038#ifdef DD
2040 const ctl_t *ctl,
2041 const dd_t *dd,
2042 double lon,
2043 double lat) {
2044
2045 /* Normalize coordinates... */
2046 dd_normalize_lon_lat(dd, &lon, &lat);
2047
2048 /* Get grid index... */
2049 const int ix = locate_reg(dd->lon_glob, dd->nx_glob, lon);
2050 const int iy = locate_irr(dd->lat_glob, dd->ny_glob, lat);
2051
2052 /* Get zonal subdomain index... */
2053 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
2054 int zonal_rank = ix / nx_block;
2055 if (zonal_rank >= ctl->dd_subdomains_zonal)
2056 zonal_rank = ctl->dd_subdomains_zonal - 1;
2057
2058 /* Get meridional subdomain index... */
2059 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
2060 int merid_rank = iy / ny_block;
2061 if (merid_rank >= ctl->dd_subdomains_meridional)
2062 merid_rank = ctl->dd_subdomains_meridional - 1;
2063
2064 /* Return rank... */
2065 return zonal_rank * ctl->dd_subdomains_meridional + merid_rank;
2066}
2067#endif
2068
2069/*****************************************************************************/
2070
2071#ifdef DD
2073 const ctl_t *ctl,
2074 const dd_t *dd,
2075 particle_t **particles,
2076 int *npart,
2077 int *capacity) {
2078
2079 /* Set timer... */
2080 SELECT_TIMER("DD_COMMUNICATE_PARTICLES", "DD");
2081
2082 int rank, size;
2083 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
2084 MPI_Comm_size(MPI_COMM_WORLD, &size);
2085
2086 int *send_counts, *recv_counts;
2087 int *send_displs, *recv_displs;
2088 int *offsets;
2089
2090 particle_t *sendbuf = NULL;
2091 particle_t *recvbuf = NULL;
2092
2093 ALLOC(send_counts, int,
2094 size);
2095 ALLOC(recv_counts, int,
2096 size);
2097 ALLOC(send_displs, int,
2098 size);
2099 ALLOC(recv_displs, int,
2100 size);
2101 ALLOC(offsets, int,
2102 size);
2103
2104 /* Count particles per destination rank... */
2105#pragma omp parallel for
2106 for (int ip = 0; ip < *npart; ip++) {
2107 const int dest = (int) (*particles)[ip].q[ctl->qnt_target_subdomain];
2108 if (dest == rank)
2109 continue;
2110 if (dest < 0 || dest >= size)
2111 ERRMSG("Invalid destination rank!");
2112#pragma omp atomic
2113 send_counts[dest]++;
2114 }
2115
2116 /* Compute send displacements... */
2117 int nsend = 0;
2118 for (int i = 0; i < size; i++) {
2119 send_displs[i] = nsend;
2120 nsend += send_counts[i];
2121 }
2122
2123 /* Exchange particle counts... */
2124 MPI_Alltoall(send_counts, 1, MPI_INT,
2125 recv_counts, 1, MPI_INT, MPI_COMM_WORLD);
2126
2127 /* Compute receive displacements... */
2128 int nrecv = 0;
2129 for (int i = 0; i < size; i++) {
2130 recv_displs[i] = nrecv;
2131 nrecv += recv_counts[i];
2132 }
2133 if (nsend > 0)
2134 ALLOC(sendbuf, particle_t, nsend);
2135 if (nrecv > 0)
2136 ALLOC(recvbuf, particle_t, nrecv);
2137 for (int i = 0; i < size; i++)
2138 offsets[i] = send_displs[i];
2139
2140 /* Pack particles into send buffer... */
2141 for (int ip = 0; ip < *npart; ip++) {
2142 const int dest = (int) (*particles)[ip].q[ctl->qnt_target_subdomain];
2143 if (dest == rank)
2144 continue;
2145 memcpy(&sendbuf[offsets[dest]], &(*particles)[ip], sizeof(particle_t));
2146 offsets[dest]++;
2147 }
2148
2149 /* Exchange particle data... */
2150 MPI_Alltoallv(sendbuf,
2151 send_counts,
2152 send_displs,
2153 dd->MPI_Particle,
2154 recvbuf,
2155 recv_counts, recv_displs, dd->MPI_Particle, MPI_COMM_WORLD);
2156
2157 /* Resize particle buffer if necessary... */
2158 if (nrecv > *capacity) {
2159 const int newcap = nrecv + nrecv / 2 + 1;
2160 particle_t *tmp =
2161 realloc(*particles, (size_t) newcap * sizeof(particle_t));
2162 if (!tmp)
2163 ERRMSG("Out of memory!");
2164 *particles = tmp;
2165 *capacity = newcap;
2166 }
2167
2168 /* Copy received particles... */
2169#pragma omp parallel for
2170 for (int ip = 0; ip < nrecv; ip++) {
2171 (*particles)[ip] = recvbuf[ip];
2172 (*particles)[ip].q[ctl->qnt_target_subdomain] = rank;
2173 (*particles)[ip].q[ctl->qnt_current_subdomain] = rank;
2174 }
2175 *npart = nrecv;
2176
2177 /* Free temporary buffers... */
2178 if (sendbuf)
2179 free(sendbuf);
2180 if (recvbuf)
2181 free(recvbuf);
2182 free(send_counts);
2183 free(recv_counts);
2184 free(send_displs);
2185 free(recv_displs);
2186 free(offsets);
2187}
2188#endif
2189
2190/*****************************************************************************/
2191
2192#ifdef DD
2193void dd_init(
2194 const ctl_t *ctl,
2195 dd_t *dd,
2196 atm_t *atm) {
2197
2198 /* Check configuration... */
2199 if ((ctl->dd) &&
2201 ERRMSG("Please provide zonal and meridional subdomain numbers!");
2202 if (!ctl->dd)
2203 ERRMSG("Activate controle flag DD!");
2204
2205 /* Check if enough tasks are requested... */
2206 int size;
2207 MPI_Comm_size(MPI_COMM_WORLD, &size);
2208 if (size != ctl->dd_subdomains_meridional * ctl->dd_subdomains_zonal)
2209 ERRMSG("Number of tasks and subdomains is not identical!");
2210
2211 /* Register the MPI_Particle data type... */
2212 const MPI_Datatype types[5] =
2213 { MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE };
2214 const int blocklengths[5] = { 1, 1, 1, 1, NQ };
2215 const MPI_Aint displacements[5] =
2216 { offsetof(particle_t, time), offsetof(particle_t, p),
2217 offsetof(particle_t, lon), offsetof(particle_t, lat),
2218 offsetof(particle_t, q)
2219 };
2220 MPI_Type_create_struct(5, blocklengths, displacements, types,
2221 &dd->MPI_Particle);
2222 MPI_Type_commit(&dd->MPI_Particle);
2223
2224 /* Check if particles are in subdomain... */
2225 dd_assign_subdomains(ctl, dd, atm, 1);
2226}
2227#endif
2228
2229/*****************************************************************************/
2230
2231#ifdef DD
2233 const dd_t *dd,
2234 double *lon,
2235 double *lat) {
2236
2237 const double lon_min = (dd->lon_glob[0] < 0) ? -180.0 : 0.0;
2238
2239 /* Normalize longitude to match global grid convention... */
2240 *lon = FMOD(*lon - lon_min, 360.0);
2241 if (*lon < 0.0)
2242 *lon += 360.0;
2243 *lon += lon_min;
2244
2245 /* Wrap latitude across the poles and shift longitude... */
2246 if (*lat > 90.0) {
2247 *lat = 180.0 - *lat;
2248 *lon += 180.0;
2249 } else if (*lat < -90.0) {
2250 *lat = -180.0 - *lat;
2251 *lon += 180.0;
2252 }
2253
2254 /* Renormalize longitude after pole crossing... */
2255 *lon = FMOD(*lon - lon_min, 360.0);
2256 if (*lon < 0.0)
2257 *lon += 360.0;
2258 *lon += lon_min;
2259}
2260#endif
2261
2262/*****************************************************************************/
2263
2264#ifdef DD
2265void dd_particles2atm(
2266 const ctl_t *ctl,
2267 cache_t *cache,
2268 const particle_t *particles,
2269 const int npart,
2270 atm_t *atm) {
2271
2272 /* Set timer... */
2273 SELECT_TIMER("DD_PARTICLES2ATM", "DD");
2274
2275 /* Check if particles are present... */
2276 if (npart == 0)
2277 return;
2278
2279 /* Check number of particles... */
2280 if (atm->np + npart > NP)
2281 ERRMSG("Too many particles. Increase NP!");
2282
2283#ifdef _OPENACC
2284#pragma acc enter data create(npart, particles[:npart])
2285#pragma acc update device(particles[:npart], npart)
2286#pragma acc data present(atm, ctl, cache, particles, npart)
2287#pragma acc parallel loop
2288#endif
2289 for (int ip = atm->np; ip < atm->np + npart; ip++) {
2290 atm->time[ip] = particles[ip - atm->np].time;
2291 atm->lon[ip] = particles[ip - atm->np].lon;
2292 atm->lat[ip] = particles[ip - atm->np].lat;
2293 atm->p[ip] = particles[ip - atm->np].p;
2294 for (int iq = 0; iq < ctl->nq; iq++)
2295 atm->q[iq][ip] = particles[ip - atm->np].q[iq];
2296 cache->dt[ip] = ctl->dt_mod;
2297 }
2298#ifdef _OPENACC
2299#pragma acc exit data delete(npart, particles)
2300#endif
2301
2302 /* Reset size... */
2303 atm->np += npart;
2304#ifdef _OPENACC
2305#pragma acc update device(atm->np)
2306#endif
2307}
2308#endif
2309
2310/*****************************************************************************/
2311
2312#ifdef DD
2313void dd_push(
2314 const ctl_t *ctl,
2315 atm_t *atm,
2316 cache_t *cache,
2317 int *npart) {
2318 SELECT_TIMER("DD_PUSH", "DD");
2319 int rank;
2320 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
2321
2322 int counter = 0;
2323
2324#ifdef _OPENACC
2325 int *counter_ptr = (int *) acc_malloc(sizeof(int));
2326 if (counter_ptr == NULL) {
2327 ERRMSG("Failed to allocate device counter memory!");
2328 }
2329 acc_memcpy_to_device(counter_ptr, &counter, sizeof(int));
2330#else
2331 int *counter_ptr = &counter;
2332#endif
2333
2334 /* Push non local particles behind the end of the atm... */
2335#ifdef _OPENACC
2336#pragma acc parallel loop present(atm, cache) deviceptr(counter_ptr)
2337#else
2338#pragma omp parallel for
2339#endif
2340 for (int ip = 0; ip < atm->np; ip++) {
2341 if ((int) atm->q[ctl->qnt_current_subdomain][ip] != -1 &&
2342 (int) atm->q[ctl->qnt_target_subdomain][ip] != rank) {
2343 int local_idx;
2344#ifdef _OPENACC
2345#pragma acc atomic capture
2346#else
2347#pragma omp atomic capture
2348#endif
2349 {
2350 local_idx = *counter_ptr;
2351 (*counter_ptr)++;
2352 }
2353 int global_index = atm->np + local_idx;
2354 /* Copy time, pressure, longitude, and latitude... */
2355 atm->time[global_index] = atm->time[ip];
2356 atm->p[global_index] = atm->p[ip];
2357 atm->lon[global_index] = atm->lon[ip];
2358 atm->lat[global_index] = atm->lat[ip];
2359 /* Copy all quantity data (q array)... */
2360 for (int iq = 0; iq < ctl->nq; iq++) {
2361 atm->q[iq][global_index] = atm->q[iq][ip];
2362 }
2363 /* Mark the original parcel as processed... */
2364 atm->q[ctl->qnt_target_subdomain][ip] = -1;
2365 atm->q[ctl->qnt_current_subdomain][ip] = -1;
2366 /* Reset cache->dt for the shifted particle... */
2367 cache->dt[global_index] = cache->dt[ip];
2368 cache->dt[ip] = 0;
2369 }
2370 }
2371
2372#ifdef _OPENACC
2373 acc_memcpy_from_device(npart, counter_ptr, sizeof(int));
2374 acc_free(counter_ptr);
2375#else
2376 *npart = counter;
2377#endif
2378}
2379#endif
2380
2381/*****************************************************************************/
2382
2383#ifdef DD
2384void dd_sort(
2385 const ctl_t *ctl,
2386 const met_t *met0,
2387 atm_t *atm,
2388 dd_t *dd,
2389 int *npart) {
2390
2391 /* Set timer... */
2392 SELECT_TIMER("DD_SORT", "DD");
2393
2394 int rank;
2395 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
2396
2397 /* Allocate... */
2398 const int np = atm->np;
2399 double amax = (met0->nx * met0->ny + met0->ny) * met0->np + met0->np;
2400#ifdef _OPENACC
2401#pragma acc enter data create(amax)
2402#pragma acc update device(amax)
2403#pragma acc data present(ctl,met0,atm,dd,amax)
2404#endif
2405
2406 /* Get box index... */
2407#ifdef _OPENACC
2408#pragma acc parallel loop independent gang vector
2409#else
2410#pragma omp parallel for default(shared)
2411#endif
2412 for (int ip = 0; ip < np; ip++) {
2413 if ((int) atm->q[ctl->qnt_current_subdomain][ip] != -1) {
2414 if ((int) atm->q[ctl->qnt_target_subdomain][ip] == rank)
2415 dd->sort_key[ip] =
2416 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) *
2417 met0->ny + locate_irr(met0->lat, met0->ny, atm->lat[ip]))
2418 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
2419 else
2420 dd->sort_key[ip] = amax + 1;
2421 } else {
2422 dd->sort_key[ip] = amax + 2;
2423 }
2424 dd->perm[ip] = ip;
2425 }
2426
2427 /* Sorting... */
2428#ifdef THRUST
2429#ifdef _OPENACC
2430#pragma acc host_data use_device(dd->sort_key, dd->perm)
2431#endif
2432 thrustSortWrapper(dd->sort_key, np, dd->perm);
2433#else
2434 size_t *perm_sz = (size_t *) malloc((size_t) np * sizeof(size_t));
2435 if (perm_sz == NULL)
2436 ERRMSG("Out of memory!");
2437#ifdef _OPENACC
2438#pragma acc update self(dd->sort_key[0:np])
2439#endif
2440 gsl_sort_index(perm_sz, dd->sort_key, 1, (size_t) np);
2441 for (int ip = 0; ip < np; ++ip)
2442 dd->perm[ip] = (int) perm_sz[ip];
2443 free(perm_sz);
2444#ifdef _OPENACC
2445#pragma acc update device(dd->perm[0:np])
2446#endif
2447#endif
2448
2449 /* Sort data... */
2450 dd_sort_help(atm->time, dd, np);
2451 dd_sort_help(atm->p, dd, np);
2452 dd_sort_help(atm->lon, dd, np);
2453 dd_sort_help(atm->lat, dd, np);
2454 for (int iq = 0; iq < ctl->nq; iq++)
2455 dd_sort_help(atm->q[iq], dd, np);
2456
2457 /* Reset the size... */
2458 int nkeep = 0;
2459#ifdef _OPENACC
2460#pragma acc parallel loop reduction(+:nkeep) present(atm, ctl)
2461#endif
2462 for (int ip = 0; ip < np; ip++)
2463 if (((int) atm->q[ctl->qnt_current_subdomain][ip] != -1)
2464 && ((int) atm->q[ctl->qnt_target_subdomain][ip] == rank))
2465 nkeep++;
2466
2467 /* Count number of particles to send... */
2468 int nsend = 0;
2469#ifdef _OPENACC
2470#pragma acc parallel loop reduction(+:nsend) present(atm, ctl)
2471#endif
2472 for (int ip = nkeep; ip < np; ip++)
2473 if (((int) atm->q[ctl->qnt_current_subdomain][ip] != -1)
2474 && ((int) atm->q[ctl->qnt_target_subdomain][ip] != rank))
2475 nsend++;
2476
2477 /* Reset sizes... */
2478 *npart = nsend;
2479
2480 /* Count particles with -1 subdomain (these will be effectively lost) */
2481 int nlost = 0;
2482 for (int ip = 0; ip < np; ip++)
2483 if ((int) atm->q[ctl->qnt_current_subdomain][ip] == -1)
2484 nlost++;
2485
2486 if (nlost > 0)
2487 WARN
2488 ("Rank %d: %d particles have subdomain index -1 and will be lost (kept: %d, to_send: %d, total_before: %d)",
2489 rank, nlost, nkeep, nsend, np);
2490
2491 atm->np = nkeep;
2492#ifdef _OPENACC
2493#pragma acc update device(atm->np)
2494#endif
2495
2496 /* Free... */
2497#ifdef _OPENACC
2498#pragma acc exit data delete(amax)
2499#endif
2500}
2501#endif
2502
2503/*****************************************************************************/
2504
2505#ifdef DD
2506void dd_sort_help(
2507 double *a,
2508 dd_t *dd,
2509 const int np) {
2510
2511 /* Reordering of array... */
2512#ifdef _OPENACC
2513#pragma acc data present(dd,a)
2514#pragma acc parallel loop independent gang vector
2515#else
2516#pragma omp parallel for default(shared)
2517#endif
2518 for (int ip = 0; ip < np; ip++)
2519 dd->tmp[ip] = a[dd->perm[ip]];
2520#ifdef _OPENACC
2521#pragma acc parallel loop independent gang vector
2522#else
2523#pragma omp parallel for default(shared)
2524#endif
2525 for (int ip = 0; ip < np; ip++)
2526 a[ip] = dd->tmp[ip];
2527}
2528#endif
2529
2530/*****************************************************************************/
2531
2533 const int year,
2534 const int doy,
2535 int *mon,
2536 int *day) {
2537
2538 const int
2539 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
2540 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
2541
2542 int i;
2543
2544 /* Get month and day... */
2545 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
2546 for (i = 11; i > 0; i--)
2547 if (d0l[i] <= doy)
2548 break;
2549 *mon = i + 1;
2550 *day = doy - d0l[i] + 1;
2551 } else {
2552 for (i = 11; i > 0; i--)
2553 if (d0[i] <= doy)
2554 break;
2555 *mon = i + 1;
2556 *day = doy - d0[i] + 1;
2557 }
2558}
2559
2560/*****************************************************************************/
2561
2563 double *fcReal,
2564 double *fcImag,
2565 const int n) {
2566
2567 double data[2 * EX];
2568
2569 /* Check size... */
2570 if (n > EX)
2571 ERRMSG("Too many data points!");
2572
2573 /* Allocate... */
2574 gsl_fft_complex_wavetable *wavetable =
2575 gsl_fft_complex_wavetable_alloc((size_t) n);
2576 gsl_fft_complex_workspace *workspace =
2577 gsl_fft_complex_workspace_alloc((size_t) n);
2578
2579 /* Set data (real, complex)... */
2580 for (int i = 0; i < n; i++) {
2581 data[2 * i] = fcReal[i];
2582 data[2 * i + 1] = fcImag[i];
2583 }
2584
2585 /* Calculate FFT... */
2586 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
2587
2588 /* Copy data... */
2589 for (int i = 0; i < n; i++) {
2590 fcReal[i] = data[2 * i];
2591 fcImag[i] = data[2 * i + 1];
2592 }
2593
2594 /* Free... */
2595 gsl_fft_complex_wavetable_free(wavetable);
2596 gsl_fft_complex_workspace_free(workspace);
2597}
2598
2599/*****************************************************************************/
2600
2602 const double z,
2603 const double lon,
2604 const double lat,
2605 double *x) {
2606
2607 const double radius = z + RE;
2608 const double latrad = DEG2RAD(lat);
2609 const double lonrad = DEG2RAD(lon);
2610 const double coslat = cos(latrad);
2611
2612 x[0] = radius * coslat * cos(lonrad);
2613 x[1] = radius * coslat * sin(lonrad);
2614 x[2] = radius * sin(latrad);
2615}
2616
2617/*****************************************************************************/
2618
2620 const ctl_t *ctl,
2621 const double t,
2622 const int direct,
2623 const char *metbase,
2624 const double dt_met,
2625 char *filename) {
2626
2627 char repl[LEN];
2628
2629 double t6, r;
2630
2631 int year, mon, day, hour, min, sec;
2632
2633 /* Round time to fixed intervals... */
2634 if (direct == -1)
2635 t6 = floor(t / dt_met) * dt_met;
2636 else
2637 t6 = ceil(t / dt_met) * dt_met;
2638
2639 /* Decode time... */
2640 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
2641
2642 /* Set filename of MPTRAC meteo files... */
2643 if (ctl->met_clams == 0) {
2644 if (ctl->met_type == 0)
2645 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
2646 else if (ctl->met_type == 1)
2647 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
2648 else if (ctl->met_type == 2)
2649 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
2650 else if (ctl->met_type == 3)
2651 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
2652 else if (ctl->met_type == 4)
2653 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
2654 else if (ctl->met_type == 5)
2655 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
2656 else if (ctl->met_type == 7)
2657 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
2658 else if (ctl->met_type == 8)
2659 sprintf(filename, "%s_YYYY_MM_DD_HH.lz4", metbase);
2660 sprintf(repl, "%d", year);
2661 get_met_replace(filename, "YYYY", repl);
2662 sprintf(repl, "%02d", mon);
2663 get_met_replace(filename, "MM", repl);
2664 sprintf(repl, "%02d", day);
2665 get_met_replace(filename, "DD", repl);
2666 sprintf(repl, "%02d", hour);
2667 get_met_replace(filename, "HH", repl);
2668 }
2669
2670 /* Set filename of CLaMS meteo files... */
2671 else {
2672 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
2673 sprintf(repl, "%d", year);
2674 get_met_replace(filename, "YYYY", repl);
2675 sprintf(repl, "%02d", year % 100);
2676 get_met_replace(filename, "YY", repl);
2677 sprintf(repl, "%02d", mon);
2678 get_met_replace(filename, "MM", repl);
2679 sprintf(repl, "%02d", day);
2680 get_met_replace(filename, "DD", repl);
2681 sprintf(repl, "%02d", hour);
2682 get_met_replace(filename, "HH", repl);
2683 }
2684}
2685
2686/*****************************************************************************/
2687
2689 char *orig,
2690 const char *search,
2691 const char *repl) {
2692
2693 char buffer[LEN];
2694
2695 /* Iterate... */
2696 for (int i = 0; i < 3; i++) {
2697
2698 /* Replace sub-string... */
2699 char *ch;
2700 if (!(ch = strstr(orig, search)))
2701 return;
2702 strncpy(buffer, orig, (size_t) (ch - orig));
2703 buffer[ch - orig] = 0;
2704 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
2705 orig[0] = 0;
2706 strcpy(orig, buffer);
2707 }
2708}
2709
2710/*****************************************************************************/
2711
2713 const int met_tropo,
2714 ctl_t *ctl,
2715 const clim_t *clim,
2716 met_t *met,
2717 const double *lons,
2718 const int nx,
2719 const double *lats,
2720 const int ny,
2721 double *pt,
2722 double *zt,
2723 double *tt,
2724 double *qt,
2725 double *o3t,
2726 double *ps,
2727 double *zs) {
2728
2730
2731 ctl->met_tropo = met_tropo;
2732 read_met_tropo(ctl, clim, met);
2733#pragma omp parallel for default(shared) private(ci,cw)
2734 for (int ix = 0; ix < nx; ix++)
2735 for (int iy = 0; iy < ny; iy++) {
2736 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
2737 &pt[iy * nx + ix], ci, cw, 1);
2738 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
2739 &ps[iy * nx + ix], ci, cw, 0);
2740 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
2741 &zs[iy * nx + ix], ci, cw, 0);
2742 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
2743 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
2744 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
2745 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
2746 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
2747 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
2748 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
2749 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
2750 }
2751}
2752
2753/*****************************************************************************/
2754
2756 const double *lons,
2757 const int nlon,
2758 const double *lats,
2759 const int nlat,
2760 const double lon,
2761 const double lat,
2762 double *lon2,
2763 double *lat2) {
2764
2765 /* Check longitude... */
2766 *lon2 = FMOD(lon, 360.);
2767 if (*lon2 < lons[0])
2768 *lon2 += 360;
2769 else if (*lon2 > lons[nlon - 1])
2770 *lon2 -= 360;
2771
2772 /* Check latitude... */
2773 *lat2 = lat;
2774 if (lats[0] < lats[nlat - 1])
2775 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
2776 else
2777 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
2778}
2779
2780/*****************************************************************************/
2781
2783 const double *lons,
2784 const int nlon,
2785 const double *lats,
2786 const int nlat,
2787 const double lon,
2788 const double lat,
2789 double *lon2,
2790 double *lat2) {
2791
2792 *lon2 = lon;
2793 if (lons[0] < lons[nlon - 1])
2794 *lon2 = MIN(MAX(lon, lons[0]), lons[nlon - 1]);
2795 else
2796 *lon2 = MIN(MAX(lon, lons[nlon - 1]), lons[0]);
2797
2798 *lat2 = lat;
2799 if (lats[0] < lats[nlat - 1])
2800 *lat2 = MIN(MAX(lat, lats[0]), lats[nlat - 1]);
2801 else
2802 *lat2 = MIN(MAX(lat, lats[nlat - 1]), lats[0]);
2803}
2804
2805
2806/*****************************************************************************/
2807
2809 const met_t *met0,
2810 float heights0[EX][EY][EP],
2811 float array0[EX][EY][EP],
2812 const met_t *met1,
2813 float heights1[EX][EY][EP],
2814 float array1[EX][EY][EP],
2815 const double ts,
2816 const double height,
2817 const double lon,
2818 const double lat,
2819 double *var,
2820 int *ci,
2821 double *cw,
2822 const int init) {
2823
2824 if (init) {
2825
2826 /* Check longitude and latitude... */
2827 double lon2, lat2;
2828
2829 if (met0->coord_type == 0)
2830 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
2831 &lon2, &lat2);
2832 else
2833 intpol_check_cartesian(met0->lon, met0->nx, met0->lat, met0->ny, lon,
2834 lat, &lon2, &lat2);
2835
2836 /* Get horizontal indizes... */
2837 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
2838 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
2839
2840 /* Locate the vertical indizes for each edge of the column... */
2841 int ind[2][4];
2842 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
2843 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
2844
2845 /* Find minimum and maximum indizes... */
2846 ci[2] = ind[0][0];
2847 int k_max = ind[0][0];
2848 for (int i = 0; i < 2; i++)
2849 for (int j = 0; j < 4; j++) {
2850 if (ci[2] > ind[i][j])
2851 ci[2] = ind[i][j];
2852 if (k_max < ind[i][j])
2853 k_max = ind[i][j];
2854 }
2855
2856 /* Get weighting factors for time, longitude and latitude... */
2857 cw[3] = (ts - met0->time) / (met1->time - met0->time);
2858 cw[0] = (lon2 - met0->lon[ci[0]]) /
2859 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
2860 cw[1] = (lat2 - met0->lat[ci[1]]) /
2861 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
2862
2863 /* Interpolate in time at the lowest level... */
2864 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
2865 - heights0[ci[0]][ci[1]][ci[2]])
2866 + heights0[ci[0]][ci[1]][ci[2]];
2867 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
2868 - heights0[ci[0]][ci[1] + 1][ci[2]])
2869 + heights0[ci[0]][ci[1] + 1][ci[2]];
2870 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
2871 - heights0[ci[0] + 1][ci[1]][ci[2]])
2872 + heights0[ci[0] + 1][ci[1]][ci[2]];
2873 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
2874 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
2875 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
2876
2877 /* Interpolate in latitude direction... */
2878 double height0 = cw[1] * (height01 - height00) + height00;
2879 double height1 = cw[1] * (height11 - height10) + height10;
2880
2881 /* Interpolate in longitude direction... */
2882 double height_bot = cw[0] * (height1 - height0) + height0;
2883
2884 /* Interpolate in time at the upper level... */
2885 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2886 - heights0[ci[0]][ci[1]][ci[2] + 1])
2887 + heights0[ci[0]][ci[1]][ci[2] + 1];
2888 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2889 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2890 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2891 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2892 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2893 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2894 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2895 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2896 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2897
2898 /* Interpolate in latitude direction... */
2899 height0 = cw[1] * (height01 - height00) + height00;
2900 height1 = cw[1] * (height11 - height10) + height10;
2901
2902 /* Interpolate in longitude direction... */
2903 double height_top = cw[0] * (height1 - height0) + height0;
2904
2905 /* Search at higher levels if height is not in box... */
2906 while (((heights0[0][0][0] > heights0[0][0][1]) &&
2907 ((height_bot <= height) || (height_top > height))
2908 && (height_bot >= height) && (ci[2] < k_max))
2909 ||
2910 ((heights0[0][0][0] < heights0[0][0][1]) &&
2911 ((height_bot >= height) || (height_top < height))
2912 && (height_bot <= height) && (ci[2] < k_max))
2913 ) {
2914
2915 ci[2]++;
2916 height_bot = height_top;
2917
2918 /* Interpolate in time at the next level... */
2919 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2920 - heights0[ci[0]][ci[1]][ci[2] + 1])
2921 + heights0[ci[0]][ci[1]][ci[2] + 1];
2922 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2923 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2924 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2925 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2926 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2927 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2928 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2929 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2930 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2931
2932 /* Interpolate in latitude direction... */
2933 height0 = cw[1] * (height01 - height00) + height00;
2934 height1 = cw[1] * (height11 - height10) + height10;
2935
2936 /* Interpolate in longitude direction... */
2937 height_top = cw[0] * (height1 - height0) + height0;
2938 }
2939
2940 /* Get vertical weighting factors... */
2941 cw[2] = (height - height_bot)
2942 / (height_top - height_bot);
2943 }
2944
2945 /* Calculate the needed array values... */
2946 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
2947 - array0[ci[0]][ci[1]][ci[2]])
2948 + array0[ci[0]][ci[1]][ci[2]];
2949 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
2950 - array0[ci[0] + 1][ci[1]][ci[2]])
2951 + array0[ci[0] + 1][ci[1]][ci[2]];
2952 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
2953 - array0[ci[0]][ci[1] + 1][ci[2]])
2954 + array0[ci[0]][ci[1] + 1][ci[2]];
2955 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
2956 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
2957 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
2958 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
2959 - array0[ci[0]][ci[1]][ci[2] + 1])
2960 + array0[ci[0]][ci[1]][ci[2] + 1];
2961 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2962 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2963 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2964 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2965 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2966 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2967 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2968 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2969 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2970
2971 const double array00 = cw[0] * (array100 - array000) + array000;
2972 const double array10 = cw[0] * (array110 - array010) + array010;
2973 const double array01 = cw[0] * (array101 - array001) + array001;
2974 const double array11 = cw[0] * (array111 - array011) + array011;
2975
2976 const double aux0 = cw[1] * (array10 - array00) + array00;
2977 const double aux1 = cw[1] * (array11 - array01) + array01;
2978
2979 /* Interpolate vertically... */
2980 *var = cw[2] * (aux1 - aux0) + aux0;
2981}
2982
2983/*****************************************************************************/
2984
2986 const met_t *met,
2987 float array[EX][EY][EP],
2988 const double p,
2989 const double lon,
2990 const double lat,
2991 double *var,
2992 int *ci,
2993 double *cw,
2994 const int init) {
2995
2996 /* Initialize interpolation... */
2997 if (init) {
2998
2999 /* Check longitude and latitude... */
3000 double lon2, lat2;
3001
3002 if (met->coord_type == 0)
3003 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
3004 &lon2, &lat2);
3005 else
3006 intpol_check_cartesian(met->lon, met->nx, met->lat, met->ny, lon, lat,
3007 &lon2, &lat2);
3008
3009 /* Get interpolation indices... */
3010 ci[0] = locate_irr(met->p, met->np, p);
3011 ci[1] = locate_reg(met->lon, met->nx, lon2);
3012 ci[2] = locate_irr(met->lat, met->ny, lat2);
3013
3014 /* Get interpolation weights... */
3015 cw[0] = (met->p[ci[0] + 1] - p)
3016 / (met->p[ci[0] + 1] - met->p[ci[0]]);
3017 cw[1] = (met->lon[ci[1] + 1] - lon2)
3018 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
3019 cw[2] = (met->lat[ci[2] + 1] - lat2)
3020 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
3021 }
3022
3023 /* Interpolate vertically... */
3024 const double aux00 =
3025 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
3026 + array[ci[1]][ci[2]][ci[0] + 1];
3027 const double aux01 =
3028 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
3029 array[ci[1]][ci[2] + 1][ci[0] + 1])
3030 + array[ci[1]][ci[2] + 1][ci[0] + 1];
3031 const double aux10 =
3032 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
3033 array[ci[1] + 1][ci[2]][ci[0] + 1])
3034 + array[ci[1] + 1][ci[2]][ci[0] + 1];
3035 const double aux11 =
3036 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
3037 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
3038 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
3039
3040 /* Interpolate horizontally... */
3041 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
3042 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
3043 *var = cw[1] * (aux0 - aux1) + aux1;
3044}
3045
3046/*****************************************************************************/
3047
3049 const met_t *met,
3050 float array[EX][EY],
3051 const double lon,
3052 const double lat,
3053 double *var,
3054 int *ci,
3055 double *cw,
3056 const int init) {
3057
3058 /* Initialize interpolation... */
3059 if (init) {
3060
3061 /* Check longitude and latitude... */
3062 double lon2, lat2;
3063
3064 if (met->coord_type == 0)
3065 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
3066 &lon2, &lat2);
3067 else
3068 intpol_check_cartesian(met->lon, met->nx, met->lat, met->ny, lon, lat,
3069 &lon2, &lat2);
3070
3071
3072 /* Get interpolation indices... */
3073 ci[1] = locate_reg(met->lon, met->nx, lon2);
3074 ci[2] = locate_irr(met->lat, met->ny, lat2);
3075
3076 /* Get interpolation weights... */
3077 cw[1] = (met->lon[ci[1] + 1] - lon2)
3078 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
3079 cw[2] = (met->lat[ci[2] + 1] - lat2)
3080 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
3081 }
3082
3083 /* Set variables... */
3084 const double aux00 = array[ci[1]][ci[2]];
3085 const double aux01 = array[ci[1]][ci[2] + 1];
3086 const double aux10 = array[ci[1] + 1][ci[2]];
3087 const double aux11 = array[ci[1] + 1][ci[2] + 1];
3088
3089 /* Interpolate horizontally... */
3090 if (isfinite(aux00) && isfinite(aux01)
3091 && isfinite(aux10) && isfinite(aux11)) {
3092 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
3093 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
3094 *var = cw[1] * (aux0 - aux1) + aux1;
3095 } else {
3096 if (cw[2] < 0.5) {
3097 if (cw[1] < 0.5)
3098 *var = aux11;
3099 else
3100 *var = aux01;
3101 } else {
3102 if (cw[1] < 0.5)
3103 *var = aux10;
3104 else
3105 *var = aux00;
3106 }
3107 }
3108}
3109
3110/*****************************************************************************/
3111
3113 const met_t *met0,
3114 float array0[EX][EY][EP],
3115 const met_t *met1,
3116 float array1[EX][EY][EP],
3117 const double ts,
3118 const double p,
3119 const double lon,
3120 const double lat,
3121 double *var,
3122 int *ci,
3123 double *cw,
3124 const int init) {
3125
3126 double var0, var1;
3127
3128 /* Spatial interpolation... */
3129 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
3130 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
3131
3132 /* Get weighting factor... */
3133 const double wt = (met1->time - ts) / (met1->time - met0->time);
3134
3135 /* Interpolate... */
3136 *var = wt * (var0 - var1) + var1;
3137}
3138
3139/*****************************************************************************/
3140
3142 const met_t *met0,
3143 float array0[EX][EY],
3144 const met_t *met1,
3145 float array1[EX][EY],
3146 const double ts,
3147 const double lon,
3148 const double lat,
3149 double *var,
3150 int *ci,
3151 double *cw,
3152 const int init) {
3153
3154 double var0, var1;
3155
3156 /* Spatial interpolation... */
3157 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
3158 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
3159
3160 /* Get weighting factor... */
3161 const double wt = (met1->time - ts) / (met1->time - met0->time);
3162
3163 /* Interpolate... */
3164 if (isfinite(var0) && isfinite(var1))
3165 *var = wt * (var0 - var1) + var1;
3166 else if (wt < 0.5)
3167 *var = var1;
3168 else
3169 *var = var0;
3170}
3171
3172/*****************************************************************************/
3173
3175 const double time0,
3176 float array0[EX][EY],
3177 const double time1,
3178 float array1[EX][EY],
3179 const double lons[EX],
3180 const double lats[EY],
3181 const int nlon,
3182 const int nlat,
3183 const double time,
3184 const double lon,
3185 const double lat,
3186 const int method,
3187 double *var,
3188 double *sigma) {
3189
3190 double mean = 0;
3191
3192 int n = 0;
3193
3194 /* Check longitude and latitude... */
3195 double lon2, lat2;
3196 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
3197
3198 /* Get indices... */
3199 const int ix = locate_reg(lons, (int) nlon, lon2);
3200 const int iy = locate_irr(lats, (int) nlat, lat2);
3201
3202 /* Calculate standard deviation... */
3203 *sigma = 0;
3204 for (int dx = 0; dx < 2; dx++)
3205 for (int dy = 0; dy < 2; dy++) {
3206 if (isfinite(array0[ix + dx][iy + dy])) {
3207 mean += array0[ix + dx][iy + dy];
3208 *sigma += SQR(array0[ix + dx][iy + dy]);
3209 n++;
3210 }
3211 if (isfinite(array1[ix + dx][iy + dy])) {
3212 mean += array1[ix + dx][iy + dy];
3213 *sigma += SQR(array1[ix + dx][iy + dy]);
3214 n++;
3215 }
3216 }
3217 if (n > 0)
3218 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
3219
3220 /* Linear interpolation... */
3221 if (method == 1 && isfinite(array0[ix][iy])
3222 && isfinite(array0[ix][iy + 1])
3223 && isfinite(array0[ix + 1][iy])
3224 && isfinite(array0[ix + 1][iy + 1])
3225 && isfinite(array1[ix][iy])
3226 && isfinite(array1[ix][iy + 1])
3227 && isfinite(array1[ix + 1][iy])
3228 && isfinite(array1[ix + 1][iy + 1])) {
3229
3230 const double aux00 = LIN(lons[ix], array0[ix][iy],
3231 lons[ix + 1], array0[ix + 1][iy], lon2);
3232 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
3233 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
3234 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
3235
3236 const double aux10 = LIN(lons[ix], array1[ix][iy],
3237 lons[ix + 1], array1[ix + 1][iy], lon2);
3238 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
3239 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
3240 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
3241
3242 *var = LIN(time0, aux0, time1, aux1, time);
3243 }
3244
3245 /* Nearest neighbor interpolation... */
3246 else {
3247 const double aux00 = NN(lons[ix], array0[ix][iy],
3248 lons[ix + 1], array0[ix + 1][iy], lon2);
3249 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
3250 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
3251 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
3252
3253 const double aux10 = NN(lons[ix], array1[ix][iy],
3254 lons[ix + 1], array1[ix + 1][iy], lon2);
3255 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
3256 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
3257 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
3258
3259 *var = NN(time0, aux0, time1, aux1, time);
3260 }
3261}
3262
3263/*****************************************************************************/
3264
3266 const double jsec,
3267 int *year,
3268 int *mon,
3269 int *day,
3270 int *hour,
3271 int *min,
3272 int *sec,
3273 double *remain) {
3274
3275 struct tm t0, *t1;
3276
3277 t0.tm_year = 100;
3278 t0.tm_mon = 0;
3279 t0.tm_mday = 1;
3280 t0.tm_hour = 0;
3281 t0.tm_min = 0;
3282 t0.tm_sec = 0;
3283
3284 const time_t jsec0 = (time_t) jsec + timegm(&t0);
3285 t1 = gmtime(&jsec0);
3286
3287 *year = t1->tm_year + 1900;
3288 *mon = t1->tm_mon + 1;
3289 *day = t1->tm_mday;
3290 *hour = t1->tm_hour;
3291 *min = t1->tm_min;
3292 *sec = t1->tm_sec;
3293 *remain = jsec - floor(jsec);
3294}
3295
3296/*****************************************************************************/
3297
3299 const double kz[EP],
3300 const double kw[EP],
3301 const int nk,
3302 const double p) {
3303
3304 /* Check number of data points... */
3305 if (nk < 2)
3306 return 1.0;
3307
3308 /* Get altitude... */
3309 const double z = Z(p);
3310
3311 /* Get weighting factor... */
3312 if (z < kz[0])
3313 return kw[0];
3314 else if (z > kz[nk - 1])
3315 return kw[nk - 1];
3316 else {
3317 const int idx = locate_irr(kz, nk, z);
3318 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
3319 }
3320}
3321
3322/*****************************************************************************/
3323
3325 const double t,
3326 const double h2o) {
3327
3328 /*
3329 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
3330 and water vapor volume mixing ratio [1].
3331
3332 Reference: https://en.wikipedia.org/wiki/Lapse_rate
3333 */
3334
3335 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
3336
3337 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
3338}
3339
3340/*****************************************************************************/
3341
3343 ctl_t *ctl) {
3344
3345 if (0 == ctl->met_press_level_def) {
3346
3347 ERRMSG
3348 ("MET_PRESS_LEVEL_DEF=0 is disabled. Use 3 for the extended L137 set.");
3349
3350 } else if (1 == ctl->met_press_level_def) {
3351
3352 ERRMSG
3353 ("MET_PRESS_LEVEL_DEF=1 is disabled. Use 4 for the extended L91 set.");
3354
3355 } else if (2 == ctl->met_press_level_def) {
3356
3357 ERRMSG
3358 ("MET_PRESS_LEVEL_DEF=2 is disabled. Use 5 for the extended L60 set.");
3359
3360 } else if (3 == ctl->met_press_level_def) {
3361
3362 ctl->met_np = 147;
3363
3364 const double press[147] = {
3365 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
3366 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
3367 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
3368 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
3369 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
3370 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
3371 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
3372 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
3373 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
3374 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
3375 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
3376 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
3377 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
3378 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
3379 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
3380 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
3381 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
3382 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
3383 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
3384 1031.97,
3385 1035.09, 1038.21, 1041.33, 1044.45
3386 };
3387
3388 for (int ip = 0; ip < ctl->met_np; ip++)
3389 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3390
3391 } else if (4 == ctl->met_press_level_def) {
3392
3393 ctl->met_np = 101;
3394
3395 const double press[101] = {
3396 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
3397 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
3398 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
3399 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
3400 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
3401 113.6382,
3402 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
3403 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
3404 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
3405 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
3406 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
3407 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
3408 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
3409 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
3410 1028.85, 1031.97,
3411 1035.09, 1038.21, 1041.33, 1044.45
3412 };
3413
3414 for (int ip = 0; ip < ctl->met_np; ip++)
3415 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3416
3417 } else if (5 == ctl->met_press_level_def) {
3418
3419 ctl->met_np = 62;
3420
3421 const double press[62] = {
3422 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
3423 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
3424 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
3425 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
3426 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
3427 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
3428 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
3429 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
3430 1044.45
3431 };
3432
3433 for (int ip = 0; ip < ctl->met_np; ip++)
3434 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3435
3436 } else if (6 == ctl->met_press_level_def) {
3437
3438 ctl->met_np = 137;
3439
3440 const double press[137] = {
3441 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
3442 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
3443 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
3444 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
3445 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
3446 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
3447 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
3448 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
3449 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
3450 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
3451 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
3452 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
3453 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
3454 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
3455 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
3456 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
3457 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
3458 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
3459 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
3460 1030.06, 1037.25, 1044.45
3461 };
3462
3463 for (int ip = 0; ip < ctl->met_np; ip++)
3464 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3465
3466 } else if (7 == ctl->met_press_level_def) {
3467
3468 ctl->met_np = 59;
3469
3470 const double press[59] = {
3471 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
3472 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
3473 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
3474 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
3475 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
3476 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
3477 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
3478 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
3479 1028.53, 1046.13
3480 };
3481
3482 for (int ip = 0; ip < ctl->met_np; ip++)
3483 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3484
3485 } else {
3486 ERRMSG("Use values between 3 and 7.");
3487 }
3488
3489 if (ctl->met_np > EP)
3490 ERRMSG("Recompile with larger EP to use this pressure level definition!");
3491}
3492
3493/*****************************************************************************/
3494
3496 const double *xx,
3497 const int n,
3498 const double x) {
3499
3500 int ilo = 0;
3501 int ihi = n - 1;
3502 int i = (ihi + ilo) >> 1;
3503
3504 if (xx[i] < xx[i + 1])
3505 while (ihi > ilo + 1) {
3506 i = (ihi + ilo) >> 1;
3507 if (xx[i] > x)
3508 ihi = i;
3509 else
3510 ilo = i;
3511 } else
3512 while (ihi > ilo + 1) {
3513 i = (ihi + ilo) >> 1;
3514 if (xx[i] <= x)
3515 ihi = i;
3516 else
3517 ilo = i;
3518 }
3519
3520 return ilo;
3521}
3522
3523/*****************************************************************************/
3524
3526 const float *xx,
3527 const int n,
3528 const double x,
3529 const int ig) {
3530
3531 int ilo = 0;
3532 int ihi = n - 1;
3533 int i = (ihi + ilo) >> 1;
3534
3535 if ((xx[ig] <= x && x < xx[ig + 1]) || (xx[ig] >= x && x > xx[ig + 1]))
3536 return ig;
3537
3538 if (xx[i] < xx[i + 1])
3539 while (ihi > ilo + 1) {
3540 i = (ihi + ilo) >> 1;
3541 if (xx[i] > x)
3542 ihi = i;
3543 else
3544 ilo = i;
3545 } else
3546 while (ihi > ilo + 1) {
3547 i = (ihi + ilo) >> 1;
3548 if (xx[i] <= x)
3549 ihi = i;
3550 else
3551 ilo = i;
3552 }
3553
3554 return ilo;
3555}
3556
3557/*****************************************************************************/
3558
3560 const double *xx,
3561 const int n,
3562 const double x) {
3563
3564 /* Calculate index... */
3565 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
3566
3567 /* Check range... */
3568 if (i < 0)
3569 return 0;
3570 else if (i > n - 2)
3571 return n - 2;
3572 else
3573 return i;
3574}
3575
3576/*****************************************************************************/
3577
3579 float profiles[EX][EY][EP],
3580 const int np,
3581 const int lon_ap_ind,
3582 const int lat_ap_ind,
3583 const double height_ap,
3584 int *ind) {
3585
3586 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
3587 np, height_ap, 0);
3588 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
3589 np, height_ap, ind[0]);
3590 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
3591 np, height_ap, ind[1]);
3592 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
3593 np, height_ap, ind[2]);
3594}
3595
3596/*****************************************************************************/
3597
3599 const ctl_t *ctl,
3600 const cache_t *cache,
3601 met_t *met0,
3602 met_t *met1,
3603 atm_t *atm) {
3604
3605 /* Set timer... */
3606 SELECT_TIMER("MODULE_ADVECT", "PHYSICS");
3607
3608 /* Use omega vertical velocity... */
3609 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
3610
3611 /* Loop over particles... */
3612 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3613
3614 /* Init... */
3616 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
3617 x[3] = { 0, 0, 0 };
3618
3619 /* Loop over integration nodes... */
3620 for (int i = 0; i < ctl->advect; i++) {
3621
3622 /* Set position... */
3623 if (i == 0) {
3624 dts = 0.0;
3625 x[0] = atm->lon[ip];
3626 x[1] = atm->lat[ip];
3627 x[2] = atm->p[ip];
3628 } else {
3629 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3630 x[0] = atm->lon[ip] + DX2COORD(met0, dts * u[i - 1], atm->lat[ip]);
3631 x[1] = atm->lat[ip] + DY2COORD(met0, dts * v[i - 1]);
3632 x[2] = atm->p[ip] + dts * w[i - 1];
3633 }
3634 const double tm = atm->time[ip] + dts;
3635
3636 /* Interpolate meteo data on pressure levels... */
3637 if (ctl->advect_vert_coord == 0) {
3638 intpol_met_time_3d(met0, met0->u, met1, met1->u,
3639 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3640 intpol_met_time_3d(met0, met0->v, met1, met1->v,
3641 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3642 intpol_met_time_3d(met0, met0->w, met1, met1->w,
3643 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3644 }
3645
3646 /* Interpolate meteo data on model levels... */
3647 else {
3648 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
3649 met1, met1->pl, met1->ul,
3650 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3651 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
3652 met1, met1->pl, met1->vl,
3653 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3654 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
3655 met1, met1->pl, met1->wl,
3656 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3657 }
3658
3659 /* Get mean wind... */
3660 double k = 1.0;
3661 if (ctl->advect == 2)
3662 k = (i == 0 ? 0.0 : 1.0);
3663 else if (ctl->advect == 4)
3664 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3665 um += k * u[i];
3666 vm += k * v[i];
3667 wm += k * w[i];
3668 }
3669
3670 /* Set new position... */
3671 atm->time[ip] += cache->dt[ip];
3672 atm->lon[ip] += DX2COORD(met0, cache->dt[ip] * um,
3673 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3674 atm->lat[ip] += DY2COORD(met0, cache->dt[ip] * vm);
3675 atm->p[ip] += cache->dt[ip] * wm;
3676
3677 }
3678 }
3679
3680 /* Use zeta or eta vertical velocity... */
3681 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
3682
3683 /* Select quantity index depending on coordinate... */
3684 const int qnt = (ctl->advect_vert_coord == 1
3685 ? ctl->qnt_zeta : ctl->qnt_eta);
3686
3687 /* Loop over particles... */
3688 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3689
3690 /* Convert pressure to vertical coordinate (zeta or eta)... */
3692 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
3693 met1, met1->pl, met1->zetal,
3694 atm->time[ip], atm->p[ip],
3695 atm->lon[ip], atm->lat[ip],
3696 &atm->q[qnt][ip], ci, cw, 1);
3697
3698 /* Init... */
3699 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
3700 wdotm = 0, x[3] = { 0, 0, 0 };
3701
3702 /* Loop over integration nodes (Runge–Kutta steps)... */
3703 for (int i = 0; i < ctl->advect; i++) {
3704
3705 /* Set position... */
3706 if (i == 0) {
3707 dts = 0.0;
3708 x[0] = atm->lon[ip];
3709 x[1] = atm->lat[ip];
3710 x[2] = atm->q[qnt][ip];
3711 } else {
3712 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3713 x[0] = atm->lon[ip] + DX2COORD(met0, dts * u[i - 1], atm->lat[ip]);
3714 x[1] = atm->lat[ip] + DY2COORD(met0, dts * v[i - 1]);
3715 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
3716 }
3717
3718 const double tm = atm->time[ip] + dts;
3719
3720 /* Interpolate meteo data... */
3721 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
3722 met1, met1->zetal, met1->ul,
3723 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3724 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
3725 met1, met1->zetal, met1->vl,
3726 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3727 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
3728 met1, met1->zetal, met1->zeta_dotl,
3729 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
3730
3731 /* Compute Runge–Kutta weights... */
3732 double k = 1.0;
3733 if (ctl->advect == 2)
3734 k = (i == 0 ? 0.0 : 1.0);
3735 else if (ctl->advect == 4)
3736 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3737
3738 um += k * u[i];
3739 vm += k * v[i];
3740 wdotm += k * wdot[i];
3741 }
3742
3743 /* Update particle position... */
3744 atm->time[ip] += cache->dt[ip];
3745 atm->lon[ip] += DX2COORD(met0, cache->dt[ip] * um,
3746 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3747 atm->lat[ip] += DY2COORD(met0, cache->dt[ip] * vm);
3748 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
3749
3750 /* Convert vertical coordinate (zeta or eta) back to pressure... */
3751 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
3752 met1, met1->zetal, met1->pl,
3753 atm->time[ip],
3754 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
3755 &atm->p[ip], ci, cw, 1);
3756 }
3757 }
3758}
3759
3760/*****************************************************************************/
3761
3763 const ctl_t *ctl,
3764 const cache_t *cache,
3765 met_t *met0,
3766 met_t *met1,
3767 atm_t *atm) {
3768
3769 /* Check parameters... */
3770 if (ctl->advect_vert_coord != 1)
3771 return;
3772
3773 /* Set timer... */
3774 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS");
3775
3776 /* Loop over particles... */
3777 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
3778
3779 /* Initialize pressure consistent with zeta... */
3781 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
3782 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
3783 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
3784 }
3785}
3786
3787/*****************************************************************************/
3788
3790 const ctl_t *ctl,
3791 const cache_t *cache,
3792 const clim_t *clim,
3793 met_t *met0,
3794 met_t *met1,
3795 atm_t *atm) {
3796
3797 /* Set timer... */
3798 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS");
3799
3800 /* Check quantity flags... */
3801 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
3802 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
3803 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
3804 return;
3805
3806 /* Loop over particles... */
3807 PARTICLE_LOOP(0, atm->np, 1,
3808 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3809
3810 /* Check latitude and pressure range... */
3811 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
3812 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
3813 continue;
3814
3815 /* Check surface layer... */
3816 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
3817 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
3818
3819 /* Get surface pressure... */
3820 double ps;
3822 INTPOL_2D(ps, 1);
3823
3824 /* Check pressure... */
3825 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
3826 continue;
3827
3828 /* Check height... */
3829 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
3830 continue;
3831
3832 /* Check zeta range... */
3833 if (ctl->bound_zetas > 0) {
3834 double t;
3835 INTPOL_3D(t, 1);
3836 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
3837 continue;
3838 }
3839
3840 /* Check planetary boundary layer... */
3841 if (ctl->bound_pbl) {
3842 double pbl;
3843 INTPOL_2D(pbl, 0);
3844 if (atm->p[ip] < pbl)
3845 continue;
3846 }
3847 }
3848
3849 /* Set mass and volume mixing ratio... */
3850 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
3851 atm->q[ctl->qnt_m][ip] =
3852 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
3853 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
3854 atm->q[ctl->qnt_vmr][ip] =
3855 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
3856
3857 /* Set CFC-10 volume mixing ratio... */
3858 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
3859 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
3860
3861 /* Set CFC-11 volume mixing ratio... */
3862 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
3863 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
3864
3865 /* Set CFC-12 volume mixing ratio... */
3866 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
3867 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
3868
3869 /* Set N2O volume mixing ratio... */
3870 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
3871 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
3872
3873 /* Set SF6 volume mixing ratio... */
3874 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
3875 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
3876
3877 /* Set age of air... */
3878 if (ctl->qnt_aoa >= 0)
3879 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
3880 }
3881}
3882
3883/*****************************************************************************/
3884
3886 const ctl_t *ctl,
3887 met_t *met0,
3888 met_t *met1,
3889 atm_t *atm,
3890 const double tt) {
3891
3892 if (met0->coord_type != 0)
3893 ERRMSG("Only lat/lon grid supported");
3894
3895 /* Check quantities... */
3896 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
3897 return;
3898 if (ctl->molmass <= 0)
3899 ERRMSG("Molar mass is not defined!");
3900
3901 /* Set timer... */
3902 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS");
3903
3904 /* Allocate... */
3905 const int ensemble_mode = (ctl->nens > 0);
3906 const int np = atm->np;
3907 const int nz = ctl->chemgrid_nz;
3908 const int nx = ctl->chemgrid_nx;
3909 const int ny = ctl->chemgrid_ny;
3910 const int ngrid = nx * ny * nz;
3911 const int nens = ensemble_mode ? ctl->nens : 1;
3912
3913 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
3914 double *restrict const press =
3915 (double *) malloc((size_t) nz * sizeof(double));
3916 double *restrict const mass =
3917 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
3918 double *restrict const area =
3919 (double *) malloc((size_t) ny * sizeof(double));
3920 double *restrict const lon =
3921 (double *) malloc((size_t) nx * sizeof(double));
3922 double *restrict const lat =
3923 (double *) malloc((size_t) ny * sizeof(double));
3924
3925 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3926 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3927 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3928
3929 /* Set grid box size... */
3930 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
3931 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
3932 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
3933
3934 /* Set vertical coordinates... */
3935#ifdef _OPENACC
3936#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])
3937#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
3938#pragma acc parallel loop independent gang vector
3939#else
3940#pragma omp parallel for default(shared)
3941#endif
3942 for (int iz = 0; iz < nz; iz++) {
3943 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
3944 press[iz] = P(z[iz]);
3945 }
3946
3947 /* Set time interval for output... */
3948 const double t0 = tt - 0.5 * ctl->dt_mod;
3949 const double t1 = tt + 0.5 * ctl->dt_mod;
3950
3951 /* Get indices... */
3952#ifdef _OPENACC
3953#pragma acc parallel loop independent gang vector
3954#else
3955#pragma omp parallel for default(shared)
3956#endif
3957 for (int ip = 0; ip < np; ip++) {
3958 const double zpart = Z(atm->p[ip]);
3959 if (atm->time[ip] < t0 || atm->time[ip] > t1
3960 || atm->lon[ip] < ctl->chemgrid_lon0
3961 || atm->lon[ip] >= ctl->chemgrid_lon1
3962 || atm->lat[ip] < ctl->chemgrid_lat0
3963 || atm->lat[ip] >= ctl->chemgrid_lat1
3964 || zpart < ctl->chemgrid_z0 || zpart >= ctl->chemgrid_z1) {
3965 izs[ip] = -1;
3966 continue;
3967 }
3968 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
3969 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
3970 izs[ip] = (int) ((zpart - ctl->chemgrid_z0) / dz);
3971 if (ixs[ip] >= nx || iys[ip] >= ny || izs[ip] >= nz)
3972 izs[ip] = -1;
3973 }
3974
3975 /* Set horizontal coordinates... */
3976#ifdef _OPENACC
3977#pragma acc parallel loop independent gang vector
3978#else
3979#pragma omp parallel for default(shared)
3980#endif
3981 for (int ix = 0; ix < nx; ix++)
3982 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3983
3984#ifdef _OPENACC
3985#pragma acc parallel loop independent gang vector
3986#else
3987#pragma omp parallel for default(shared)
3988#endif
3989 for (int iy = 0; iy < ny; iy++) {
3990 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3991 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3992 }
3993
3994 /* Get mass per grid box... */
3995#ifdef _OPENACC
3996#pragma acc parallel loop independent gang vector
3997#endif
3998 for (int ip = 0; ip < np; ip++) {
3999 if (izs[ip] >= 0) {
4000 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
4001 if (ensemble_mode) {
4002 const int ens = (int) atm->q[ctl->qnt_ens][ip];
4003 mass_idx += ens * ngrid;
4004 }
4005#ifdef _OPENACC
4006#pragma acc atomic update
4007#endif
4008 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
4009 }
4010 }
4011
4012 /* Assign grid data to air parcels ... */
4013#ifdef _OPENACC
4014#pragma acc parallel loop independent gang vector
4015#else
4016#pragma omp parallel for default(shared)
4017#endif
4018 for (int ip = 0; ip < np; ip++)
4019 if (izs[ip] >= 0) {
4020
4021 /* Interpolate temperature... */
4022 double temp;
4024 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
4025 press[izs[ip]],
4026 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
4027
4028 /* Set mass... */
4029 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
4030 if (ensemble_mode) {
4031 const int ens = (int) atm->q[ctl->qnt_ens][ip];
4032 mass_idx += ens * ngrid;
4033 }
4034
4035 /* Calculate volume mixing ratio... */
4036 const double m = mass[mass_idx];
4037 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
4038 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
4039 }
4040
4041 /* Free... */
4042#ifdef _OPENACC
4043#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
4044#endif
4045 free(mass);
4046 free(lon);
4047 free(lat);
4048 free(area);
4049 free(z);
4050 free(press);
4051 free(ixs);
4052 free(iys);
4053 free(izs);
4054}
4055
4056/*****************************************************************************/
4057
4059 const ctl_t *ctl,
4060 const cache_t *cache,
4061 const clim_t *clim,
4062 met_t *met0,
4063 met_t *met1,
4064 atm_t *atm) {
4065
4066 /* Set timer... */
4067 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS");
4068
4069 /* Loop over particles... */
4070 PARTICLE_LOOP(0, atm->np, 0,
4071 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4072
4073 /* Set H2O and O3 using meteo data... */
4075 if (ctl->qnt_Ch2o >= 0) {
4076 double h2o;
4077 INTPOL_3D(h2o, 1);
4078 SET_ATM(qnt_Ch2o, h2o);
4079 }
4080 if (ctl->qnt_Co3 >= 0) {
4081 double o3;
4082 INTPOL_3D(o3, 1);
4083 SET_ATM(qnt_Co3, o3);
4084 }
4085
4086 /* Set radical species... */
4087 const double lat_ref =
4088 ctl->met_coord_type == 0 ? atm->lat[ip] : ctl->met_utm_ref_lat;
4089 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
4090 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4091 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
4092 lat_ref, atm->p[ip]));
4093 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
4094 lat_ref, atm->p[ip]));
4095 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
4096 lat_ref, atm->p[ip]));
4097 }
4098}
4099
4100/*****************************************************************************/
4101
4103 const ctl_t *ctl,
4104 cache_t *cache,
4105 met_t *met0,
4106 met_t *met1,
4107 atm_t *atm) {
4108
4109 /* Set timer... */
4110 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS");
4111
4112 /* Create random numbers... */
4113 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
4114
4115 /* Loop over particles... */
4116 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4117
4118 /* Interpolate surface pressure... */
4119 double ps;
4121 INTPOL_2D(ps, 1);
4122
4123 /* Initialize pressure range for vertical mixing... */
4124 double pbot = ps, ptop = ps;
4125
4126 /* Mixing in the PBL... */
4127 if (ctl->conv_mix_pbl) {
4128
4129 /* Interpolate PBL... */
4130 double pbl;
4131 INTPOL_2D(pbl, 0);
4132
4133 /* Set pressure range... */
4134 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
4135 }
4136
4137 /* Convective mixing... */
4138 if (ctl->conv_cape >= 0) {
4139
4140 /* Interpolate CAPE, CIN, and equilibrium level... */
4141 double cape, cin, pel;
4142 INTPOL_2D(cape, 0);
4143 INTPOL_2D(cin, 0);
4144 INTPOL_2D(pel, 0);
4145
4146 /* Set pressure range... */
4147 if (isfinite(cape) && cape >= ctl->conv_cape
4148 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
4149 ptop = GSL_MIN(ptop, pel);
4150 }
4151
4152 /* Apply vertical mixing... */
4153 if (ptop != pbot && atm->p[ip] >= ptop) {
4154
4155 /* Get density range... */
4156 double tbot, ttop;
4157 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
4158 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
4159 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
4160 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
4161 const double rhobot = pbot / tbot;
4162 const double rhotop = ptop / ttop;
4163
4164 /* Get new density... */
4165 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
4166
4167 /* Get pressure... */
4168 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
4169 }
4170 }
4171}
4172
4173/*****************************************************************************/
4174
4175#ifdef DD
4176void module_dd(
4177 double t,
4178 const ctl_t *ctl,
4179 cache_t *cache,
4180 dd_t *dd,
4181 atm_t *atm,
4182 met_t **met) {
4183
4184 /* Initialize particles locally... */
4185 int npart = 0, capacity = 0;
4186 particle_t *particles = NULL;
4187
4188 /* Assign particles to new subdomains... */
4189 dd_assign_subdomains(ctl, dd, atm, 0);
4190
4191 /* Sort particles according to location and target rank... */
4192 if (fmod(t, ctl->dd_sort_dt) == 0)
4193 dd_sort(ctl, *met, atm, dd, &npart);
4194 else
4195 dd_push(ctl, atm, cache, &npart);
4196
4197 /* Ensure particle buffer is large enough for outgoing particles... */
4198 if (npart > capacity) {
4199 const int newcap = npart + npart / 2 + 1;
4200 particle_t *tmp =
4201 realloc(particles, (size_t) newcap * sizeof(particle_t));
4202 if (!tmp)
4203 ERRMSG("Out of memory!");
4204 particles = tmp;
4205 capacity = newcap;
4206 }
4207
4208 /* Transform from struct of array to array of struct... */
4209 dd_atm2particles(ctl, cache, atm, particles, npart);
4210
4211 SELECT_TIMER("SYNC", "DD");
4212 MPI_Barrier(MPI_COMM_WORLD);
4213
4214 /* Perform the communication... */
4215 dd_communicate_particles(ctl, dd, &particles, &npart, &capacity);
4216
4217 /* Transform from array of struct to struct of array... */
4218 dd_particles2atm(ctl, cache, particles, npart, atm);
4219
4220 /* Free local particle array... */
4221 free(particles);
4222}
4223#endif
4224
4225/*****************************************************************************/
4226
4228 const ctl_t *ctl,
4229 const cache_t *cache,
4230 const clim_t *clim,
4231 atm_t *atm) {
4232
4233 /* Set timer... */
4234 SELECT_TIMER("MODULE_DECAY", "PHYSICS");
4235
4236 /* Check quantity flags... */
4237 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4238 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4239
4240 /* Loop over particles... */
4241 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
4242
4243 /* Get weighting factor... */
4244 const double w = tropo_weight(ctl, clim, atm, ip);
4245
4246 /* Set lifetime... */
4247 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
4248
4249 /* Calculate exponential decay... */
4250 const double aux = exp(-cache->dt[ip] / tdec);
4251 if (ctl->qnt_m >= 0) {
4252 if (ctl->qnt_mloss_decay >= 0)
4253 atm->q[ctl->qnt_mloss_decay][ip]
4254 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4255 atm->q[ctl->qnt_m][ip] *= aux;
4256 if (ctl->qnt_loss_rate >= 0)
4257 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
4258 }
4259 if (ctl->qnt_vmr >= 0)
4260 atm->q[ctl->qnt_vmr][ip] *= aux;
4261 }
4262}
4263
4264/*****************************************************************************/
4265
4267 const ctl_t *ctl,
4268 cache_t *cache,
4269 met_t *met0,
4270 met_t *met1,
4271 atm_t *atm) {
4272
4273 /* Set timer... */
4274 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS");
4275
4276 /* Create random numbers... */
4277 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4278
4279 /* Loop over particles... */
4280 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4281
4282 /* Get indices... */
4283 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
4284 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
4285 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
4286
4287 /* Get standard deviations of local wind data... */
4288 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
4289 for (int i = 0; i < 2; i++)
4290 for (int j = 0; j < 2; j++)
4291 for (int k = 0; k < 2; k++) {
4292 umean += met0->u[ix + i][iy + j][iz + k];
4293 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
4294 vmean += met0->v[ix + i][iy + j][iz + k];
4295 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
4296 wmean += met0->w[ix + i][iy + j][iz + k];
4297 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
4298
4299 umean += met1->u[ix + i][iy + j][iz + k];
4300 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
4301 vmean += met1->v[ix + i][iy + j][iz + k];
4302 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
4303 wmean += met1->w[ix + i][iy + j][iz + k];
4304 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
4305 }
4306 usig = usig / 16.f - SQR(umean / 16.f);
4307 usig = (usig > 0 ? sqrtf(usig) : 0);
4308 vsig = vsig / 16.f - SQR(vmean / 16.f);
4309 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
4310 wsig = wsig / 16.f - SQR(wmean / 16.f);
4311 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
4312
4313 /* Set temporal correlations for mesoscale fluctuations... */
4314 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
4315 const double r2 = sqrt(1 - r * r);
4316
4317 /* Calculate horizontal mesoscale wind fluctuations... */
4318 if (ctl->turb_mesox > 0) {
4319 cache->uvwp[ip][0] =
4320 (float) (r * cache->uvwp[ip][0] +
4321 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
4322 atm->lon[ip] +=
4323 DX2COORD(met0, cache->uvwp[ip][0] * cache->dt[ip], atm->lat[ip]);
4324
4325 cache->uvwp[ip][1] =
4326 (float) (r * cache->uvwp[ip][1] +
4327 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
4328 atm->lat[ip] += DY2COORD(met0, cache->uvwp[ip][1] * cache->dt[ip]);
4329 }
4330
4331 /* Calculate vertical mesoscale wind fluctuations... */
4332 if (ctl->turb_mesoz > 0) {
4333 cache->uvwp[ip][2] =
4334 (float) (r * cache->uvwp[ip][2] +
4335 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
4336 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
4337 }
4338 }
4339}
4340
4341/*****************************************************************************/
4342
4344 const ctl_t *ctl,
4345 cache_t *cache,
4346 met_t *met0,
4347 met_t *met1,
4348 atm_t *atm) {
4349
4350 /* Set timer... */
4351 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS");
4352
4353 /* Create random numbers... */
4354 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4355
4356 /* Loop over particles... */
4357 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4358
4359 double pbl, ps, dsigw_dz = 0.0, sig_u = 0.0, sig_v = 0.0, sig_w = 0.0;
4360 double tau_u = 0.0, tau_v = 0.0, tau_w = 0.0;
4361
4362 /* Get PBL pressure... */
4364 INTPOL_2D(pbl, 1);
4365
4366 /* Let the background diffusion scheme handle particles above the PBL. */
4367 if (atm->p[ip] < pbl)
4368 continue;
4369
4370 /* Get surface pressure... */
4371 INTPOL_2D(ps, 0);
4372
4373 /* Skip invalid or vanishing PBL layers. */
4374 if (!(ps > 0.0 && pbl > 0.0 && ps > pbl))
4375 continue;
4376
4377 /* Calculate heights [m] above ground.
4378 Z() returns altitude in km, so multiply differences by 1e3. */
4379 const double p = MIN(atm->p[ip], ps);
4380 const double zs = Z(ps);
4381 const double z_raw = 1e3 * (Z(p) - zs);
4382 const double zi = 1e3 * (Z(pbl) - zs);
4383
4384 /* Require a physically meaningful PBL depth. */
4385 if (!(zi > 1.0))
4386 continue;
4387
4388 /* Clamp height to the PBL interval for closure evaluation. */
4389 const double z = CLAMP(z_raw, 0.0, zi);
4390 const double zeta = CLAMP(z / zi, 1e-6, 1.0 - 1e-6);
4391 const double z_m = MAX(z, 1.0);
4392
4393 /* Temporarily use clamped pressure for thermodynamic interpolation.
4394 This avoids inconsistent interpolation if a particle has slipped
4395 below the surface pressure. */
4396 const double p_save = atm->p[ip];
4397 atm->p[ip] = p;
4398
4399 /* Calculate friction velocity... */
4400 double ess, nss, h2o, t;
4401 INTPOL_2D(ess, 0);
4402 INTPOL_2D(nss, 0);
4403 INTPOL_3D(t, 1);
4404 INTPOL_3D(h2o, 0);
4405
4406 /* Restore particle pressure before any continue/update path. */
4407 atm->p[ip] = p_save;
4408
4409 const double tv = TVIRT(t, h2o);
4410 const double thetav = THETAVIRT(p, t, h2o);
4411 const double rho = RHO(p, tv);
4412 const double tau = sqrt(SQR(ess) + SQR(nss));
4413
4414 if (!(rho > 0.0))
4415 continue;
4416
4417 const double ustar = sqrt(MAX(tau / rho, 0.0));
4418 const double ust = MAX(1e-4, ustar);
4419
4420 /* Get surface sensible heat flux.
4421 Sign convention assumed here: unstable surface heating gives shf < 0,
4422 as in the existing implementation. */
4423 double shf;
4424 INTPOL_2D(shf, 1);
4425
4426 /* Estimate Monin-Obukhov length [m] to distinguish
4427 neutral, stable, and unstable cases. */
4428 double ol = 1e12;
4429 if (fabs(shf) > 1e-6)
4430 ol = thetav * rho * CPD * SQR(ust) * ust / (KARMAN * G0 * shf);
4431
4432 /* Neutral conditions... */
4433 if (zi / fabs(ol) < 1.0) {
4434
4435 /* corr has units of seconds, hence the exponential coefficients
4436 have units of s^-1. The derivative d(sig_w)/dz therefore needs
4437 the extra factor 1/ust. */
4438 const double corr = z_m / ust;
4439 const double sigw0 = 1.3 * ust * exp(-2e-4 * corr);
4440
4441 sig_u = MAX(2.0 * ust * exp(-3e-4 * corr), 1e-5);
4442 sig_v = MAX(sigw0, 1e-5);
4443 sig_w = MAX(sigw0, 1e-5);
4444 dsigw_dz = -2e-4 * sigw0 / ust;
4445
4446 tau_u = 0.5 * z_m / sig_w / (1.0 + 1.5e-3 * corr);
4447 tau_v = tau_u;
4448 tau_w = tau_u;
4449 }
4450
4451 /* Unstable conditions... */
4452 else if (ol < 0.0) {
4453
4454 /* Convective velocity scale [m/s]. */
4455 const double wstar_arg = -G0 / thetav * shf / (rho * CPD) * zi;
4456 const double wstar = pow(MAX(wstar_arg, 0.0), 1.0 / 3.0);
4457 double dsigw2_dz = 0.0;
4458
4459 /* Hanna1/FLEXPART turbulent velocity standard deviations [m/s]. */
4460 sig_u = MAX(ust * pow(MAX(12.0 - 0.5 * zi / ol, 0.0), 1.0 / 3.0), 1e-6);
4461 sig_v = sig_u;
4462
4463 if (zeta < 0.03) {
4464 const double arg = MAX(3.0 * zeta - ol / zi, 1e-12);
4465 sig_w = 0.96 * wstar * pow(arg, 1.0 / 3.0);
4466 dsigw2_dz = 1.8432 * SQR(wstar) / zi * pow(arg, -1.0 / 3.0);
4467 } else if (zeta < 0.4) {
4468 const double arg = MAX(3.0 * zeta - ol / zi, 1e-12);
4469 const double s1 = 0.96 * pow(arg, 1.0 / 3.0);
4470 const double s2 = 0.763 * pow(zeta, 0.175);
4471 if (s1 < s2) {
4472 sig_w = wstar * s1;
4473 dsigw2_dz = 1.8432 * SQR(wstar) / zi * pow(arg, -1.0 / 3.0);
4474 } else {
4475 sig_w = wstar * s2;
4476 dsigw2_dz = 0.203759 * SQR(wstar) / zi * pow(zeta, -0.65);
4477 }
4478 } else if (zeta < 0.96) {
4479 sig_w = 0.722 * wstar * pow(1.0 - zeta, 0.207);
4480 dsigw2_dz = -0.215812 * SQR(wstar) / zi * pow(1.0 - zeta, -0.586);
4481 } else {
4482 sig_w = 0.37 * wstar;
4483 dsigw2_dz = 0.0;
4484 }
4485
4486 sig_w = MAX(sig_w, 1e-6);
4487 dsigw_dz = sig_w > 1e-12 ? 0.5 * dsigw2_dz / sig_w : 0.0;
4488
4489 /* Hanna/FLEXPART Lagrangian timescales [s]. */
4490 tau_u = 0.15 * zi / MAX(sig_u, 1e-12);
4491 tau_v = tau_u;
4492
4493 if (z_m < fabs(ol)) {
4494 const double denom = 0.55 - 0.38 * fabs(z_m / ol);
4495 tau_w = 0.1 * z_m / (sig_w * MAX(denom, 0.05));
4496 } else if (zeta < 0.1)
4497 tau_w = 0.59 * z_m / sig_w;
4498 else
4499 tau_w = 0.15 * zi / sig_w * (1.0 - exp(-5.0 * zeta));
4500 }
4501
4502 /* Stable conditions... */
4503 else {
4504
4505 sig_u = MAX(2.0 * ust * (1.0 - zeta), 1e-6);
4506 sig_v = MAX(1.3 * ust * (1.0 - zeta), 1e-6);
4507 sig_w = MAX(1.3 * ust * (1.0 - zeta), 1e-6);
4508 dsigw_dz = -1.3 * ust / zi;
4509
4510 tau_u = 0.15 * zi / sig_u * sqrt(zeta);
4511 tau_v = 0.467 * tau_u;
4512 tau_w = 0.1 * zi / sig_w * pow(zeta, 0.8);
4513 }
4514
4515 /* Apply FLEXPART-consistent lower bounds for timescales. */
4516 tau_u = MAX(tau_u, 10.0);
4517 tau_v = MAX(tau_v, 10.0);
4518 tau_w = MAX(tau_w, 30.0);
4519
4520 /* Skip pathological states. */
4521 if (!(sig_u > 0.0 && sig_v > 0.0
4522 && sig_w > 0.0 && tau_u > 0.0 && tau_v > 0.0 && tau_w > 0.0))
4523 continue;
4524
4525 /* Update horizontal perturbation [m/s]. */
4526 const double dt = cache->dt[ip];
4527 const double dt_abs = fabs(dt);
4528
4529 const double ru = exp(-dt_abs / tau_u);
4530 const double ru2 = sqrt(MAX(0.0, 1.0 - SQR(ru)));
4531 const double rv = exp(-dt_abs / tau_v);
4532 const double rv2 = sqrt(MAX(0.0, 1.0 - SQR(rv)));
4533
4534 cache->uvwp[ip][0]
4535 = (float) (cache->uvwp[ip][0] * ru + sig_u * ru2 * cache->rs[3 * ip]);
4536
4537 cache->uvwp[ip][1]
4538 = (float) (cache->uvwp[ip][1] * rv
4539 + sig_v * rv2 * cache->rs[3 * ip + 1]);
4540
4541 /* Update vertical perturbation [m/s].
4542 The drift term is d(sig_w^2)/dz + sig_w^2/rho * d(rho)/dz.
4543 With exponential scale height H0 [km], dln(rho)/dz ~= -1/(1000 H0). */
4544 const double rw = exp(-dt_abs / tau_w);
4545 const double rw2 = sqrt(MAX(0.0, 1.0 - SQR(rw)));
4546 const double rhoaux = -1.0 / (1e3 * H0);
4547
4548 cache->uvwp[ip][2]
4549 = (float) (cache->uvwp[ip][2] * rw + sig_w * rw2 * cache->rs[3 * ip + 2]
4550 + tau_w * (1.0 - rw)
4551 * (2.0 * sig_w * dsigw_dz + rhoaux * SQR(sig_w)));
4552
4553 /* Calculate new horizontal air parcel position. */
4554 atm->lon[ip] += DX2COORD(met0, cache->uvwp[ip][0] * dt, atm->lat[ip]);
4555 atm->lat[ip] += DY2COORD(met0, cache->uvwp[ip][1] * dt);
4556
4557 /* Calculate new height and reflect robustly at surface and PBL top.
4558 Each boundary reflection reverses the vertical turbulent velocity.
4559 This loop is intentionally simple and explicit: it remains correct
4560 even if a large step crosses multiple boundaries. */
4561 double znew = z + cache->uvwp[ip][2] * dt;
4562
4563 while (znew < 0.0 || znew > zi) {
4564
4565 if (znew < 0.0) {
4566 znew = -znew;
4567 cache->uvwp[ip][2] = -cache->uvwp[ip][2];
4568 }
4569
4570 if (znew > zi) {
4571 znew = 2.0 * zi - znew;
4572 cache->uvwp[ip][2] = -cache->uvwp[ip][2];
4573 }
4574 }
4575
4576 /* Set pressure from reflected geometric height.
4577 This is more consistent than a linearized DZ2DP update for
4578 potentially large turbulent steps. */
4579 atm->p[ip] = P(zs + znew / 1000.0);
4580
4581 /* Enforce exact pressure limits of the local PBL column. */
4582 atm->p[ip] = CLAMP(atm->p[ip], pbl, ps);
4583 }
4584}
4585
4586/*****************************************************************************/
4587
4589 const ctl_t *ctl,
4590 cache_t *cache,
4591 const clim_t *clim,
4592 met_t *met0,
4593 met_t *met1,
4594 atm_t *atm) {
4595
4596 /* Set timer... */
4597 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS");
4598
4599 /* Create random numbers... */
4600 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4601
4602 /* Loop over particles... */
4603 PARTICLE_LOOP(0, atm->np, 1,
4604 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4605
4606 /* Get PBL pressure... */
4607 double pbl;
4609 INTPOL_2D(pbl, 1);
4610
4611 /* Let optional PBL closure schemes handle turbulent diffusion inside the PBL. */
4612 if (ctl->turb_pbl_scheme > 0 && atm->p[ip] >= pbl)
4613 continue;
4614
4615 /* Get surface pressure... */
4616 double ps;
4617 INTPOL_2D(ps, 0);
4618
4619 /* Pressure at model top [hPa]. */
4620 const double ptop = met0->p[met0->np - 1];
4621
4622 /* Get weighting factors at current particle position... */
4623 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
4624 const double wtrop = tropo_weight(ctl, clim, atm, ip) * (1.0 - wpbl);
4625 const double wstrat = 1.0 - wpbl - wtrop;
4626
4627 /* Set diffusivities [m2/s]... */
4628 const double Kx =
4629 wpbl * ctl->turb_dx_pbl
4630 + wtrop * ctl->turb_dx_trop + wstrat * ctl->turb_dx_strat;
4631
4632 const double Kz =
4633 wpbl * ctl->turb_dz_pbl
4634 + wtrop * ctl->turb_dz_trop + wstrat * ctl->turb_dz_strat;
4635
4636 /* Set time step... */
4637 const double dt_abs = fabs(cache->dt[ip]);
4638
4639 /* Horizontal turbulent diffusion...
4640 Kx [m2/s], dt [s] => sigma_h [m]. */
4641 if (Kx > 0) {
4642 const double sigma_h = sqrt(2.0 * Kx * dt_abs);
4643
4644 atm->lon[ip] +=
4645 DX2COORD(met0, cache->rs[3 * ip] * sigma_h, atm->lat[ip]);
4646
4647 atm->lat[ip] += DY2COORD(met0, cache->rs[3 * ip + 1] * sigma_h);
4648 }
4649
4650 /* Vertical turbulent diffusion... */
4651 if (Kz > 0) {
4652
4653 /* Random displacement:
4654 Kz [m2/s], dt [s] => sigma_z [m], converted to [km]. */
4655 const double sigma_z = sqrt(2.0 * Kz * dt_abs) * 1e-3;
4656
4657 /* Save current pressure because pbl_weight() and tropo_weight()
4658 use atm->p[ip]. */
4659 const double p_save = atm->p[ip];
4660
4661 /* Estimate dKz/dz by centered finite difference.
4662 eps_km = 0.01 km = 10 m.
4663 Positive z is upward; therefore p_up < p_save and p_dn > p_save. */
4664 const double eps_km = 0.01;
4665 const double p_up = p_save + DZ2DP(eps_km, p_save);
4666 const double p_dn = p_save + DZ2DP(-eps_km, p_save);
4667
4668 /* Kz above... */
4669 atm->p[ip] = MAX(ptop, MIN(ps, p_up));
4670 const double wpbl_up = pbl_weight(ctl, atm, ip, pbl, ps);
4671 const double wtrop_up =
4672 tropo_weight(ctl, clim, atm, ip) * (1.0 - wpbl_up);
4673 const double wstrat_up = 1.0 - wpbl_up - wtrop_up;
4674
4675 const double Kz_up =
4676 wpbl_up * ctl->turb_dz_pbl
4677 + wtrop_up * ctl->turb_dz_trop + wstrat_up * ctl->turb_dz_strat;
4678
4679 /* Kz below... */
4680 atm->p[ip] = MAX(ptop, MIN(ps, p_dn));
4681 const double wpbl_dn = pbl_weight(ctl, atm, ip, pbl, ps);
4682 const double wtrop_dn =
4683 tropo_weight(ctl, clim, atm, ip) * (1.0 - wpbl_dn);
4684 const double wstrat_dn = 1.0 - wpbl_dn - wtrop_dn;
4685
4686 const double Kz_dn =
4687 wpbl_dn * ctl->turb_dz_pbl
4688 + wtrop_dn * ctl->turb_dz_trop + wstrat_dn * ctl->turb_dz_strat;
4689
4690 /* Restore current pressure... */
4691 atm->p[ip] = p_save;
4692
4693 /* Well-mixed drift:
4694 w_drift = dKz/dz + Kz * dlnrho/dz
4695
4696 Units:
4697 dKz_dz [m2/s] / [m] = [m/s]
4698 dlnrho_dz [1/m]
4699 Kz*dlnrho [m2/s] * [1/m] = [m/s]
4700 dz_drift [m/s] * [s] * 1e-3 = [km]
4701
4702 With exponential atmosphere rho ~ exp(-z/H0):
4703 dlnrho/dz = -1 / (1000 * H0)
4704 because H0 is in [km]. */
4705 const double dKz_dz = (Kz_up - Kz_dn) / (2.0 * eps_km * 1e3);
4706 const double dlnrho_dz = -1.0 / (1e3 * H0);
4707 const double w_drift = dKz_dz + Kz * dlnrho_dz;
4708 const double dz_drift = w_drift * dt_abs * 1e-3;
4709
4710 /* Total vertical displacement [km]. */
4711 const double dz_tot = cache->rs[3 * ip + 2] * sigma_z + dz_drift;
4712
4713 /* Update particle pressure... */
4714 double ptrial = p_save + DZ2DP(dz_tot, p_save);
4715
4716 /* Reflect at surface and model top.
4717 The transformation p -> pb^2 / p corresponds to reflection in
4718 logarithmic pressure / approximate height coordinates. Use repeated
4719 reflection for robustness in case a large random step crosses more
4720 than one boundary. */
4721 for (int iter = 0; iter < 10; iter++) {
4722 if (ptrial > ps)
4723 ptrial = ps * ps / ptrial;
4724 else if (ptrial < ptop)
4725 ptrial = ptop * ptop / ptrial;
4726 else
4727 break;
4728 }
4729
4730 /* Final safety clamp in case of an exceptionally large displacement... */
4731 atm->p[ip] = MAX(ptop, MIN(ps, ptrial));
4732 }
4733 }
4734}
4735
4736/*****************************************************************************/
4737
4739 const ctl_t *ctl,
4740 const cache_t *cache,
4741 met_t *met0,
4742 met_t *met1,
4743 atm_t *atm) {
4744
4745 /* Set timer... */
4746 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS");
4747
4748 /* Check quantity flags... */
4749 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4750 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4751
4752 /* Loop over particles... */
4753 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4754
4755 /* Get surface pressure... */
4756 double ps;
4758 INTPOL_2D(ps, 1);
4759
4760 /* Check whether particle is above the surface layer... */
4761 if (atm->p[ip] < ps - ctl->dry_depo_dp)
4762 continue;
4763
4764 /* Set depth of surface layer... */
4765 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
4766
4767 /* Calculate sedimentation velocity for particles... */
4768 double v_dep;
4769 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
4770
4771 /* Get temperature... */
4772 double t;
4773 INTPOL_3D(t, 1);
4774
4775 /* Set deposition velocity... */
4776 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4777 atm->q[ctl->qnt_rhop][ip]);
4778 }
4779
4780 /* Use explicit sedimentation velocity for gases... */
4781 else
4782 v_dep = ctl->dry_depo_vdep;
4783
4784 /* Calculate loss of mass based on deposition velocity... */
4785 const double aux = exp(-cache->dt[ip] * v_dep / dz);
4786 if (ctl->qnt_m >= 0) {
4787 if (ctl->qnt_mloss_dry >= 0)
4788 atm->q[ctl->qnt_mloss_dry][ip]
4789 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4790 atm->q[ctl->qnt_m][ip] *= aux;
4791 if (ctl->qnt_loss_rate >= 0)
4792 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
4793 }
4794 if (ctl->qnt_vmr >= 0)
4795 atm->q[ctl->qnt_vmr][ip] *= aux;
4796 }
4797}
4798
4799/*****************************************************************************/
4800
4802 const ctl_t *ctl,
4803 const cache_t *cache,
4804 const clim_t *clim,
4805 met_t *met0,
4806 met_t *met1,
4807 atm_t *atm) {
4808
4809 if (ctl->met_coord_type != 0)
4810 ERRMSG("Only lat/lon grid supported");
4811
4812 /* Set timer... */
4813 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS");
4814
4815 /* Check quantity flags... */
4816 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4817 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4818
4819 /* Parameter of SO2 correction... */
4820 const double low = pow(1. / SO2_CORR_A, 1. / SO2_CORR_B);
4821
4822 /* Loop over particles... */
4823 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4824
4825 /* Check whether particle is inside cloud... */
4826 double lwc, rwc;
4828 INTPOL_3D(lwc, 1);
4829 INTPOL_3D(rwc, 0);
4830 if (!(lwc > 0 || rwc > 0))
4831 continue;
4832
4833 /* Get temperature... */
4834 double t;
4835 INTPOL_3D(t, 0);
4836
4837 /* Get molecular density... */
4838 const double M = MOLEC_DENS(atm->p[ip], t);
4839
4840 /* Reaction rate (Berglen et al., 2004)... */
4841 const double k = H2O2_SO2_RATE_REF * exp(-H2O2_SO2_RATE_TEMP / RI * (1. / t - 1. / CHEM_REF_TEMP)); /* Maass (1999), M^(-2) */
4842
4843 /* Henry constant of SO2... */
4844 const double H_SO2 =
4846 * (1. / t - 1. / CHEM_REF_TEMP)) * RI * t;
4847 const double K_1S = SO2_DISS_K1_REF * exp(SO2_DISS_K1_TEMP * (1. / t - 1. / CHEM_REF_TEMP)); /* unit: mol/L */
4848
4849 /* Henry constant of H2O2... */
4850 const double H_h2o2 =
4852 * (1. / t - 1. / CHEM_REF_TEMP)) * RI * t;
4853
4854 /* Correction factor for high SO2 concentration
4855 (if qnt_Cx is defined, the correction is switched on)... */
4856 double cor = 1.0;
4857 if (ctl->qnt_Cx >= 0)
4858 cor = atm->q[ctl->qnt_Cx][ip] >
4859 low ? SO2_CORR_A * pow(atm->q[ctl->qnt_Cx][ip], SO2_CORR_B) : 1;
4860
4861 const double h2o2 = H_h2o2
4862 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
4863 * M * cor * 1000. / AVO; /* unit: mol/L */
4864
4865 /* Volume water content in cloud [m^3 m^(-3)]... */
4866 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
4867 const double CWC = (lwc + rwc) * rho_air / 1e3;
4868
4869 /* Calculate exponential decay (Rolph et al., 1992)... */
4870 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
4871 const double aux = exp(-cache->dt[ip] * rate_coef);
4872 if (ctl->qnt_m >= 0) {
4873 if (ctl->qnt_mloss_h2o2 >= 0)
4874 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
4875 atm->q[ctl->qnt_m][ip] *= aux;
4876 if (ctl->qnt_loss_rate >= 0)
4877 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4878 }
4879 if (ctl->qnt_vmr >= 0)
4880 atm->q[ctl->qnt_vmr][ip] *= aux;
4881 }
4882}
4883
4884/*****************************************************************************/
4885
4887 const ctl_t *ctl,
4888 cache_t *cache,
4889 met_t *met0,
4890 met_t *met1,
4891 atm_t *atm) {
4892
4893 double t;
4894
4895 /* Set timer... */
4896 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS");
4897
4898 /* Save pressure... */
4899 if (ctl->isosurf == 1) {
4900 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
4901 cache->iso_var[ip] = atm->p[ip];
4902 }
4903 }
4904
4905 /* Save density... */
4906 else if (ctl->isosurf == 2) {
4907 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4909 INTPOL_3D(t, 1);
4910 cache->iso_var[ip] = atm->p[ip] / t;
4911 }
4912 }
4913
4914 /* Save potential temperature... */
4915 else if (ctl->isosurf == 3) {
4916 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4918 INTPOL_3D(t, 1);
4919 cache->iso_var[ip] = THETA(atm->p[ip], t);
4920 }
4921 }
4922
4923 /* Read balloon pressure data... */
4924 else if (ctl->isosurf == 4) {
4925
4926 /* Write info... */
4927 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
4928
4929 /* Open file... */
4930 FILE *in;
4931 if (!(in = fopen(ctl->balloon, "r")))
4932 ERRMSG("Cannot open file!");
4933
4934 /* Read pressure time series... */
4935 char line[LEN];
4936 while (fgets(line, LEN, in))
4937 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
4938 &(cache->iso_ps[cache->iso_n])) == 2)
4939 if ((++cache->iso_n) > NP)
4940 ERRMSG("Too many data points!");
4941
4942 /* Check number of points... */
4943 if (cache->iso_n < 1)
4944 ERRMSG("Could not read any data!");
4945
4946 /* Close file... */
4947 fclose(in);
4948
4949 /* Update of cache data on device... */
4950 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
4951 }
4952}
4953
4954/*****************************************************************************/
4955
4957 const ctl_t *ctl,
4958 const cache_t *cache,
4959 met_t *met0,
4960 met_t *met1,
4961 atm_t *atm) {
4962
4963 /* Set timer... */
4964 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS");
4965
4966 /* Loop over particles... */
4967 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
4968
4969 /* Init... */
4970 double t;
4972
4973 /* Restore pressure... */
4974 if (ctl->isosurf == 1)
4975 atm->p[ip] = cache->iso_var[ip];
4976
4977 /* Restore density... */
4978 else if (ctl->isosurf == 2) {
4979 INTPOL_3D(t, 1);
4980 atm->p[ip] = cache->iso_var[ip] * t;
4981 }
4982
4983 /* Restore potential temperature... */
4984 else if (ctl->isosurf == 3) {
4985 INTPOL_3D(t, 1);
4986 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / KAPPA);
4987 }
4988
4989 /* Interpolate pressure... */
4990 else if (ctl->isosurf == 4) {
4991 if (atm->time[ip] <= cache->iso_ts[0])
4992 atm->p[ip] = cache->iso_ps[0];
4993 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
4994 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
4995 else {
4996 const int idx =
4997 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
4998 atm->p[ip] =
4999 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
5000 cache->iso_ps[idx + 1], atm->time[ip]);
5001 }
5002 }
5003 }
5004}
5005
5006/*****************************************************************************/
5007
5008#ifdef KPP
5009void module_kpp_chem(
5010 ctl_t *ctl,
5011 cache_t *cache,
5012 clim_t *clim,
5013 met_t *met0,
5014 met_t *met1,
5015 atm_t *atm) {
5016
5017 /* Set timer... */
5018 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS");
5019
5020 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
5021 double rtol[1] = { 1.0e-3 };
5022 double atol[1] = { 1.0 };
5023
5024 /* Loop over particles... */
5025#ifdef _OPENACC
5026#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
5027#endif
5028 PARTICLE_LOOP(0, atm->np, 1,
5029 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
5030
5031 /* Initialize... */
5032 double var[nvar], fix[nfix], rconst[nreact];
5033 for (int i = 0; i < nvar; i++)
5034 var[i] = 0.0;
5035 for (int i = 0; i < nfix; i++)
5036 fix[i] = 0.0;
5037 for (int i = 0; i < nreact; i++)
5038 rconst[i] = 0.0;
5039 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
5040
5041 /* Integrate... */
5042 double rpar[20];
5043 int ipar[20];
5044 for (int i = 0; i < 20; i++) {
5045 ipar[i] = 0;
5046 rpar[i] = 0.0;
5047 }
5048 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) */
5049 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
5050 ipar[3] = 4; /* choice of the method:Rodas3 */
5051 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
5052 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
5053
5054 /* Save results.. */
5055 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
5056 }
5057}
5058#endif
5059
5060/*****************************************************************************/
5061
5063 const ctl_t *ctl,
5064 const cache_t *cache,
5065 const clim_t *clim,
5066 met_t *met0,
5067 met_t *met1,
5068 atm_t *atm) {
5069
5070 /* Set timer... */
5071 SELECT_TIMER("MODULE_METEO", "PHYSICS");
5072
5073 /* Check quantity flags... */
5074 if (ctl->qnt_tsts >= 0)
5075 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
5076 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
5077
5078 /* Loop over particles... */
5079 PARTICLE_LOOP(0, atm->np, 0,
5080 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5081
5082 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
5083 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
5084 o3, lwc, rwc, iwc, swc, cc, z, zt;
5085
5086 /* Interpolate meteo data... */
5088 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
5089
5090 /* Set quantities... */
5091 SET_ATM(qnt_ps, ps);
5092 SET_ATM(qnt_ts, ts);
5093 SET_ATM(qnt_zs, zs);
5094 SET_ATM(qnt_us, us);
5095 SET_ATM(qnt_vs, vs);
5096 SET_ATM(qnt_ess, ess);
5097 SET_ATM(qnt_nss, nss);
5098 SET_ATM(qnt_shf, shf);
5099 SET_ATM(qnt_lsm, lsm);
5100 SET_ATM(qnt_sst, sst);
5101 SET_ATM(qnt_pbl, pbl);
5102 SET_ATM(qnt_pt, pt);
5103 SET_ATM(qnt_tt, tt);
5104 SET_ATM(qnt_zt, zt);
5105 SET_ATM(qnt_h2ot, h2ot);
5106 SET_ATM(qnt_zg, z);
5107 SET_ATM(qnt_p, atm->p[ip]);
5108 SET_ATM(qnt_t, t);
5109 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
5110 SET_ATM(qnt_u, u);
5111 SET_ATM(qnt_v, v);
5112 SET_ATM(qnt_w, w);
5113 SET_ATM(qnt_h2o, h2o);
5114 SET_ATM(qnt_o3, o3);
5115 SET_ATM(qnt_lwc, lwc);
5116 SET_ATM(qnt_rwc, rwc);
5117 SET_ATM(qnt_iwc, iwc);
5118 SET_ATM(qnt_swc, swc);
5119 SET_ATM(qnt_cc, cc);
5120 SET_ATM(qnt_pct, pct);
5121 SET_ATM(qnt_pcb, pcb);
5122 SET_ATM(qnt_cl, cl);
5123 SET_ATM(qnt_plcl, plcl);
5124 SET_ATM(qnt_plfc, plfc);
5125 SET_ATM(qnt_pel, pel);
5126 SET_ATM(qnt_cape, cape);
5127 SET_ATM(qnt_cin, cin);
5128 SET_ATM(qnt_o3c, o3c);
5129 const double lat_ref =
5130 ctl->met_coord_type == 0 ? atm->lat[ip] : ctl->met_utm_ref_lat;
5131 SET_ATM(qnt_hno3,
5132 clim_zm(&clim->hno3, atm->time[ip], lat_ref, atm->p[ip]));
5133 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
5134 atm->lon[ip], atm->lat[ip], atm->p[ip]));
5135 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
5136 lat_ref, atm->p[ip]));
5137 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip], lat_ref, atm->p[ip]));
5138 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip], lat_ref, atm->p[ip]));
5139 SET_ATM(qnt_vh, sqrt(u * u + v * v));
5140 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
5141 SET_ATM(qnt_psat, PSAT(t));
5142 SET_ATM(qnt_psice, PSICE(t));
5143 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
5144 SET_ATM(qnt_sh, SH(h2o));
5145 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
5146 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
5147 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
5148 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
5149 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
5150 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
5151 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
5152 SET_ATM(qnt_eta_dot, atm->q[ctl->qnt_eta_dot][ip]);
5153 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
5154 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
5155 SET_ATM(qnt_pv, pv);
5156 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
5157 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
5158 SET_ATM(qnt_tnat,
5159 nat_temperature(atm->p[ip], h2o,
5160 clim_zm(&clim->hno3, atm->time[ip],
5161 atm->lat[ip], atm->p[ip])));
5162 SET_ATM(qnt_tsts,
5163 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
5164 }
5165}
5166
5167/*****************************************************************************/
5168
5170 const ctl_t *ctl,
5171 const clim_t *clim,
5172 atm_t *atm,
5173 const double t) {
5174
5175 /* Set timer... */
5176 SELECT_TIMER("MODULE_MIXING", "PHYSICS");
5177
5178 /* Allocate... */
5179 const int np = atm->np;
5180 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
5181 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
5182 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
5183
5184 /* Set grid box size... */
5185 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
5186 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
5187 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
5188
5189 /* Set time interval... */
5190 const double t0 = t - 0.5 * ctl->dt_mod;
5191 const double t1 = t + 0.5 * ctl->dt_mod;
5192
5193 /* Get indices... */
5194#ifdef _OPENACC
5195#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
5196#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
5197#pragma acc parallel loop independent gang vector
5198#else
5199#pragma omp parallel for default(shared)
5200#endif
5201 for (int ip = 0; ip < np; ip++) {
5202 const double zpart = Z(atm->p[ip]);
5203 if (atm->time[ip] < t0 || atm->time[ip] > t1
5204 || atm->lon[ip] < ctl->mixing_lon0
5205 || atm->lon[ip] >= ctl->mixing_lon1
5206 || atm->lat[ip] < ctl->mixing_lat0
5207 || atm->lat[ip] >= ctl->mixing_lat1
5208 || zpart < ctl->mixing_z0 || zpart >= ctl->mixing_z1) {
5209 izs[ip] = -1;
5210 continue;
5211 }
5212 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
5213 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
5214 izs[ip] = (int) ((zpart - ctl->mixing_z0) / dz);
5215 if (ixs[ip] >= ctl->mixing_nx || iys[ip] >= ctl->mixing_ny
5216 || izs[ip] >= ctl->mixing_nz)
5217 izs[ip] = -1;
5218 }
5219
5220 /* Calculate interparcel mixing... */
5221 const int use_ensemble = (ctl->nens > 0);
5222
5223 const int quantities[] = {
5224 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
5225 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
5226 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
5227 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
5228 ctl->qnt_Csf6, ctl->qnt_aoa, ctl->qnt_Arn222, ctl->qnt_Apb210,
5229 ctl->qnt_Abe7, ctl->qnt_Acs137, ctl->qnt_Ai131, ctl->qnt_Axe133
5230 };
5231 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
5232
5233 for (int i = 0; i < n_qnt; i++)
5234 if (quantities[i] >= 0)
5235 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
5236 use_ensemble);
5237
5238 /* Free... */
5239#ifdef _OPENACC
5240#pragma acc exit data delete(ixs,iys,izs)
5241#endif
5242 free(ixs);
5243 free(iys);
5244 free(izs);
5245}
5246
5247/*****************************************************************************/
5248
5250 const ctl_t *ctl,
5251 const clim_t *clim,
5252 atm_t *atm,
5253 const int *ixs,
5254 const int *iys,
5255 const int *izs,
5256 const int qnt_idx,
5257 const int use_ensemble) {
5258
5259 const int np = atm->np;
5260 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
5261 const int nens = use_ensemble ? ctl->nens : 1;
5262 const int total_grid = ngrid * nens;
5263
5264 double *restrict const cmean =
5265 (double *) malloc((size_t) total_grid * sizeof(double));
5266 int *restrict const count =
5267 (int *) malloc((size_t) total_grid * sizeof(int));
5268
5269 /* Init... */
5270#ifdef _OPENACC
5271#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
5272#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
5273#pragma acc parallel loop independent gang vector
5274#else
5275#ifdef __NVCOMPILER
5276#pragma novector
5277#endif
5278#pragma omp parallel for
5279#endif
5280 for (int i = 0; i < total_grid; i++) {
5281 count[i] = 0;
5282 cmean[i] = 0.0;
5283 }
5284
5285 /* Loop over particles... */
5286#ifdef _OPENACC
5287#pragma acc parallel loop independent gang vector
5288#endif
5289 for (int ip = 0; ip < np; ip++)
5290 if (izs[ip] >= 0) {
5291 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
5292 const int idx =
5293 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
5294 ctl->mixing_nz);
5295#ifdef _OPENACC
5296#pragma acc atomic update
5297#endif
5298 cmean[idx] += atm->q[qnt_idx][ip];
5299#ifdef _OPENACC
5300#pragma acc atomic update
5301#endif
5302 count[idx]++;
5303 }
5304
5305 /* Compute means... */
5306#ifdef _OPENACC
5307#pragma acc parallel loop independent gang vector
5308#else
5309#ifdef __NVCOMPILER
5310#pragma novector
5311#endif
5312#pragma omp parallel for
5313#endif
5314 for (int i = 0; i < total_grid; i++)
5315 if (count[i] > 0)
5316 cmean[i] /= count[i];
5317
5318 /* Interparcel mixing... */
5319#ifdef _OPENACC
5320#pragma acc parallel loop independent gang vector
5321#else
5322#pragma omp parallel for
5323#endif
5324 for (int ip = 0; ip < np; ip++) {
5325 if (izs[ip] >= 0) {
5326 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
5327
5328 double mixparam = 1.0;
5329 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
5330 const double w = tropo_weight(ctl, clim, atm, ip);
5331 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
5332 }
5333
5334 const int idx =
5335 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
5336 ctl->mixing_nz);
5337 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
5338 }
5339 }
5340
5341 /* Free... */
5342#ifdef _OPENACC
5343#pragma acc exit data delete(cmean,count)
5344#endif
5345 free(cmean);
5346 free(count);
5347}
5348
5349/*****************************************************************************/
5350
5352 const ctl_t *ctl,
5353 const cache_t *cache,
5354 const clim_t *clim,
5355 met_t *met0,
5356 met_t *met1,
5357 atm_t *atm) {
5358
5359 /* Set timer... */
5360 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS");
5361
5362 /* Check quantity flags... */
5363 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5364 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5365
5366 /* Parameter of SO2 correction... */
5367 const double a = 4.71572206e-08;
5368 const double b = -8.28782867e-01;
5369 const double low = pow(1. / a, 1. / b);
5370
5371 /* Loop over particles... */
5372 PARTICLE_LOOP(0, atm->np, 1,
5373 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5374
5375 /* Get temperature... */
5376 double t;
5378 INTPOL_3D(t, 1);
5379
5380 /* Calculate molecular density... */
5381 const double M = MOLEC_DENS(atm->p[ip], t);
5382
5383 /* Use constant reaction rate... */
5384 double k = NAN;
5385 if (ctl->oh_chem_reaction == 1)
5386 k = ctl->oh_chem[0];
5387
5388 /* Calculate bimolecular reaction rate... */
5389 else if (ctl->oh_chem_reaction == 2)
5390 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
5391
5392 /* Calculate termolecular reaction rate... */
5393 if (ctl->oh_chem_reaction == 3) {
5394
5395 /* Calculate rate coefficient for X + OH + M -> XOH + M
5396 (JPL Publication 19-05) ... */
5397 const double k0 =
5398 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
5399 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
5400 const double ki =
5401 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
5402 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
5403 const double c = log10(k0 * M / ki);
5404 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
5405 }
5406
5407 /* Correction factor for high SO2 concentration
5408 (if qnt_Cx is defined, the correction is switched on)... */
5409 double cor = 1;
5410 if (ctl->qnt_Cx >= 0)
5411 cor =
5412 atm->q[ctl->qnt_Cx][ip] >
5413 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
5414
5415 /* Calculate exponential decay... */
5416 const double rate_coef =
5417 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
5418 atm->lat[ip], atm->p[ip]) * M * cor;
5419 const double aux = exp(-cache->dt[ip] * rate_coef);
5420 if (ctl->qnt_m >= 0) {
5421 if (ctl->qnt_mloss_oh >= 0)
5422 atm->q[ctl->qnt_mloss_oh][ip]
5423 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5424 atm->q[ctl->qnt_m][ip] *= aux;
5425 if (ctl->qnt_loss_rate >= 0)
5426 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
5427 }
5428 if (ctl->qnt_vmr >= 0)
5429 atm->q[ctl->qnt_vmr][ip] *= aux;
5430 }
5431}
5432
5433/*****************************************************************************/
5434
5436 const cache_t *cache,
5437 met_t *met0,
5438 met_t *met1,
5439 atm_t *atm) {
5440
5441 /* Set timer... */
5442 SELECT_TIMER("MODULE_POSITION", "PHYSICS");
5443
5444 /* Loop over particles... */
5445 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
5446
5447 /* Init... */
5448 double ps;
5450
5451 if (met0->coord_type == 0) {
5452 /* Calculate modulo... */
5453 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
5454 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
5455
5456 /* Check latitude... */
5457 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
5458 if (atm->lat[ip] > 90) {
5459 atm->lat[ip] = 180 - atm->lat[ip];
5460 atm->lon[ip] += 180;
5461 }
5462 if (atm->lat[ip] < -90) {
5463 atm->lat[ip] = -180 - atm->lat[ip];
5464 atm->lon[ip] += 180;
5465 }
5466 }
5467
5468 /* Check longitude... */
5469 while (atm->lon[ip] < -180)
5470 atm->lon[ip] += 360;
5471 while (atm->lon[ip] >= 180)
5472 atm->lon[ip] -= 360;
5473 } else {
5474 intpol_check_cartesian(met0->lon, met0->nx, met0->lat, met0->ny,
5475 atm->lon[ip], atm->lat[ip], &atm->lon[ip],
5476 &atm->lat[ip]);
5477 }
5478
5479 /* Check pressure... */
5480 const double ptop = met0->p[met0->np - 1];
5481 if (atm->p[ip] < ptop) {
5482 atm->p[ip] = ptop * ptop / atm->p[ip];
5483 } else if (atm->p[ip] > 300.) {
5484 INTPOL_2D(ps, 0);
5485 if (atm->p[ip] > ps)
5486 atm->p[ip] = ps * ps / atm->p[ip];
5487 }
5488 }
5489}
5490
5491/*****************************************************************************/
5492
5494 const ctl_t *ctl,
5495 const cache_t *cache,
5496 atm_t *atm) {
5497
5498 /* Set timer... */
5499 SELECT_TIMER("MODULE_RADIO_DECAY", "PHYSICS");
5500
5501 /* Set decay constants of radioactive species [s^-1]... */
5502 const double lambda_rn222 = log(2.0) / RADIO_HALF_LIFE_RN222;
5503 const double lambda_pb210 = log(2.0) / RADIO_HALF_LIFE_PB210;
5504 const double lambda_be7 = log(2.0) / RADIO_HALF_LIFE_BE7;
5505 const double lambda_cs137 = log(2.0) / RADIO_HALF_LIFE_CS137;
5506 const double lambda_i131 = log(2.0) / RADIO_HALF_LIFE_I131;
5507 const double lambda_xe133 = log(2.0) / RADIO_HALF_LIFE_XE133;
5508
5509 /* Loop over particles... */
5510 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,atm)") {
5511
5512 /* Set timestep... */
5513 const double dt = cache->dt[ip];
5514
5515 /* Loss for Pb-210... */
5516 if (ctl->qnt_Apb210 >= 0)
5517 atm->q[ctl->qnt_Apb210][ip] *= exp(-dt * lambda_pb210);
5518
5519 /* Loss for Rn-222... */
5520 if (ctl->qnt_Arn222 >= 0) {
5521 const double old = atm->q[ctl->qnt_Arn222][ip];
5522 const double aux = exp(-dt * lambda_rn222);
5523 const double lost = old * (1.0 - aux);
5524 atm->q[ctl->qnt_Arn222][ip] = old * aux;
5525
5526 /* Parent-daughter process for Pb-210... */
5527 if (ctl->qnt_Apb210 >= 0)
5528 atm->q[ctl->qnt_Apb210][ip] += lost * lambda_pb210 / lambda_rn222;
5529 }
5530
5531 /* Loss for Be-7... */
5532 if (ctl->qnt_Abe7 >= 0)
5533 atm->q[ctl->qnt_Abe7][ip] *= exp(-dt * lambda_be7);
5534
5535 /* Loss for Cs-137... */
5536 if (ctl->qnt_Acs137 >= 0)
5537 atm->q[ctl->qnt_Acs137][ip] *= exp(-dt * lambda_cs137);
5538
5539 /* Loss for I-131... */
5540 if (ctl->qnt_Ai131 >= 0)
5541 atm->q[ctl->qnt_Ai131][ip] *= exp(-dt * lambda_i131);
5542
5543 /* Loss for Xe-133... */
5544 if (ctl->qnt_Axe133 >= 0)
5545 atm->q[ctl->qnt_Axe133][ip] *= exp(-dt * lambda_xe133);
5546 }
5547}
5548
5549/*****************************************************************************/
5550
5552 const ctl_t *ctl,
5553 const cache_t *cache,
5554 met_t *met0,
5555 met_t *met1,
5556 atm_t *atm,
5557 depo_t *depo) {
5558
5559 /* Set timer... */
5560 SELECT_TIMER("MODULE_RADIO_DEPO", "PHYSICS");
5561
5562 /* Decay constants of deposited radionuclides [s^-1]... */
5563 const double lambda_pb210 = log(2.0) / RADIO_HALF_LIFE_PB210;
5564 const double lambda_be7 = log(2.0) / RADIO_HALF_LIFE_BE7;
5565 const double lambda_cs137 = log(2.0) / RADIO_HALF_LIFE_CS137;
5566 const double lambda_i131 = log(2.0) / RADIO_HALF_LIFE_I131;
5567
5568 /* Set horizontal grid increments... */
5569 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
5570 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
5571
5572 /* Loop over particles... */
5573 PARTICLE_LOOP(0, atm->np, 1,
5574 "acc data present(ctl,cache,met0,met1,atm,depo)") {
5575
5576 /* Deposition is only defined for forward integration... */
5577 const double dt = cache->dt[ip];
5578 if (dt <= 0)
5579 continue;
5580
5581 /* Get surface pressure... */
5582 double ps;
5584 INTPOL_2D(ps, 1);
5585
5586 /* Calculate dry deposition rate [s^-1]... */
5587 double dry_pb210 = 0, dry_be7 = 0, dry_cs137 = 0, dry_i131 = 0;
5588 if (atm->p[ip] >= ps - ctl->dry_depo_dp) {
5589 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
5590 if (dz > 0) {
5591 dry_pb210 = RADIO_DRY_VDEP_PB210 / dz;
5592 dry_be7 = RADIO_DRY_VDEP_BE7 / dz;
5593 dry_cs137 = RADIO_DRY_VDEP_CS137 / dz;
5594 dry_i131 = RADIO_DRY_VDEP_I131 / dz;
5595 }
5596 }
5597
5598 /* Calculate wet deposition rate [s^-1]... */
5599 double wet_pb210 = 0, wet_be7 = 0, wet_cs137 = 0, wet_i131 = 0;
5600 double pct;
5601 INTPOL_2D(pct, 1);
5602 if (isfinite(pct) && atm->p[ip] > pct) {
5603 double cl;
5604 INTPOL_2D(cl, 0);
5605 if (cl > 0) {
5606 const double Is =
5607 pow(cl / ctl->wet_depo_pre[0], 1. / ctl->wet_depo_pre[1]);
5608 if (Is >= 0.01) {
5609 double lwc, rwc, iwc, swc, t;
5610 INTPOL_3D(lwc, 1);
5611 INTPOL_3D(rwc, 0);
5612 INTPOL_3D(iwc, 0);
5613 INTPOL_3D(swc, 0);
5614 INTPOL_3D(t, 0);
5615 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
5616 double eta;
5617 if (inside) {
5618 if (t > WET_DEPO_T_LIQUID)
5619 eta = 1;
5620 else if (t <= WET_DEPO_T_ICE)
5621 eta = ctl->wet_depo_ic_ret_ratio;
5622 else
5624 ctl->wet_depo_ic_ret_ratio, t);
5625 } else
5626 eta = (t > WET_DEPO_T_LIQUID_BC ? 1 : ctl->wet_depo_bc_ret_ratio);
5627 wet_pb210 = RADIO_WET_COEFF_PB210 * Is * eta;
5628 wet_be7 = RADIO_WET_COEFF_BE7 * Is * eta;
5629 wet_cs137 = RADIO_WET_COEFF_CS137 * Is * eta;
5630 wet_i131 = RADIO_WET_COEFF_I131 * Is * eta;
5631 }
5632 }
5633 }
5634
5635 /* Get deposition grid index... */
5636 const int ingrid =
5637 (atm->lon[ip] >= ctl->grid_lon0
5638 && atm->lon[ip] < ctl->grid_lon1
5639 && atm->lat[ip] >= ctl->grid_lat0 && atm->lat[ip] < ctl->grid_lat1);
5640 const int ix = ingrid
5641 ? (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon) : 0;
5642 const int iy = ingrid
5643 ? (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat) : 0;
5644 const int idx = (ingrid ? ARRAY_2D(ix, iy, ctl->grid_ny) : 0);
5645 const double tref = atm->time[ip] - ctl->t_start;
5646
5647 /* Deposit Pb-210... */
5648 if (ctl->qnt_Apb210 >= 0) {
5649 const double old = atm->q[ctl->qnt_Apb210][ip];
5650 const double aux = exp(-dt * (dry_pb210 + wet_pb210));
5651 const double lost = old * (1. - aux);
5652 const double deposited = lost
5653 * (ctl->radio_decay ? exp(lambda_pb210 * tref) : 1.0);
5654 atm->q[ctl->qnt_Apb210][ip] = old * aux;
5655 if (ingrid && lost > 0) {
5656#ifdef _OPENACC
5657#pragma acc atomic update
5658#else
5659#pragma omp atomic update
5660#endif
5661 depo->Apb210[idx] += deposited;
5662 }
5663 }
5664
5665 /* Deposit Be-7... */
5666 if (ctl->qnt_Abe7 >= 0) {
5667 const double old = atm->q[ctl->qnt_Abe7][ip];
5668 const double aux = exp(-dt * (dry_be7 + wet_be7));
5669 const double lost = old * (1. - aux);
5670 const double deposited = lost
5671 * (ctl->radio_decay ? exp(lambda_be7 * tref) : 1.0);
5672 atm->q[ctl->qnt_Abe7][ip] = old * aux;
5673 if (ingrid && lost > 0) {
5674#ifdef _OPENACC
5675#pragma acc atomic update
5676#else
5677#pragma omp atomic update
5678#endif
5679 depo->Abe7[idx] += deposited;
5680 }
5681 }
5682
5683 /* Deposit Cs-137... */
5684 if (ctl->qnt_Acs137 >= 0) {
5685 const double old = atm->q[ctl->qnt_Acs137][ip];
5686 const double aux = exp(-dt * (dry_cs137 + wet_cs137));
5687 const double lost = old * (1. - aux);
5688 const double deposited = lost
5689 * (ctl->radio_decay ? exp(lambda_cs137 * tref) : 1.0);
5690 atm->q[ctl->qnt_Acs137][ip] = old * aux;
5691 if (ingrid && lost > 0) {
5692#ifdef _OPENACC
5693#pragma acc atomic update
5694#else
5695#pragma omp atomic update
5696#endif
5697 depo->Acs137[idx] += deposited;
5698 }
5699 }
5700
5701 /* Deposit aerosol-bound I-131... */
5702 if (ctl->qnt_Ai131 >= 0) {
5703 const double old = atm->q[ctl->qnt_Ai131][ip];
5704 const double aux = exp(-dt * (dry_i131 + wet_i131));
5705 const double lost = old * (1. - aux);
5706 const double deposited = lost
5707 * (ctl->radio_decay ? exp(lambda_i131 * tref) : 1.0);
5708 atm->q[ctl->qnt_Ai131][ip] = old * aux;
5709 if (ingrid && lost > 0) {
5710#ifdef _OPENACC
5711#pragma acc atomic update
5712#else
5713#pragma omp atomic update
5714#endif
5715 depo->Ai131[idx] += deposited;
5716 }
5717 }
5718 }
5719}
5720
5721/*****************************************************************************/
5722
5724 const int ntask) {
5725
5726 /* Initialize GSL random number generators... */
5727 gsl_rng_env_setup();
5728 if (omp_get_max_threads() > NTHREADS)
5729 ERRMSG("Too many threads!");
5730 for (int i = 0; i < NTHREADS; i++) {
5731 rng[i] = gsl_rng_alloc(gsl_rng_default);
5732 gsl_rng_set(rng[i], gsl_rng_default_seed
5733 + (long unsigned) (ntask * NTHREADS + i));
5734 }
5735
5736 /* Initialize cuRAND random number generators... */
5737#ifdef CURAND
5738 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
5739 CURAND_STATUS_SUCCESS)
5740 ERRMSG("Cannot create random number generator!");
5741 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
5742 CURAND_STATUS_SUCCESS)
5743 ERRMSG("Cannot set seed for random number generator!");
5744 if (curandSetStream
5745 (rng_curand,
5746 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
5747 CURAND_STATUS_SUCCESS)
5748 ERRMSG("Cannot set stream for random number generator!");
5749#endif
5750}
5751
5752/*****************************************************************************/
5753
5755 const ctl_t *ctl,
5756 double *rs,
5757 const size_t n,
5758 const int method) {
5759
5760 /* Use GSL random number generators... */
5761 if (ctl->rng_type == 0) {
5762
5763 /* Uniform distribution... */
5764 if (method == 0) {
5765#pragma omp parallel for default(shared)
5766 for (size_t i = 0; i < n; ++i)
5767 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
5768 }
5769
5770 /* Normal distribution... */
5771 else if (method == 1) {
5772#pragma omp parallel for default(shared)
5773 for (size_t i = 0; i < n; ++i)
5774 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
5775 }
5776
5777 /* Update of random numbers on device... */
5778#ifdef _OPENACC
5779 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
5780#pragma acc update device(rs[:n])
5781#endif
5782 }
5783
5784 /* Use Squares random number generator (Widynski, 2022)... */
5785 else if (ctl->rng_type == 1) {
5786
5787 /* Set key (don't change this!)... */
5788 const uint64_t key = 0xc8e4fd154ce32f6d;
5789
5790 /* Uniform distribution... */
5791#ifdef _OPENACC
5792#pragma acc data present(rs)
5793#pragma acc parallel loop independent gang vector
5794#else
5795#pragma omp parallel for default(shared)
5796#endif
5797 for (size_t i = 0; i < n + 1; ++i) {
5798 uint64_t r, t, x, y, z;
5799 y = x = (rng_ctr + i) * key;
5800 z = y + key;
5801 x = x * x + y;
5802 x = (x >> 32) | (x << 32);
5803 x = x * x + z;
5804 x = (x >> 32) | (x << 32);
5805 x = x * x + y;
5806 x = (x >> 32) | (x << 32);
5807 t = x = x * x + z;
5808 x = (x >> 32) | (x << 32);
5809 r = t ^ ((x * x + y) >> 32);
5810 rs[i] = (double) r / (double) UINT64_MAX;
5811 }
5812 rng_ctr += n + 1;
5813
5814 /* Normal distribution... */
5815 if (method == 1) {
5816#ifdef _OPENACC
5817#pragma acc parallel loop independent gang vector
5818#else
5819#pragma omp parallel for default(shared)
5820#endif
5821 for (size_t i = 0; i < n; i += 2) {
5822 const double r = sqrt(-2.0 * log(rs[i]));
5823 const double phi = 2.0 * M_PI * rs[i + 1];
5824 rs[i] = r * cosf((float) phi);
5825 rs[i + 1] = r * sinf((float) phi);
5826 }
5827 }
5828 }
5829
5830 /* Use cuRAND random number generators... */
5831 else if (ctl->rng_type == 2) {
5832#ifdef CURAND
5833#pragma acc host_data use_device(rs)
5834 {
5835
5836 /* Uniform distribution... */
5837 if (method == 0) {
5838 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
5839 CURAND_STATUS_SUCCESS)
5840 ERRMSG("Cannot create random numbers!");
5841 }
5842
5843 /* Normal distribution... */
5844 else if (method == 1) {
5845 if (curandGenerateNormalDouble
5846 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
5847 1.0) != CURAND_STATUS_SUCCESS)
5848 ERRMSG("Cannot create random numbers!");
5849 }
5850 }
5851#else
5852 ERRMSG("MPTRAC was compiled without cuRAND!");
5853#endif
5854 }
5855}
5856
5857/*****************************************************************************/
5858
5860 const ctl_t *ctl,
5861 const cache_t *cache,
5862 met_t *met0,
5863 met_t *met1,
5864 atm_t *atm) {
5865
5866 /* Set timer... */
5867 SELECT_TIMER("MODULE_SEDI", "PHYSICS")
5868 /* Loop over particles... */
5869 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5870
5871 /* Get temperature... */
5872 double t;
5874 INTPOL_3D(t, 1);
5875
5876 /* Sedimentation velocity... */
5877 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
5878 atm->q[ctl->qnt_rhop][ip]);
5879
5880 /* Calculate pressure change... */
5881 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
5882 }
5883}
5884
5885/*****************************************************************************/
5886
5888 const ctl_t *ctl,
5889 const met_t *met0,
5890 atm_t *atm) {
5891
5892 /* Set timer... */
5893 SELECT_TIMER("MODULE_SORT", "PHYSICS");
5894
5895 /* Allocate... */
5896 const int np = atm->np;
5897 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
5898 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
5899 if (a == NULL || p == NULL)
5900 ERRMSG("Out of memory!");
5901
5902#ifdef _OPENACC
5903#pragma acc enter data create(a[0:np],p[0:np])
5904#pragma acc data present(ctl,met0,atm,a,p)
5905#endif
5906
5907 /* Get box index... */
5908#ifdef _OPENACC
5909#pragma acc parallel loop independent gang vector
5910#else
5911#pragma omp parallel for default(shared)
5912#endif
5913 for (int ip = 0; ip < np; ip++) {
5914 a[ip] =
5915 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
5916 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
5917 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
5918 p[ip] = ip;
5919 }
5920
5921 /* Sorting... */
5922#ifdef THRUST
5923#ifdef _OPENACC
5924#pragma acc host_data use_device(a,p)
5925#endif
5926 thrustSortWrapper(a, np, p);
5927#else
5928 size_t *perm_sz = (size_t *) malloc((size_t) np * sizeof(size_t));
5929 if (perm_sz == NULL)
5930 ERRMSG("Out of memory!");
5931#ifdef _OPENACC
5932#pragma acc update self(a[0:np])
5933#endif
5934 gsl_sort_index(perm_sz, a, 1, (size_t) np);
5935 for (int ip = 0; ip < np; ++ip)
5936 p[ip] = (int) perm_sz[ip];
5937 free(perm_sz);
5938#ifdef _OPENACC
5939#pragma acc update device(p[0:np])
5940#endif
5941#endif
5942
5943 /* Sort data... */
5944 module_sort_help(atm->time, p, np);
5945 module_sort_help(atm->p, p, np);
5946 module_sort_help(atm->lon, p, np);
5947 module_sort_help(atm->lat, p, np);
5948 for (int iq = 0; iq < ctl->nq; iq++)
5949 module_sort_help(atm->q[iq], p, np);
5950
5951 /* Free... */
5952#ifdef _OPENACC
5953#pragma acc exit data delete(a,p)
5954#endif
5955 free(a);
5956 free(p);
5957}
5958
5959/*****************************************************************************/
5960
5962 double *a,
5963 const int *p,
5964 const int np) {
5965
5966 /* Allocate... */
5967 double *restrict const help =
5968 (double *) malloc((size_t) np * sizeof(double));
5969 if (help == NULL)
5970 ERRMSG("Out of memory!");
5971
5972 /* Reordering of array... */
5973#ifdef _OPENACC
5974#pragma acc enter data create(help[0:np])
5975#pragma acc data present(a,p,help)
5976#pragma acc parallel loop independent gang vector
5977#else
5978#pragma omp parallel for default(shared)
5979#endif
5980 for (int ip = 0; ip < np; ip++)
5981 help[ip] = a[p[ip]];
5982#ifdef _OPENACC
5983#pragma acc parallel loop independent gang vector
5984#else
5985#pragma omp parallel for default(shared)
5986#endif
5987 for (int ip = 0; ip < np; ip++)
5988 a[ip] = help[ip];
5989
5990 /* Free... */
5991#ifdef _OPENACC
5992#pragma acc exit data delete(help)
5993#endif
5994 free(help);
5995}
5996
5997/*****************************************************************************/
5998
6000 const ctl_t *ctl,
6001 cache_t *cache,
6002 met_t *met0,
6003 atm_t *atm,
6004 const double t) {
6005
6006 /* Set timer... */
6007 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS");
6008
6009 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
6010 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
6011
6012 const int local =
6013 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
6014
6015 /* Loop over particles... */
6016 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
6017
6018 /* Set time step for each air parcel... */
6019 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
6020 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
6021 && ctl->direction * (atm->time[ip] - t) < 0))
6022 cache->dt[ip] = t - atm->time[ip];
6023 else
6024 cache->dt[ip] = 0.0;
6025
6026 /* Check horizontal boundaries of local meteo data... */
6027#ifndef DD
6028 int dd = 1;
6029#else
6030 int dd = 0;
6031#endif
6032 if (dd) {
6033 if (local && (atm->lon[ip] <= met0->lon[0]
6034 || atm->lon[ip] >= met0->lon[met0->nx - 1]
6035 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
6036 cache->dt[ip] = 0.0;
6037 } else {
6038 if ((int) atm->q[ctl->qnt_current_subdomain][ip] == -1)
6039 cache->dt[ip] = 0;
6040 }
6041 }
6042}
6043
6044/*****************************************************************************/
6045
6047 ctl_t *ctl,
6048 const atm_t *atm) {
6049
6050 /* Set timer... */
6051 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS");
6052
6053 /* Set start time... */
6054 if (ctl->direction == 1) {
6055 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
6056 if (ctl->t_stop > 1e99)
6057 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
6058 } else {
6059 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
6060 if (ctl->t_stop > 1e99)
6061 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
6062 }
6063
6064 /* Check time interval... */
6065 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
6066 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
6067
6068 /* Round start time... */
6069 if (ctl->direction == 1)
6070 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
6071 else
6072 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
6073}
6074
6075/*****************************************************************************/
6076
6078 const ctl_t *ctl,
6079 const cache_t *cache,
6080 const clim_t *clim,
6081 met_t *met0,
6082 met_t *met1,
6083 atm_t *atm) {
6084
6085 if (ctl->met_coord_type != 0)
6086 ERRMSG("Only lat/lon grid supported");
6087
6088 /* Set timer... */
6089 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS");
6090
6091 /* Loop over particles... */
6092 PARTICLE_LOOP(0, atm->np, 1,
6093 "acc data present(ctl,cache,clim,met0,met1,atm)") {
6094
6095 /* Get temperature... */
6096 double t;
6098 INTPOL_3D(t, 1);
6099
6100 /* Get molecular density... */
6101 const double M = MOLEC_DENS(atm->p[ip], t);
6102
6103 /* Get total column ozone... */
6104 double o3c;
6105 INTPOL_2D(o3c, 1);
6106
6107 /* Get solar zenith angle... */
6108 const double sza =
6109 acos(cos_sza(atm->time[ip], atm->lon[ip], atm->lat[ip]));
6110
6111 /* Get O(1D) volume mixing ratio... */
6112 const double o1d =
6113 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
6114
6115 /* Reactions for CFC-10... */
6116 if (ctl->qnt_Cccl4 >= 0) {
6117 const double K_o1d =
6119 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
6120 atm->p[ip], sza, o3c);
6121 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6122 }
6123
6124 /* Reactions for CFC-11... */
6125 if (ctl->qnt_Cccl3f >= 0) {
6126 const double K_o1d =
6128 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
6129 atm->p[ip], sza, o3c);
6130 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6131 }
6132
6133 /* Reactions for CFC-12... */
6134 if (ctl->qnt_Cccl2f2 >= 0) {
6135 const double K_o1d =
6137 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
6138 atm->p[ip], sza, o3c);
6139 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6140 }
6141
6142 /* Reactions for N2O... */
6143 if (ctl->qnt_Cn2o >= 0) {
6144 const double K_o1d =
6146 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
6147 atm->p[ip], sza, o3c);
6148 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
6149 }
6150 }
6151}
6152
6153/*****************************************************************************/
6154
6156 const ctl_t *ctl,
6157 const cache_t *cache,
6158 met_t *met0,
6159 met_t *met1,
6160 atm_t *atm) {
6161
6162 /* Set timer... */
6163 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS");
6164
6165 /* Check quantity flags... */
6166 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
6167 ERRMSG("Module needs quantity mass or volume mixing ratio!");
6168
6169 /* Loop over particles... */
6170 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
6171
6172 /* Check whether particle is below cloud top... */
6173 double pct;
6175 INTPOL_2D(pct, 1);
6176 if (!isfinite(pct) || atm->p[ip] <= pct)
6177 continue;
6178
6179 /* Get cloud bottom pressure... */
6180 double pcb;
6181 INTPOL_2D(pcb, 0);
6182
6183 /* Estimate precipitation rate (Pisso et al., 2019)... */
6184 double cl;
6185 INTPOL_2D(cl, 0);
6186 const double Is =
6187 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
6188 if (Is < 0.01)
6189 continue;
6190
6191 /* Check whether particle is inside or below cloud... */
6192 double lwc, rwc, iwc, swc;
6193 INTPOL_3D(lwc, 1);
6194 INTPOL_3D(rwc, 0);
6195 INTPOL_3D(iwc, 0);
6196 INTPOL_3D(swc, 0);
6197 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
6198
6199 /* Get temperature... */
6200 double t;
6201 INTPOL_3D(t, 0);
6202
6203 /* Calculate in-cloud scavenging coefficient... */
6204 double lambda = 0;
6205 if (inside) {
6206
6207 /* Calculate retention factor... */
6208 double eta;
6209 if (t > WET_DEPO_T_LIQUID)
6210 eta = 1;
6211 else if (t <= WET_DEPO_T_ICE)
6212 eta = ctl->wet_depo_ic_ret_ratio;
6213 else
6214 eta =
6216 ctl->wet_depo_ic_ret_ratio, t);
6217
6218 /* Use exponential dependency for particles (Bakels et al., 2024)... */
6219 if (ctl->wet_depo_ic_a > 0)
6220 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
6221
6222 /* Use Henry's law for gases... */
6223 else if (ctl->wet_depo_ic_h[0] > 0) {
6224
6225 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
6226 double h = ctl->wet_depo_ic_h[0]
6227 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / CHEM_REF_TEMP));
6228
6229 /* Use effective Henry's constant for SO2
6230 (Berglen, 2004; Simpson, 2012)... */
6231 if (ctl->wet_depo_so2_ph > 0) {
6232 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
6233 const double K_1 = SO2_DISS_K1_REF
6234 * exp(SO2_DISS_K1_TEMP * (1. / t - 1. / CHEM_REF_TEMP));
6235 const double K_2 = SO2_DISS_K2_REF
6236 * exp(SO2_DISS_K2_TEMP * (1. / t - 1. / CHEM_REF_TEMP));
6237 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
6238 }
6239
6240 /* Estimate depth of cloud layer... */
6241 const double dz = 1e3 * (Z(pct) - Z(pcb));
6242
6243 /* Calculate scavenging coefficient... */
6244 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
6245 }
6246 }
6247
6248 /* Calculate below-cloud scavenging coefficient... */
6249 else {
6250
6251 /* Calculate retention factor... */
6252 double eta;
6253 if (t > WET_DEPO_T_LIQUID_BC)
6254 eta = 1;
6255 else
6256 eta = ctl->wet_depo_bc_ret_ratio;
6257
6258 /* Use exponential dependency for particles (Bakels et al., 2024)... */
6259 if (ctl->wet_depo_bc_a > 0)
6260 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
6261
6262 /* Use Henry's law for gases... */
6263 else if (ctl->wet_depo_bc_h[0] > 0) {
6264
6265 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
6266 const double h = ctl->wet_depo_bc_h[0]
6267 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / CHEM_REF_TEMP));
6268
6269 /* Estimate depth of cloud layer... */
6270 const double dz = 1e3 * (Z(pct) - Z(pcb));
6271
6272 /* Calculate scavenging coefficient... */
6273 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
6274 }
6275 }
6276
6277 /* Calculate exponential decay of mass... */
6278 const double aux = exp(-cache->dt[ip] * lambda);
6279 if (ctl->qnt_m >= 0) {
6280 if (ctl->qnt_mloss_wet >= 0)
6281 atm->q[ctl->qnt_mloss_wet][ip]
6282 += atm->q[ctl->qnt_m][ip] * (1 - aux);
6283 atm->q[ctl->qnt_m][ip] *= aux;
6284 if (ctl->qnt_loss_rate >= 0)
6285 atm->q[ctl->qnt_loss_rate][ip] += lambda;
6286 }
6287 if (ctl->qnt_vmr >= 0)
6288 atm->q[ctl->qnt_vmr][ip] *= aux;
6289 }
6290}
6291
6292/*****************************************************************************/
6293
6295 ctl_t **ctl,
6296 cache_t **cache,
6297 clim_t **clim,
6298 met_t **met0,
6299 met_t **met1,
6300 atm_t **atm,
6301 depo_t **depo,
6302 dd_t **dd) {
6303
6304 /* Initialize GPU... */
6305#ifdef _OPENACC
6306 if (ctl != NULL || cache != NULL || clim != NULL || met0 != NULL
6307 || met1 != NULL || atm != NULL || depo != NULL || dd != NULL) {
6308 SELECT_TIMER("ACC_INIT", "INIT");
6309 if (acc_get_num_devices(acc_device_nvidia) <= 0)
6310 ERRMSG("Not running on a GPU device!");
6311 acc_device_t device_type = acc_get_device_type();
6312 acc_init(device_type);
6313 }
6314#endif
6315
6316 /* Allocate... */
6317 SELECT_TIMER("ALLOC", "MEMORY");
6318 if (ctl != NULL)
6319 ALLOC(*ctl, ctl_t, 1);
6320 if (cache != NULL)
6321 ALLOC(*cache, cache_t, 1);
6322 if (clim != NULL)
6323 ALLOC(*clim, clim_t, 1);
6324 if (met0 != NULL)
6325 ALLOC(*met0, met_t, 1);
6326 if (met1 != NULL)
6327 ALLOC(*met1, met_t, 1);
6328 if (atm != NULL)
6329 ALLOC(*atm, atm_t, 1);
6330 if (depo != NULL)
6331 ALLOC(*depo, depo_t, 1);
6332 if (dd != NULL)
6333 ALLOC(*dd, dd_t, 1);
6334
6335 /* Create data region on GPU... */
6336#ifdef _OPENACC
6337 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY");
6338 if (ctl != NULL) {
6339 ctl_t *ctlup = *ctl;
6340#pragma acc enter data create(ctlup[:1])
6341 }
6342 if (cache != NULL) {
6343 cache_t *cacheup = *cache;
6344#pragma acc enter data create(cacheup[:1])
6345 }
6346 if (clim != NULL) {
6347 clim_t *climup = *clim;
6348#pragma acc enter data create(climup[:1])
6349 }
6350 if (met0 != NULL) {
6351 met_t *met0up = *met0;
6352#pragma acc enter data create(met0up[:1])
6353 }
6354 if (met1 != NULL) {
6355 met_t *met1up = *met1;
6356#pragma acc enter data create(met1up[:1])
6357 }
6358 if (atm != NULL) {
6359 atm_t *atmup = *atm;
6360#pragma acc enter data create(atmup[:1])
6361 }
6362 if (depo != NULL) {
6363 depo_t *depoup = *depo;
6364#pragma acc enter data create(depoup[:1])
6365 }
6366#ifdef DD
6367 if (dd != NULL) {
6368 dd_t *ddup = *dd;
6369#pragma acc enter data create(ddup[:1])
6370 }
6371#endif
6372#endif
6373}
6374
6375/*****************************************************************************/
6376
6378 ctl_t *ctl,
6379 cache_t *cache,
6380 clim_t *clim,
6381 met_t *met0,
6382 met_t *met1,
6383 atm_t *atm,
6384 depo_t *depo,
6385 dd_t *dd) {
6386
6387 /* Delete data region on GPU... */
6388#ifdef _OPENACC
6389 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY");
6390 if (ctl != NULL) {
6391#pragma acc exit data delete(ctl[:1])
6392 }
6393 if (cache != NULL) {
6394#pragma acc exit data delete(cache[:1])
6395 }
6396 if (clim != NULL) {
6397#pragma acc exit data delete(clim[:1])
6398 }
6399 if (met0 != NULL) {
6400#pragma acc exit data delete(met0[:1])
6401 }
6402 if (met1 != NULL) {
6403#pragma acc exit data delete(met1[:1])
6404 }
6405 if (atm != NULL) {
6406#pragma acc exit data delete(atm[:1])
6407 }
6408 if (depo != NULL) {
6409#pragma acc exit data delete(depo[:1])
6410 }
6411#ifdef DD
6412 if (dd != NULL) {
6413#pragma acc exit data delete(dd[:1])
6414 }
6415#endif
6416#endif
6417
6418 /* Free... */
6419 SELECT_TIMER("FREE", "MEMORY");
6420 free(atm);
6421 free(depo);
6422 free(ctl);
6423 free(cache);
6424 free(clim);
6425 free(met0);
6426 free(met1);
6427
6428 /* Free MPI datatype... */
6429#ifdef DD
6430 if (dd != NULL)
6431 MPI_Type_free(&dd->MPI_Particle);
6432#endif
6433 free(dd);
6434}
6435
6436/*****************************************************************************/
6437
6439 ctl_t *ctl,
6440 clim_t *clim,
6441 const double t,
6442 met_t **met0,
6443 met_t **met1,
6444 dd_t *dd) {
6445
6446 static int init;
6447
6448 met_t *mets;
6449
6450 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
6451
6452 /* Set timer... */
6453 SELECT_TIMER("GET_MET", "INPUT");
6454
6455 /* Init... */
6456 if (t == ctl->t_start || !init) {
6457 init = 1;
6458
6459 /* Read meteo data... */
6460 get_met_filename(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
6461 ctl->metbase, ctl->dt_met, filename);
6462 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
6463 ERRMSG("Cannot open file!");
6464
6465 get_met_filename(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
6466 ctl->metbase, ctl->dt_met, filename);
6467 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
6468 ERRMSG("Cannot open file!");
6469
6470 /* Update GPU... */
6471 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
6472 SELECT_TIMER("GET_MET", "INPUT");
6473
6474 /* Caching... */
6475 if (ctl->met_cache && t != ctl->t_stop) {
6476 get_met_filename(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
6477 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
6478 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6479 LOG(1, "Caching: %s", cachefile);
6480 if (system(cmd) != 0)
6481 WARN("Caching command failed!");
6482 }
6483 }
6484
6485 /* Read new data for forward trajectories... */
6486 if (t > (*met1)->time) {
6487
6488 /* Pointer swap... */
6489 mets = *met1;
6490 *met1 = *met0;
6491 *met0 = mets;
6492
6493 /* Read new meteo data... */
6494 get_met_filename(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
6495 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
6496 ERRMSG("Cannot open file!");
6497
6498 /* Update GPU... */
6499 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
6500 SELECT_TIMER("GET_MET", "INPUT");
6501
6502 /* Caching... */
6503 if (ctl->met_cache && t != ctl->t_stop) {
6504 get_met_filename(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
6505 cachefile);
6506 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6507 LOG(1, "Caching: %s", cachefile);
6508 if (system(cmd) != 0)
6509 WARN("Caching command failed!");
6510 }
6511 }
6512
6513 /* Read new data for backward trajectories... */
6514 if (t < (*met0)->time) {
6515
6516 /* Pointer swap... */
6517 mets = *met1;
6518 *met1 = *met0;
6519 *met0 = mets;
6520
6521 /* Read new meteo data... */
6522 get_met_filename(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
6523 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
6524 ERRMSG("Cannot open file!");
6525
6526 /* Update GPU... */
6527 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
6528 SELECT_TIMER("GET_MET", "INPUT");
6529
6530 /* Caching... */
6531 if (ctl->met_cache && t != ctl->t_stop) {
6532 get_met_filename(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
6533 cachefile);
6534 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6535 LOG(1, "Caching: %s", cachefile);
6536 if (system(cmd) != 0)
6537 WARN("Caching command failed!");
6538 }
6539 }
6540
6541 if ((*met0)->coord_type != (*met1)->coord_type)
6542 ERRMSG("Coordinate types do not match!");
6543
6544 /* Check that grids are consistent... */
6545 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
6546 if ((*met0)->nx != (*met1)->nx
6547 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
6548 ERRMSG("Meteo grid dimensions do not match!");
6549 for (int ix = 0; ix < (*met0)->nx; ix++)
6550 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
6551 ERRMSG("Meteo grid longitudes do not match!");
6552 for (int iy = 0; iy < (*met0)->ny; iy++)
6553 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
6554 ERRMSG("Meteo grid latitudes do not match!");
6555 for (int ip = 0; ip < (*met0)->np; ip++)
6556 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
6557 ERRMSG("Meteo grid pressure levels do not match!");
6558 }
6559}
6560
6561/*****************************************************************************/
6562
6564 ctl_t *ctl,
6565 cache_t *cache,
6566 clim_t *clim,
6567 atm_t *atm,
6568 depo_t *depo,
6569 const int ntask) {
6570
6571 /* Initialize timesteps... */
6572 module_timesteps_init(ctl, atm);
6573
6574 /* Initialize random number generator... */
6575 module_rng_init(ntask);
6576
6577 /* Update GPU memory... */
6578 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
6579#ifdef _OPENACC
6580#pragma acc update device(depo[:1])
6581#else
6582 (void) depo;
6583#endif
6584}
6585
6586/*****************************************************************************/
6587
6589 const char *filename,
6590 const ctl_t *ctl,
6591 atm_t *atm) {
6592
6593 int result;
6594
6595 /* Set timer... */
6596 SELECT_TIMER("READ_ATM", "INPUT");
6597
6598 /* Init... */
6599 atm->np = 0;
6600
6601 /* Write info... */
6602 LOG(1, "Read atmospheric data: %s", filename);
6603
6604 /* Read ASCII data... */
6605 if (ctl->atm_type == 0)
6606 result = read_atm_asc(filename, ctl, atm);
6607
6608 /* Read binary data... */
6609 else if (ctl->atm_type == 1)
6610 result = read_atm_bin(filename, ctl, atm);
6611
6612 /* Read netCDF data... */
6613 else if (ctl->atm_type == 2)
6614 result = read_atm_nc(filename, ctl, atm);
6615
6616 /* Read CLaMS data... */
6617 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
6618 result = read_atm_clams(filename, ctl, atm);
6619
6620 /* Error... */
6621 else
6622 ERRMSG("Atmospheric data type not supported!");
6623
6624 /* Check result... */
6625 if (result != 1)
6626 return 0;
6627
6628 /* Check number of air parcels... */
6629 if (atm->np < 1)
6630 ERRMSG("Can not read any data!");
6631
6632 /* Write info... */
6633 double mini, maxi;
6634 LOG(2, "Number of particles: %d", atm->np);
6635 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6636 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6637 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6638 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6639 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6640 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6641 LOG(2, "%s range: %g ... %g %s",
6642 ctl->met_coord_type == 0 ? "Longitude" : "X coordinate", mini, maxi,
6643 ctl->met_coord_type == 0 ? "deg" : "m");
6644 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6645 LOG(2, "%s range: %g ... %g %s",
6646 ctl->met_coord_type == 0 ? "Latitude" : "Y coordinate", mini, maxi,
6647 ctl->met_coord_type == 0 ? "deg" : "m");
6648 for (int iq = 0; iq < ctl->nq; iq++) {
6649 char msg[5 * LEN];
6650 sprintf(msg, "Quantity %s range: %s ... %s %s",
6651 ctl->qnt_name[iq], ctl->qnt_format[iq],
6652 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6653 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6654 LOG(2, msg, mini, maxi);
6655 }
6656
6657 /* Return success... */
6658 return 1;
6659}
6660
6661/*****************************************************************************/
6662
6664 const ctl_t *ctl,
6665 clim_t *clim) {
6666
6667 /* Set timer... */
6668 SELECT_TIMER("READ_CLIM", "INPUT");
6669
6670 /* Init tropopause climatology... */
6671 clim_tropo_init(clim);
6672
6673 /* Read photolysis rates... */
6674 if (ctl->clim_photo[0] != '-')
6675 read_clim_photo(ctl->clim_photo, &clim->photo);
6676
6677 /* Read HNO3 climatology... */
6678 if (ctl->clim_hno3_filename[0] != '-')
6679 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
6680
6681 /* Read OH climatology... */
6682 if (ctl->clim_oh_filename[0] != '-') {
6683 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
6684 if (ctl->oh_chem_beta > 0)
6685 clim_oh_diurnal_correction(ctl, clim);
6686 }
6687
6688 /* Read H2O2 climatology... */
6689 if (ctl->clim_h2o2_filename[0] != '-')
6690 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
6691
6692 /* Read HO2 climatology... */
6693 if (ctl->clim_ho2_filename[0] != '-')
6694 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
6695
6696 /* Read O(1D) climatology... */
6697 if (ctl->clim_o1d_filename[0] != '-')
6698 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
6699
6700 /* Read CFC-10 time series... */
6701 if (ctl->clim_ccl4_timeseries[0] != '-')
6703
6704 /* Read CFC-11 time series... */
6705 if (ctl->clim_ccl3f_timeseries[0] != '-')
6707
6708 /* Read CFC-12 time series... */
6709 if (ctl->clim_ccl2f2_timeseries[0] != '-')
6711
6712 /* Read N2O time series... */
6713 if (ctl->clim_n2o_timeseries[0] != '-')
6714 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
6715
6716 /* Read SF6 time series... */
6717 if (ctl->clim_sf6_timeseries[0] != '-')
6718 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
6719}
6720
6721/*****************************************************************************/
6722
6724 const char *filename,
6725 int argc,
6726 char *argv[],
6727 ctl_t *ctl) {
6728
6729 /* Set timer... */
6730 SELECT_TIMER("READ_CTL", "INPUT");
6731
6732 /* Write info... */
6733 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
6734 "(executable: %s | version: %s | compiled: %s, %s)\n",
6735 argv[0], VERSION, __DATE__, __TIME__);
6736
6737 /* Initialize quantity indices... */
6738 ctl->qnt_idx = -1;
6739 ctl->qnt_ens = -1;
6740 ctl->qnt_stat = -1;
6741 ctl->qnt_m = -1;
6742 ctl->qnt_vmr = -1;
6743 ctl->qnt_rp = -1;
6744 ctl->qnt_rhop = -1;
6745 ctl->qnt_ps = -1;
6746 ctl->qnt_ts = -1;
6747 ctl->qnt_zs = -1;
6748 ctl->qnt_us = -1;
6749 ctl->qnt_vs = -1;
6750 ctl->qnt_ess = -1;
6751 ctl->qnt_nss = -1;
6752 ctl->qnt_shf = -1;
6753 ctl->qnt_lsm = -1;
6754 ctl->qnt_sst = -1;
6755 ctl->qnt_pbl = -1;
6756 ctl->qnt_pt = -1;
6757 ctl->qnt_tt = -1;
6758 ctl->qnt_zt = -1;
6759 ctl->qnt_h2ot = -1;
6760 ctl->qnt_zg = -1;
6761 ctl->qnt_p = -1;
6762 ctl->qnt_t = -1;
6763 ctl->qnt_rho = -1;
6764 ctl->qnt_u = -1;
6765 ctl->qnt_v = -1;
6766 ctl->qnt_w = -1;
6767 ctl->qnt_h2o = -1;
6768 ctl->qnt_o3 = -1;
6769 ctl->qnt_lwc = -1;
6770 ctl->qnt_rwc = -1;
6771 ctl->qnt_iwc = -1;
6772 ctl->qnt_swc = -1;
6773 ctl->qnt_cc = -1;
6774 ctl->qnt_pct = -1;
6775 ctl->qnt_pcb = -1;
6776 ctl->qnt_cl = -1;
6777 ctl->qnt_plcl = -1;
6778 ctl->qnt_plfc = -1;
6779 ctl->qnt_pel = -1;
6780 ctl->qnt_cape = -1;
6781 ctl->qnt_cin = -1;
6782 ctl->qnt_o3c = -1;
6783 ctl->qnt_hno3 = -1;
6784 ctl->qnt_oh = -1;
6785 ctl->qnt_h2o2 = -1;
6786 ctl->qnt_ho2 = -1;
6787 ctl->qnt_o1d = -1;
6788 ctl->qnt_mloss_oh = -1;
6789 ctl->qnt_mloss_h2o2 = -1;
6790 ctl->qnt_mloss_kpp = -1;
6791 ctl->qnt_mloss_wet = -1;
6792 ctl->qnt_mloss_dry = -1;
6793 ctl->qnt_mloss_decay = -1;
6794 ctl->qnt_loss_rate = -1;
6795 ctl->qnt_psat = -1;
6796 ctl->qnt_psice = -1;
6797 ctl->qnt_pw = -1;
6798 ctl->qnt_sh = -1;
6799 ctl->qnt_rh = -1;
6800 ctl->qnt_rhice = -1;
6801 ctl->qnt_theta = -1;
6802 ctl->qnt_zeta = -1;
6803 ctl->qnt_zeta_d = -1;
6804 ctl->qnt_zeta_dot = -1;
6805 ctl->qnt_eta = -1;
6806 ctl->qnt_eta_dot = -1;
6807 ctl->qnt_tvirt = -1;
6808 ctl->qnt_lapse = -1;
6809 ctl->qnt_vh = -1;
6810 ctl->qnt_vz = -1;
6811 ctl->qnt_pv = -1;
6812 ctl->qnt_tdew = -1;
6813 ctl->qnt_tice = -1;
6814 ctl->qnt_tsts = -1;
6815 ctl->qnt_tnat = -1;
6816 ctl->qnt_Cx = -1;
6817 ctl->qnt_Ch2o = -1;
6818 ctl->qnt_Co3 = -1;
6819 ctl->qnt_Cco = -1;
6820 ctl->qnt_Coh = -1;
6821 ctl->qnt_Ch = -1;
6822 ctl->qnt_Cho2 = -1;
6823 ctl->qnt_Ch2o2 = -1;
6824 ctl->qnt_Co1d = -1;
6825 ctl->qnt_Co3p = -1;
6826 ctl->qnt_Cccl4 = -1;
6827 ctl->qnt_Cccl3f = -1;
6828 ctl->qnt_Cccl2f2 = -1;
6829 ctl->qnt_Cn2o = -1;
6830 ctl->qnt_Csf6 = -1;
6831 ctl->qnt_aoa = -1;
6832 ctl->qnt_Arn222 = -1;
6833 ctl->qnt_Apb210 = -1;
6834 ctl->qnt_Abe7 = -1;
6835 ctl->qnt_Acs137 = -1;
6836 ctl->qnt_Ai131 = -1;
6837 ctl->qnt_Axe133 = -1;
6838 ctl->qnt_current_subdomain = -1;
6839 ctl->qnt_target_subdomain = -1;
6840
6841 /* Read quantities... */
6842 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
6843 if (ctl->nq > NQ)
6844 ERRMSG("Too many quantities!");
6845 for (int iq = 0; iq < ctl->nq; iq++) {
6846
6847 /* Read quantity name and format... */
6848 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
6849 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
6850 ctl->qnt_longname[iq]);
6851 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
6852 ctl->qnt_format[iq]);
6853 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
6854 sprintf(ctl->qnt_format[iq], "%%.2f");
6855
6856 /* Try to identify quantity... */
6857 SET_QNT(qnt_idx, "idx", "particle index", "-")
6858 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
6859 SET_QNT(qnt_stat, "stat", "station flag", "-")
6860 SET_QNT(qnt_m, "m", "mass", "kg")
6861 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
6862 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
6863 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
6864 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
6865 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
6866 SET_QNT(qnt_zs, "zs", "surface height", "km")
6867 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
6868 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
6869 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
6870 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
6871 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
6872 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
6873 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
6874 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
6875 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
6876 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
6877 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
6878 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
6879 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
6880 SET_QNT(qnt_p, "p", "pressure", "hPa")
6881 SET_QNT(qnt_t, "t", "temperature", "K")
6882 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
6883 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
6884 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
6885 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
6886 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
6887 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
6888 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
6889 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
6890 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
6891 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
6892 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
6893 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
6894 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
6895 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
6896 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
6897 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
6898 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
6899 SET_QNT(qnt_cape, "cape", "convective available potential energy",
6900 "J/kg")
6901 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
6902 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
6903 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
6904 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
6905 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
6906 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
6907 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
6908 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
6909 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
6910 "mass loss due to H2O2 chemistry", "kg")
6911 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
6912 "kg")
6913 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
6914 "kg")
6915 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
6916 "kg")
6917 SET_QNT(qnt_mloss_decay, "mloss_decay",
6918 "mass loss due to exponential decay", "kg")
6919 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
6920 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
6921 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
6922 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
6923 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
6924 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
6925 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
6926 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
6927 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
6928 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
6929 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
6930 "K/day")
6931 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
6932 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
6933 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
6934 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
6935 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
6936 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
6937 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
6938 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
6939 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
6940 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
6941 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
6942 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
6943 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
6944 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
6945 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
6946 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
6947 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
6948 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
6949 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
6950 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
6951 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
6952 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
6953 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
6954 "ppv")
6955 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
6956 "ppv")
6957 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
6958 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
6959 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
6960 SET_QNT(qnt_Arn222, "Arn222", "Rn-222 activity", "Bq")
6961 SET_QNT(qnt_Apb210, "Apb210", "Pb-210 activity", "Bq")
6962 SET_QNT(qnt_Abe7, "Abe7", "Be-7 activity", "Bq")
6963 SET_QNT(qnt_Acs137, "Acs137", "Cs-137 activity", "Bq")
6964 SET_QNT(qnt_Ai131, "Ai131", "I-131 activity", "Bq")
6965 SET_QNT(qnt_Axe133, "Axe133", "Xe-133 activity", "Bq")
6966 SET_QNT(qnt_current_subdomain, "current_subdomain",
6967 "current subdomain rank", "-")
6968 SET_QNT(qnt_target_subdomain, "target_subdomain",
6969 "target subdomain rank", "-")
6970 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
6971 }
6972
6973 ctl->met_coord_type =
6974 (int) scan_ctl(filename, argc, argv, "MET_COORD_TYPE", -1, "0", NULL);
6975 if (ctl->met_coord_type < 0 || ctl->met_coord_type > 1)
6976 ERRMSG("MET_COORD_TYPE must be 0 or 1!");
6977 ctl->met_utm_ref_lat = 0.0;
6978 ctl->met_utm_ref_lon = 0.0;
6979 if (ctl->met_coord_type == 1) {
6980 ctl->met_utm_ref_lat =
6981 scan_ctl(filename, argc, argv, "MET_UTM_REF_LAT", -1, "", NULL);
6982 ctl->met_utm_ref_lon =
6983 scan_ctl(filename, argc, argv, "MET_UTM_REF_LON", -1, "", NULL);
6984 }
6985
6986 /* Vertical coordinate and velocity... */
6987 ctl->advect_vert_coord =
6988 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
6989 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
6990 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
6991
6992 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
6993 ERRMSG("Add quantity zeta for diabatic advection!");
6994 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
6995 ERRMSG("Add quantity eta for etadot avection!");
6996
6997 ctl->met_vert_coord =
6998 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
6999 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
7000 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
7001
7002 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
7003 ERRMSG
7004 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
7005 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
7006 ERRMSG
7007 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
7008
7009 ctl->met_gp2z =
7010 (int) scan_ctl(filename, argc, argv, "MET_GP2Z", -1, "0", NULL);
7011 if (ctl->met_gp2z != 0 && ctl->met_gp2z != 1)
7012 ERRMSG("Set MET_GP2Z to 0 or 1!");
7013
7014 /* Time steps of simulation... */
7015 ctl->direction =
7016 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
7017 if (ctl->direction != -1 && ctl->direction != 1)
7018 ERRMSG("Set DIRECTION to -1 or 1!");
7019 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
7020 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
7021
7022 /* Meteo data... */
7023 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
7024 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
7025 if (ctl->dt_mod > ctl->dt_met)
7026 ERRMSG("DT_MOD must not exceed DT_MET!");
7027 ctl->met_convention =
7028 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
7029 ctl->met_type =
7030 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
7031 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
7032 ERRMSG
7033 ("Please use meteo files in netcdf format for diabatic calculations.");
7034 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
7035 ERRMSG
7036 ("Please use meteo files in netcdf format for etadot calculations.");
7037 ctl->met_clams =
7038 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
7039 ctl->met_nc_scale =
7040 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
7041 ctl->met_nc_level =
7042 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
7043 ctl->met_nc_quant =
7044 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
7045 ctl->met_zstd_level =
7046 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "-3", NULL);
7047 ctl->met_zstd_nworkers =
7048 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_NWORKERS", -1, "4", NULL);
7049 ctl->met_lz4_accel =
7050 (int) scan_ctl(filename, argc, argv, "MET_LZ4_ACCEL", -1, "8", NULL);
7051 ctl->met_pck_zstd =
7052 (int) scan_ctl(filename, argc, argv, "MET_PCK_ZSTD", -1, "0", NULL);
7053 if (ctl->met_pck_zstd != 0 && ctl->met_pck_zstd != 1)
7054 ERRMSG("Set MET_PCK_ZSTD to 0 or 1!");
7055#ifndef ZSTD
7056 if (ctl->met_type == 2 && ctl->met_pck_zstd)
7057 ERRMSG("MET_PCK_ZSTD requires MPTRAC to be compiled with ZSTD support!");
7058#endif
7059 const int def_lossy_scale =
7060 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", -1, "0", NULL);
7061 for (int i = 0; i < METVAR; i++) {
7062 char defprec_zfp[LEN] = "7", deftol_zfp[LEN] = "0.0";
7063 char defprec_sz3[LEN] = "6", deftol_sz3[LEN] = "0.0";
7064 if (i == 0) { /* geopotential height */
7065 sprintf(defprec_zfp, "12");
7066 sprintf(defprec_sz3, "11");
7067 } else if (i == 1) { /* temperature */
7068 sprintf(defprec_zfp, "11");
7069 sprintf(defprec_sz3, "7");
7070 } else if (i == 2 || i == 3) { /* horizontal wind */
7071 sprintf(defprec_zfp, "7");
7072 sprintf(defprec_sz3, "7");
7073 } else if (i == 4) { /* vertical wind */
7074 sprintf(defprec_zfp, "6");
7075 sprintf(defprec_sz3, "13");
7076 } else if (i == 5) { /* potential vorticity */
7077 sprintf(defprec_zfp, "7");
7078 sprintf(defprec_sz3, "20");
7079 } else if (i == 6) { /* water vapor */
7080 sprintf(defprec_zfp, "10");
7081 sprintf(defprec_sz3, "18");
7082 } else if (i == 7) { /* ozone */
7083 sprintf(defprec_zfp, "9");
7084 sprintf(defprec_sz3, "10");
7085 } else if (i >= 8 && i <= 11) { /* cloud water fields */
7086 sprintf(defprec_zfp, "6");
7087 sprintf(defprec_sz3, "13");
7088 } else if (i == 12) { /* cloud cover */
7089 sprintf(defprec_zfp, "9");
7090 sprintf(defprec_sz3, "6");
7091 }
7092 ctl->met_zfp_prec[i] =
7093 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", i, defprec_zfp,
7094 NULL);
7095 ctl->met_zfp_tol[i] =
7096 scan_ctl(filename, argc, argv, "MET_ZFP_TOL", i, deftol_zfp, NULL);
7097 ctl->met_sz3_prec[i] =
7098 (int) scan_ctl(filename, argc, argv, "MET_SZ3_PREC", i, defprec_sz3,
7099 NULL);
7100 ctl->met_sz3_tol[i] =
7101 scan_ctl(filename, argc, argv, "MET_SZ3_TOL", i, deftol_sz3, NULL);
7102 char defscale[LEN];
7103 snprintf(defscale, LEN, "%d", def_lossy_scale);
7104 ctl->met_lossy_scale[i] =
7105 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", i, defscale,
7106 NULL);
7107 if (ctl->met_lossy_scale[i] < 0 || ctl->met_lossy_scale[i] > 1)
7108 ERRMSG("Set MET_LOSSY_SCALE to 0 or 1!");
7109 }
7110
7111 /* Scan compression diagnostics file... */
7112 scan_ctl(filename, argc, argv, "MET_COMP_LOGFILE", -1, "-",
7113 ctl->met_comp_logfile);
7114 ctl->met_cms_batch =
7115 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
7116 ctl->met_cms_zstd =
7117 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
7118 ctl->met_cms_nd0x =
7119 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0X", -1, "48", NULL);
7120 ctl->met_cms_nd0y =
7121 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0Y", -1, "24", NULL);
7122 ctl->met_cms_maxlev =
7123 (int) scan_ctl(filename, argc, argv, "MET_CMS_MAXLEV", -1, "6", NULL);
7124 for (int i = 0; i < METVAR; i++) {
7125 char defeps[LEN] = "1.0";
7126 if (i == 1 || i == 2 || i == 3)
7127 sprintf(defeps, "0.05");
7128 ctl->met_cms_eps[i] =
7129 scan_ctl(filename, argc, argv, "MET_CMS_EPS", i, defeps, NULL);
7130 }
7131 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
7132 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
7133 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
7134 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
7135 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
7136 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
7137 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
7138 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
7139 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
7140 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
7141 ctl->met_detrend =
7142 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
7143 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
7144 if (ctl->met_np > EP)
7145 ERRMSG("Too many pressure levels!");
7146 ctl->met_press_level_def =
7147 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
7148 NULL);
7149 if (ctl->met_press_level_def >= 0) {
7150 level_definitions(ctl);
7151 } else {
7152 if (ctl->met_np > 0) {
7153 for (int ip = 0; ip < ctl->met_np; ip++)
7154 ctl->met_p[ip] =
7155 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
7156 }
7157 }
7158 ctl->met_nlev =
7159 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
7160 if (ctl->met_nlev > EP)
7161 ERRMSG("Too many model levels!");
7162 for (int ip = 0; ip < ctl->met_nlev; ip++)
7163 ctl->met_lev_hyam[ip] =
7164 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
7165 for (int ip = 0; ip < ctl->met_nlev; ip++)
7166 ctl->met_lev_hybm[ip] =
7167 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
7168 ctl->met_geopot_sx =
7169 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
7170 ctl->met_geopot_sy =
7171 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
7172 ctl->met_relhum =
7173 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
7174 ctl->met_cape =
7175 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
7176 if (ctl->met_cape < 0 || ctl->met_cape > 1)
7177 ERRMSG("Set MET_CAPE to 0 or 1!");
7178 ctl->met_pbl =
7179 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
7180 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
7181 ERRMSG("Set MET_PBL to 0 ... 3!");
7182 ctl->met_pbl_min =
7183 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
7184 ctl->met_pbl_max =
7185 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
7186 ctl->met_tropo =
7187 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
7188 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
7189 ERRMSG("Set MET_TROPO to 0 ... 5!");
7190 ctl->met_tropo_pv =
7191 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
7192 ctl->met_tropo_theta =
7193 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
7194 ctl->met_tropo_spline =
7195 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
7196 ctl->met_dt_out =
7197 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
7198 ctl->met_cache =
7199 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
7200 ctl->met_mpi_share =
7201 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
7202
7203 /* Sorting... */
7204 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
7205
7206 /* Isosurface parameters... */
7207 ctl->isosurf =
7208 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
7209 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
7210
7211 /* Random number generator... */
7212 ctl->rng_type =
7213 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
7214 if (ctl->rng_type < 0 || ctl->rng_type > 2)
7215 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
7216
7217 /* Advection parameters... */
7218 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
7219 if (!(ctl->advect == 1 || ctl->advect == 2 || ctl->advect == 4))
7220 ERRMSG("Set ADVECT to 1, 2, or 4!");
7221
7222 /* Diffusion parameters... */
7223 ctl->diffusion
7224 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
7225 if (ctl->diffusion < 0 || ctl->diffusion > 1)
7226 ERRMSG("Set DIFFUSION to 0 or 1!");
7227 ctl->turb_pbl_scheme =
7228 (int) scan_ctl(filename, argc, argv, "TURB_PBL_SCHEME", -1, "0", NULL);
7229 if (ctl->turb_pbl_scheme < 0 || ctl->turb_pbl_scheme > 1)
7230 ERRMSG("Set TURB_PBL_SCHEME to 0 or 1!");
7231 ctl->turb_dx_pbl =
7232 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
7233 ctl->turb_dx_trop =
7234 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
7235 ctl->turb_dx_strat =
7236 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
7237 ctl->turb_dz_pbl =
7238 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
7239 ctl->turb_dz_trop =
7240 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
7241 ctl->turb_dz_strat =
7242 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
7243 ctl->turb_mesox =
7244 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
7245 ctl->turb_mesoz =
7246 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
7247 ctl->turb_pbl_trans =
7248 scan_ctl(filename, argc, argv, "TURB_PBL_TRANS", -1, "0", NULL);
7249 if (ctl->turb_pbl_trans < 0 || ctl->turb_pbl_trans > 1)
7250 ERRMSG("TURB_PBL_TRANS must be in the range [0, 1]!");
7251
7252 /* Convection... */
7253 ctl->conv_mix_pbl
7254 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
7255 ctl->conv_pbl_trans
7256 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
7257 if (ctl->conv_pbl_trans < 0 || ctl->conv_pbl_trans > 1)
7258 ERRMSG("CONV_PBL_TRANS must be in the range [0, 1]!");
7259 ctl->conv_cape
7260 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
7261 ctl->conv_cin
7262 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
7263 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
7264
7265 /* Boundary conditions... */
7266 ctl->bound_mass =
7267 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
7268 ctl->bound_mass_trend =
7269 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
7270 ctl->bound_vmr =
7271 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
7272 ctl->bound_vmr_trend =
7273 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
7274 ctl->bound_lat0 =
7275 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
7276 ctl->bound_lat1 =
7277 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
7278 ctl->bound_p0 =
7279 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
7280 ctl->bound_p1 =
7281 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
7282 ctl->bound_dps =
7283 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
7284 ctl->bound_dzs =
7285 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
7286 ctl->bound_zetas =
7287 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
7288 ctl->bound_pbl =
7289 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
7290
7291 /* Species parameters... */
7292 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
7293 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
7294 ctl->molmass = 120.907;
7295 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
7296 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
7297 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
7298 ctl->molmass = 137.359;
7299 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
7300 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
7301 } else if (strcasecmp(ctl->species, "CH4") == 0) {
7302 ctl->molmass = 16.043;
7303 ctl->oh_chem_reaction = 2;
7304 ctl->oh_chem[0] = 2.45e-12;
7305 ctl->oh_chem[1] = 1775;
7306 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
7307 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
7308 } else if (strcasecmp(ctl->species, "CO") == 0) {
7309 ctl->molmass = 28.01;
7310 ctl->oh_chem_reaction = 3;
7311 ctl->oh_chem[0] = 6.9e-33;
7312 ctl->oh_chem[1] = 2.1;
7313 ctl->oh_chem[2] = 1.1e-12;
7314 ctl->oh_chem[3] = -1.3;
7315 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
7316 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
7317 } else if (strcasecmp(ctl->species, "CO2") == 0) {
7318 ctl->molmass = 44.009;
7319 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
7320 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
7321 } else if (strcasecmp(ctl->species, "H2O") == 0) {
7322 ctl->molmass = 18.01528;
7323 } else if (strcasecmp(ctl->species, "N2O") == 0) {
7324 ctl->molmass = 44.013;
7325 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
7326 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
7327 } else if (strcasecmp(ctl->species, "NH3") == 0) {
7328 ctl->molmass = 17.031;
7329 ctl->oh_chem_reaction = 2;
7330 ctl->oh_chem[0] = 1.7e-12;
7331 ctl->oh_chem[1] = 710;
7332 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
7333 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
7334 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
7335 ctl->molmass = 63.012;
7336 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
7337 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
7338 } else if (strcasecmp(ctl->species, "NO") == 0) {
7339 ctl->molmass = 30.006;
7340 ctl->oh_chem_reaction = 3;
7341 ctl->oh_chem[0] = 7.1e-31;
7342 ctl->oh_chem[1] = 2.6;
7343 ctl->oh_chem[2] = 3.6e-11;
7344 ctl->oh_chem[3] = 0.1;
7345 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
7346 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
7347 } else if (strcasecmp(ctl->species, "NO2") == 0) {
7348 ctl->molmass = 46.005;
7349 ctl->oh_chem_reaction = 3;
7350 ctl->oh_chem[0] = 1.8e-30;
7351 ctl->oh_chem[1] = 3.0;
7352 ctl->oh_chem[2] = 2.8e-11;
7353 ctl->oh_chem[3] = 0.0;
7354 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
7355 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
7356 } else if (strcasecmp(ctl->species, "O3") == 0) {
7357 ctl->molmass = 47.997;
7358 ctl->oh_chem_reaction = 2;
7359 ctl->oh_chem[0] = 1.7e-12;
7360 ctl->oh_chem[1] = 940;
7361 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
7362 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
7363 } else if (strcasecmp(ctl->species, "SF6") == 0) {
7364 ctl->molmass = 146.048;
7365 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
7366 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
7367 } else if (strcasecmp(ctl->species, "SO2") == 0) {
7368 ctl->molmass = 64.066;
7369 ctl->oh_chem_reaction = 3;
7370 ctl->oh_chem[0] = 2.9e-31;
7371 ctl->oh_chem[1] = 4.1;
7372 ctl->oh_chem[2] = 1.7e-12;
7373 ctl->oh_chem[3] = -0.2;
7374 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = SO2_HENRY_REF;
7375 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = SO2_HENRY_TEMP;
7376 }
7377
7378 /* Molar mass... */
7379 char defstr[LEN];
7380 sprintf(defstr, "%g", ctl->molmass);
7381 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
7382
7383 /* OH chemistry... */
7384 sprintf(defstr, "%d", ctl->oh_chem_reaction);
7385 ctl->oh_chem_reaction =
7386 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
7387 NULL);
7388 for (int ip = 0; ip < 4; ip++) {
7389 sprintf(defstr, "%g", ctl->oh_chem[ip]);
7390 ctl->oh_chem[ip] =
7391 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
7392 }
7393 ctl->oh_chem_beta =
7394 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
7395
7396 /* H2O2 chemistry... */
7397 ctl->h2o2_chem_reaction =
7398 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
7399
7400 /* KPP chemistry... */
7401 ctl->kpp_chem =
7402 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
7403 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
7404
7405 /* First order tracer chemistry... */
7406 ctl->tracer_chem =
7407 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
7408
7409 /* Radioactive decay... */
7410 ctl->radio_decay =
7411 (int) scan_ctl(filename, argc, argv, "RADIO_DECAY", -1, "0", NULL);
7412 ctl->radio_depo =
7413 (int) scan_ctl(filename, argc, argv, "RADIO_DEPO", -1, "0", NULL);
7414 if (ctl->radio_depo && ctl->met_coord_type != 0)
7415 ERRMSG("Radioactive deposition requires a lat/lon meteorological grid!");
7416#ifdef DD
7417 if (ctl->radio_depo)
7418 ERRMSG
7419 ("Radioactive deposition is not supported with domain decomposition!");
7420#endif
7421
7422 /* Wet deposition... */
7423 for (int ip = 0; ip < 2; ip++) {
7424 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
7425 ctl->wet_depo_ic_h[ip] =
7426 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
7427 }
7428 for (int ip = 0; ip < 1; ip++) {
7429 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
7430 ctl->wet_depo_bc_h[ip] =
7431 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
7432 }
7433 ctl->wet_depo_so2_ph =
7434 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
7435 ctl->wet_depo_ic_a =
7436 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
7437 ctl->wet_depo_ic_b =
7438 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
7439 ctl->wet_depo_bc_a =
7440 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
7441 ctl->wet_depo_bc_b =
7442 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
7443 ctl->wet_depo_pre[0] =
7444 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
7445 ctl->wet_depo_pre[1] =
7446 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
7448 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
7450 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
7451
7452 /* Dry deposition... */
7453 ctl->dry_depo_vdep =
7454 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
7455 ctl->dry_depo_dp =
7456 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
7457
7458 /* Climatological data... */
7459 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
7460 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
7461 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
7462 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
7463 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
7464 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
7465 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
7466 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
7467 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
7468 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
7469 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
7470 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
7471 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
7472 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
7473 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
7474 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
7475 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
7476 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
7477 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
7478 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
7479 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
7480 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
7481
7482 /* Mixing... */
7483 ctl->mixing_dt =
7484 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
7485 ctl->mixing_trop =
7486 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
7487 ctl->mixing_strat =
7488 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
7489 ctl->mixing_z0 =
7490 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
7491 ctl->mixing_z1 =
7492 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
7493 ctl->mixing_nz =
7494 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
7495 ctl->mixing_lon0 =
7496 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
7497 ctl->mixing_lon1 =
7498 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
7499 ctl->mixing_nx =
7500 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
7501 ctl->mixing_lat0 =
7502 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
7503 ctl->mixing_lat1 =
7504 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
7505 ctl->mixing_ny =
7506 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
7507 if (ctl->mixing_nx < 1 || ctl->mixing_ny < 1 || ctl->mixing_nz < 1
7508 || ctl->mixing_lon0 >= ctl->mixing_lon1
7509 || ctl->mixing_lat0 >= ctl->mixing_lat1
7510 || ctl->mixing_z0 >= ctl->mixing_z1
7511 || ctl->mixing_lat0 < -90 || ctl->mixing_lat1 > 90)
7512 ERRMSG("Invalid mixing grid!");
7513
7514 /* Chemistry grid... */
7515 ctl->chemgrid_z0 =
7516 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
7517 ctl->chemgrid_z1 =
7518 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
7519 ctl->chemgrid_nz =
7520 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
7521 ctl->chemgrid_lon0 =
7522 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
7523 ctl->chemgrid_lon1 =
7524 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
7525 ctl->chemgrid_nx =
7526 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
7527 ctl->chemgrid_lat0 =
7528 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
7529 ctl->chemgrid_lat1 =
7530 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
7531 ctl->chemgrid_ny =
7532 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
7533 if (ctl->chemgrid_nx < 1 || ctl->chemgrid_ny < 1 || ctl->chemgrid_nz < 1
7534 || ctl->chemgrid_lon0 >= ctl->chemgrid_lon1
7535 || ctl->chemgrid_lat0 >= ctl->chemgrid_lat1
7536 || ctl->chemgrid_z0 >= ctl->chemgrid_z1
7537 || ctl->chemgrid_lat0 < -90 || ctl->chemgrid_lat1 > 90)
7538 ERRMSG("Invalid chemistry grid!");
7539
7540 /* Exponential decay... */
7541 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
7542 ctl->tdec_strat =
7543 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
7544
7545 /* PSC analysis... */
7546 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
7547 ctl->psc_hno3 =
7548 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
7549
7550 /* Output of atmospheric data... */
7551 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
7552 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
7553 ctl->atm_dt_out =
7554 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
7555 ctl->atm_filter =
7556 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
7557 ctl->atm_stride =
7558 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
7559 ctl->atm_type =
7560 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
7561 ctl->atm_type_out =
7562 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
7563 if (ctl->atm_type_out == -1)
7564 ctl->atm_type_out = ctl->atm_type;
7565 ctl->atm_nc_level =
7566 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
7567 for (int iq = 0; iq < ctl->nq; iq++)
7568 ctl->atm_nc_quant[iq] =
7569 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
7570 ctl->obs_type =
7571 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
7572
7573 /* Output of radioactive deposition data... */
7574 scan_ctl(filename, argc, argv, "DEPO_BASENAME", -1, "-",
7575 ctl->depo_basename);
7576 ctl->depo_dt_out =
7577 scan_ctl(filename, argc, argv, "DEPO_DT_OUT", -1, "86400", NULL);
7578 ctl->depo_type =
7579 (int) scan_ctl(filename, argc, argv, "DEPO_TYPE", -1, "0", NULL);
7580
7581 /* Output of CSI data... */
7582 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
7583 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
7584 ctl->csi_dt_out =
7585 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
7586 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
7587 ctl->csi_obsmin =
7588 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
7589 ctl->csi_modmin =
7590 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
7591 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
7592 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
7593 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
7594 ctl->csi_lon0 =
7595 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
7596 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
7597 ctl->csi_nx =
7598 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
7599 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
7600 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
7601 ctl->csi_ny =
7602 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
7603 if (ctl->csi_nx < 1 || ctl->csi_ny < 1 || ctl->csi_nz < 1
7604 || ctl->csi_lon0 >= ctl->csi_lon1
7605 || ctl->csi_lat0 >= ctl->csi_lat1 || ctl->csi_z0 >= ctl->csi_z1
7606 || ctl->csi_lat0 < -90 || ctl->csi_lat1 > 90)
7607 ERRMSG("Invalid CSI grid!");
7608
7609 /* Output of ensemble data... */
7610 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
7611 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
7612 ctl->ens_dt_out =
7613 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
7614
7615 /* Output of grid data... */
7616 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
7617 ctl->grid_basename);
7618 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
7619 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
7620 ctl->grid_dt_out =
7621 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
7622 ctl->grid_sparse =
7623 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
7624 ctl->grid_nc_level =
7625 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
7626 for (int iq = 0; iq < ctl->nq; iq++)
7627 ctl->grid_nc_quant[iq] =
7628 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
7629 ctl->grid_stddev =
7630 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
7631 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
7632 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
7633 ctl->grid_nz =
7634 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
7635 ctl->grid_lon0 =
7636 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
7637 ctl->grid_lon1 =
7638 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
7639 ctl->grid_nx =
7640 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
7641 ctl->grid_lat0 =
7642 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
7643 ctl->grid_lat1 =
7644 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
7645 ctl->grid_ny =
7646 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
7647 ctl->grid_type =
7648 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
7649 if (ctl->grid_nx < 1 || ctl->grid_nx > EX
7650 || ctl->grid_ny < 1 || ctl->grid_ny > EY || ctl->grid_nz < 1)
7651 ERRMSG("Invalid output grid dimensions!");
7652 if (ctl->grid_lon0 >= ctl->grid_lon1
7653 || ctl->grid_lat0 >= ctl->grid_lat1 || ctl->grid_z0 >= ctl->grid_z1
7654 || ctl->grid_lat0 < -90 || ctl->grid_lat1 > 90)
7655 ERRMSG("Invalid output grid boundaries!");
7656 if (ctl->depo_basename[0] != '-'
7657 && (ctl->depo_dt_out <= 0 || ctl->depo_type < 0 || ctl->depo_type > 1))
7658 ERRMSG("Invalid radioactive deposition output settings!");
7659
7660 /* Output of profile data... */
7661 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
7662 ctl->prof_basename);
7663 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
7664 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
7665 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
7666 ctl->prof_nz =
7667 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
7668 ctl->prof_lon0 =
7669 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
7670 ctl->prof_lon1 =
7671 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
7672 ctl->prof_nx =
7673 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
7674 ctl->prof_lat0 =
7675 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
7676 ctl->prof_lat1 =
7677 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
7678 ctl->prof_ny =
7679 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
7680 if (ctl->prof_nx < 1 || ctl->prof_ny < 1 || ctl->prof_nz < 1
7681 || ctl->prof_lon0 >= ctl->prof_lon1
7682 || ctl->prof_lat0 >= ctl->prof_lat1 || ctl->prof_z0 >= ctl->prof_z1
7683 || ctl->prof_lat0 < -90 || ctl->prof_lat1 > 90)
7684 ERRMSG("Invalid profile grid!");
7685
7686 /* Output of sample data... */
7687 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
7688 ctl->sample_basename);
7689 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
7690 ctl->sample_kernel);
7691 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
7692 ctl->sample_obsfile);
7693 ctl->sample_dx =
7694 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
7695 ctl->sample_dz =
7696 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
7697
7698 /* Output of station data... */
7699 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
7700 ctl->stat_basename);
7701 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
7702 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
7703 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
7704 ctl->stat_t0 =
7705 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
7706 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
7707
7708 /* Output of VTK data... */
7709 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
7710 ctl->vtk_dt_out =
7711 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
7712 ctl->vtk_stride =
7713 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
7714 ctl->vtk_scale =
7715 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
7716 ctl->vtk_offset =
7717 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
7718 ctl->vtk_sphere =
7719 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
7720
7721 /* Domain decomposition... */
7722#ifdef DD
7723 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "1", NULL);
7724#else
7725 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
7726#endif
7727
7729 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
7730 (ctl->dd == 1) ? "2" : "1", NULL);
7731 ctl->dd_subdomains_zonal =
7732 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
7733 (ctl->dd == 1) ? "2" : "1", NULL);
7734 ctl->dd_halos_size =
7735 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
7736 ctl->dd_sort_dt =
7737 (double) scan_ctl(filename, argc, argv, "DD_SORT_DT", -1, "1800", NULL);
7738}
7739
7740/*****************************************************************************/
7741
7743 const char *filename,
7744 const ctl_t *ctl,
7745 const clim_t *clim,
7746 met_t *met,
7747 dd_t *dd) {
7748
7749 /* Write info... */
7750 LOG(1, "Read meteo data: %s", filename);
7751
7752 /* Set rank... */
7753 int rank = 0;
7754#ifdef MPI
7755 if (ctl->met_mpi_share)
7756 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
7757#endif
7758
7759 /* Check rank... */
7760 if (!ctl->met_mpi_share || rank == 0) {
7761
7762 /* Read netCDF data... */
7763 if (ctl->met_type == 0) {
7764 if (read_met_nc(filename, ctl, met, dd) != 1)
7765 return 0;
7766 }
7767
7768 /* Read binary data... */
7769 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
7770 || ctl->met_type == 7 || ctl->met_type == 8) {
7771 if (read_met_bin(filename, ctl, met) != 1)
7772 return 0;
7773 }
7774#ifdef ECCODES
7775 /* Read grib data... */
7776 else if (ctl->met_type == 6) {
7777 if (read_met_grib(filename, ctl, met) != 1)
7778 return 0;
7779 }
7780#endif
7781
7782 /* Not implemented... */
7783 else
7784 ERRMSG("MET_TYPE not implemented!");
7785
7786 /* Preprocessing for netCDF and grib files... */
7787 if (ctl->met_type == 0 || ctl->met_type == 6) {
7788
7789 /* Extrapolate data for lower boundary... */
7791
7792 /* Fix polar winds... */
7794
7795 /* Create periodic boundary conditions... */
7796#ifndef DD
7797 read_met_periodic(met);
7798#endif
7799
7800 /* Downsampling... */
7801 read_met_sample(ctl, met);
7802
7803 /* Calculate geopotential heights... */
7804 read_met_geopot(ctl, met);
7805
7806 /* Calculate potential vorticity... */
7807 read_met_pv(met);
7808
7809 /* Calculate boundary layer data... */
7810 read_met_pbl(ctl, met);
7811
7812 /* Calculate tropopause data... */
7813 read_met_tropo(ctl, clim, met);
7814
7815 /* Calculate cloud properties... */
7816 read_met_cloud(met);
7817
7818 /* Calculate convective available potential energy... */
7819 read_met_cape(ctl, clim, met);
7820
7821 /* Calculate total column ozone... */
7822 read_met_ozone(met);
7823
7824 /* Detrending... */
7825 read_met_detrend(ctl, met);
7826
7827 /* Check meteo data and smooth zeta profiles ... */
7828 read_met_monotonize(ctl, met);
7829 }
7830 }
7831
7832 /* Broadcast data via MPI... */
7833#ifdef MPI
7834 if (ctl->met_mpi_share) {
7835
7836 /* Set timer... */
7837 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM");
7838 LOG(2, "Broadcast data on rank %d...", rank);
7839
7840 /* Broadcast... */
7841 broadcast_large_data(met, sizeof(met_t));
7842 }
7843#endif
7844
7845 /* Return success... */
7846 return 1;
7847}
7848
7849/*****************************************************************************/
7850
7852 ctl_t *ctl,
7853 cache_t *cache,
7854 clim_t *clim,
7855 met_t **met0,
7856 met_t **met1,
7857 atm_t *atm,
7858 depo_t *depo,
7859 double t,
7860 dd_t *dd) {
7861
7862 /* Initialize modules... */
7863 if (t == ctl->t_start) {
7864
7865 /* Initialize isosurface data... */
7866 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7867 module_isosurf_init(ctl, cache, *met0, *met1, atm);
7868
7869 /* Initialize advection... */
7870 module_advect_init(ctl, cache, *met0, *met1, atm);
7871
7872 /* Initialize chemistry... */
7873 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
7874 }
7875
7876 /* Set time steps of air parcels... */
7877 module_timesteps(ctl, cache, *met0, atm, t);
7878
7879 /* Sort particles... */
7880 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
7881 module_sort(ctl, *met0, atm);
7882
7883 /* Check positions (initial)... */
7884 module_position(cache, *met0, *met1, atm);
7885
7886 /* Advection... */
7887 if (ctl->advect > 0)
7888 module_advect(ctl, cache, *met0, *met1, atm);
7889
7890 /* Turbulent diffusion... */
7891 if (ctl->diffusion
7892 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
7893 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
7894 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
7895 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
7896
7897 /* Optional PBL-specific diffusion scheme... */
7898 if (ctl->diffusion && ctl->turb_pbl_scheme == 1)
7899 module_diff_pbl(ctl, cache, *met0, *met1, atm);
7900
7901 /* Mesoscale diffusion... */
7902 if (ctl->diffusion && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
7903 module_diff_meso(ctl, cache, *met0, *met1, atm);
7904
7905 /* Convection... */
7906 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
7907 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
7908 module_convection(ctl, cache, *met0, *met1, atm);
7909
7910 /* Sedimentation... */
7911 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
7912 module_sedi(ctl, cache, *met0, *met1, atm);
7913
7914 /* Isosurface... */
7915 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7916 module_isosurf(ctl, cache, *met0, *met1, atm);
7917
7918 /* Check positions (final)... */
7919 module_position(cache, *met0, *met1, atm);
7920
7921 /* Interpolate meteo data... */
7922 if (ctl->met_dt_out > 0
7923 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
7924 module_meteo(ctl, cache, clim, *met0, *met1, atm);
7925
7926 /* Check boundary conditions (initial)... */
7927 if ((ctl->bound_lat0 < ctl->bound_lat1)
7928 && (ctl->bound_p0 > ctl->bound_p1))
7929 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
7930
7931 /* Initialize quantity of total loss rate... */
7932 if (ctl->qnt_loss_rate >= 0) {
7933 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
7934 atm->q[ctl->qnt_loss_rate][ip] = 0;
7935 }
7936 }
7937
7938 /* Decay of particle mass... */
7939 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
7940 module_decay(ctl, cache, clim, atm);
7941
7942 /* Interparcel mixing... */
7943 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
7944 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
7945 module_mixing(ctl, clim, atm, t);
7946
7947 /* Calculate the tracer vmr in the chemistry grid... */
7948 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
7949 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
7950 module_chem_grid(ctl, *met0, *met1, atm, t);
7951
7952 /* OH chemistry... */
7953 if (ctl->oh_chem_reaction != 0)
7954 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
7955
7956 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
7957 if (ctl->h2o2_chem_reaction != 0)
7958 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
7959
7960 /* First-order tracer chemistry... */
7961 if (ctl->tracer_chem)
7962 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
7963
7964 /* Radioactive decay... */
7965 if (ctl->radio_decay)
7966 module_radio_decay(ctl, cache, atm);
7967
7968 /* Domain decomposition... */
7969#ifdef DD
7970 module_dd(t, ctl, cache, dd, atm, met0);
7971#else
7972 (void) dd;
7973#endif
7974
7975 /* Radioactive deposition... */
7976 if (ctl->radio_depo)
7977 module_radio_depo(ctl, cache, *met0, *met1, atm, depo);
7978
7979 /* KPP chemistry... */
7980 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
7981#ifdef KPP
7982 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
7983#else
7984 ERRMSG("Code was compiled without KPP!");
7985#endif
7986 }
7987
7988 /* Wet deposition... */
7989 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
7990 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
7991 module_wet_depo(ctl, cache, *met0, *met1, atm);
7992
7993 /* Dry deposition... */
7994 if (ctl->dry_depo_vdep > 0)
7995 module_dry_depo(ctl, cache, *met0, *met1, atm);
7996
7997 /* Check boundary conditions (final)... */
7998 if ((ctl->bound_lat0 < ctl->bound_lat1)
7999 && (ctl->bound_p0 > ctl->bound_p1))
8000 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
8001}
8002
8003/*****************************************************************************/
8004
8006 const ctl_t *ctl,
8007 const cache_t *cache,
8008 const clim_t *clim,
8009 met_t **met0,
8010 met_t **met1,
8011 const atm_t *atm) {
8012
8013 /* Update GPU... */
8014 if (ctl != NULL) {
8015#ifdef _OPENACC
8016 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8017#pragma acc update device(ctl[:1])
8018#endif
8019 }
8020
8021 if (cache != NULL) {
8022#ifdef _OPENACC
8023 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8024#pragma acc update device(cache[:1])
8025#endif
8026 }
8027
8028 if (clim != NULL) {
8029#ifdef _OPENACC
8030 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8031#pragma acc update device(clim[:1])
8032#endif
8033 }
8034
8035 if (met0 != NULL) {
8036#ifdef _OPENACC
8037 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8038 met_t *met0up = *met0;
8039#pragma acc update device(met0up[:1])
8040#endif
8041 }
8042
8043 if (met1 != NULL) {
8044#ifdef _OPENACC
8045 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8046 met_t *met1up = *met1;
8047#pragma acc update device(met1up[:1])
8048#endif
8049 }
8050
8051 if (atm != NULL) {
8052#ifdef _OPENACC
8053 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
8054#pragma acc update device(atm[:1])
8055#endif
8056 }
8057}
8058
8059/*****************************************************************************/
8060
8062 const ctl_t *ctl,
8063 const cache_t *cache,
8064 const clim_t *clim,
8065 met_t **met0,
8066 met_t **met1,
8067 const atm_t *atm) {
8068
8069 /* Update GPU... */
8070 if (ctl != NULL) {
8071#ifdef _OPENACC
8072 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8073#pragma acc update host(ctl[:1])
8074#endif
8075 }
8076
8077 if (cache != NULL) {
8078#ifdef _OPENACC
8079 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8080#pragma acc update host(cache[:1])
8081#endif
8082 }
8083
8084 if (clim != NULL) {
8085#ifdef _OPENACC
8086 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8087#pragma acc update host(clim[:1])
8088#endif
8089 }
8090
8091 if (met0 != NULL) {
8092#ifdef _OPENACC
8093 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8094 met_t *met0up = *met0;
8095#pragma acc update host(met0up[:1])
8096#endif
8097 }
8098
8099 if (met1 != NULL) {
8100#ifdef _OPENACC
8101 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8102 met_t *met1up = *met1;
8103#pragma acc update host(met1up[:1])
8104#endif
8105 }
8106
8107 if (atm != NULL) {
8108#ifdef _OPENACC
8109 SELECT_TIMER("UPDATE_HOST", "MEMORY");
8110#pragma acc update host(atm[:1])
8111#endif
8112 }
8113}
8114
8115/*****************************************************************************/
8116
8118 const char *filename,
8119 const ctl_t *ctl,
8120 const atm_t *atm,
8121 const double t) {
8122
8123 /* Set timer... */
8124 SELECT_TIMER("WRITE_ATM", "OUTPUT");
8125
8126 /* Write info... */
8127 LOG(1, "Write atmospheric data: %s", filename);
8128
8129 /* Write ASCII data... */
8130 if (ctl->atm_type_out == 0)
8131 write_atm_asc(filename, ctl, atm, t);
8132
8133 /* Write binary data... */
8134 else if (ctl->atm_type_out == 1)
8135 write_atm_bin(filename, ctl, atm);
8136
8137 /* Write netCDF data... */
8138 else if (ctl->atm_type_out == 2)
8139 write_atm_nc(filename, ctl, atm);
8140
8141 /* Write CLaMS trajectory data... */
8142 else if (ctl->atm_type_out == 3)
8143 write_atm_clams_traj(filename, ctl, atm, t);
8144
8145 /* Write CLaMS pos data... */
8146 else if (ctl->atm_type_out == 4)
8147 write_atm_clams(filename, ctl, atm);
8148
8149 /* Error... */
8150 else
8151 ERRMSG("Atmospheric data type not supported!");
8152
8153 /* Write info... */
8154 double mini, maxi;
8155 LOG(2, "Number of particles: %d", atm->np);
8156 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
8157 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8158 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
8159 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
8160 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
8161 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
8162 LOG(2, "%s range: %g ... %g %s",
8163 ctl->met_coord_type == 0 ? "Longitude" : "X coordinate", mini, maxi,
8164 ctl->met_coord_type == 0 ? "deg" : "m");
8165 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
8166 LOG(2, "%s range: %g ... %g %s",
8167 ctl->met_coord_type == 0 ? "Latitude" : "Y coordinate", mini, maxi,
8168 ctl->met_coord_type == 0 ? "deg" : "m");
8169 for (int iq = 0; iq < ctl->nq; iq++) {
8170 char msg[5 * LEN];
8171 sprintf(msg, "Quantity %s range: %s ... %s %s",
8172 ctl->qnt_name[iq], ctl->qnt_format[iq],
8173 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
8174 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
8175 LOG(2, msg, mini, maxi);
8176 }
8177}
8178
8179/*****************************************************************************/
8180
8182 const char *filename,
8183 const ctl_t *ctl,
8184 met_t *met) {
8185
8186 /* Set timer... */
8187 SELECT_TIMER("WRITE_MET", "OUTPUT");
8188
8189 /* Write info... */
8190 LOG(1, "Write meteo data: %s", filename);
8191
8192 /* Check compression flags... */
8193#ifndef ZFP
8194 if (ctl->met_type == 3)
8195 ERRMSG("MPTRAC was compiled without ZFP compression!");
8196#endif
8197#ifndef ZSTD
8198 if (ctl->met_type == 4)
8199 ERRMSG("MPTRAC was compiled without ZSTD compression!");
8200#endif
8201#ifndef LZ4
8202 if (ctl->met_type == 8)
8203 ERRMSG("MPTRAC was compiled without LZ4 compression!");
8204#endif
8205#ifndef CMS
8206 if (ctl->met_type == 5)
8207 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
8208#endif
8209#ifndef SZ3
8210 if (ctl->met_type == 7)
8211 ERRMSG("MPTRAC was compiled without SZ3 compression!");
8212#endif
8213
8214 /* Write netCDF data... */
8215 if (ctl->met_type == 0)
8216 write_met_nc(filename, ctl, met);
8217
8218 /* Write binary data... */
8219 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
8220 || ctl->met_type == 7 || ctl->met_type == 8)
8221 write_met_bin(filename, ctl, met);
8222
8223 /* Not implemented... */
8224 else
8225 ERRMSG("MET_TYPE not implemented!");
8226}
8227
8228/*****************************************************************************/
8229
8231 const char *dirname,
8232 const ctl_t *ctl,
8233 met_t *met0,
8234 met_t *met1,
8235 atm_t *atm,
8236 depo_t *depo,
8237 const double t) {
8238
8239 char ext[10], filename[2 * LEN];
8240
8241 double r;
8242
8243 int year, mon, day, hour, min, sec;
8244
8245 /* Get time... */
8246 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
8247
8248 /* Update host... */
8249 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
8250 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
8251 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
8252 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
8253 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
8254 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
8255 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
8256
8257 /* Write atmospheric data... */
8258 if (ctl->atm_basename[0] != '-' &&
8259 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
8260 if (ctl->atm_type_out == 0)
8261 sprintf(ext, "tab");
8262 else if (ctl->atm_type_out == 1)
8263 sprintf(ext, "bin");
8264 else if (ctl->atm_type_out >= 2)
8265 sprintf(ext, "nc");
8266 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
8267 dirname, ctl->atm_basename, year, mon, day, hour, min, sec, ext);
8268 mptrac_write_atm(filename, ctl, atm, t);
8269 }
8270
8271 /* Write gridded data... */
8272 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
8273 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
8274 dirname, ctl->grid_basename, year, mon, day, hour, min, sec,
8275 ctl->grid_type == 0 ? "tab" : "nc");
8276 write_grid(filename, ctl, met0, met1, atm, t);
8277 }
8278
8279 /* Write radioactive deposition data... */
8280 if (ctl->depo_basename[0] != '-'
8281 && (fmod(t, ctl->depo_dt_out) == 0 || t == ctl->t_stop)) {
8282#ifdef _OPENACC
8283#pragma acc update host(depo[:1])
8284#endif
8285 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
8286 dirname, ctl->depo_basename, year, mon, day, hour, min, sec,
8287 ctl->depo_type == 0 ? "tab" : "nc");
8288 write_depo(filename, ctl, depo, t);
8289 }
8290
8291 /* Write CSI data... */
8292 if (ctl->csi_basename[0] != '-') {
8293 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
8294 write_csi(filename, ctl, atm, t);
8295 }
8296
8297 /* Write ensemble data... */
8298 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
8299 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.tab",
8300 dirname, ctl->ens_basename, year, mon, day, hour, min, sec);
8301 write_ens(filename, ctl, atm, t);
8302 }
8303
8304 /* Write profile data... */
8305 if (ctl->prof_basename[0] != '-') {
8306 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
8307 write_prof(filename, ctl, met0, met1, atm, t);
8308 }
8309
8310 /* Write sample data... */
8311 if (ctl->sample_basename[0] != '-') {
8312 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
8313 write_sample(filename, ctl, met0, met1, atm, t);
8314 }
8315
8316 /* Write station data... */
8317 if (ctl->stat_basename[0] != '-') {
8318 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
8319 write_station(filename, ctl, atm, t);
8320 }
8321
8322 /* Write VTK data... */
8323 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
8324 static int nvtk;
8325 if (t == ctl->t_start)
8326 nvtk = 0;
8327 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
8328 write_vtk(filename, ctl, atm, t);
8329 }
8330}
8331
8332/*****************************************************************************/
8333
8335 const double p,
8336 const double h2o,
8337 const double hno3) {
8338
8339 /* Check water vapor volume mixing ratio... */
8340 const double h2o_help = MAX(h2o, 0.1e-6);
8341
8342 /* Calculate T_NAT... */
8343 const double p_hno3 = hno3 * p / 1.333224;
8344 const double p_h2o = h2o_help * p / 1.333224;
8345 const double a = 0.009179 - 0.00088 * log10(p_h2o);
8346 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
8347 const double c = -11397.0 / a;
8348 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
8349 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
8350 if (x2 > 0)
8351 tnat = x2;
8352
8353 return tnat;
8354}
8355
8356/*****************************************************************************/
8357
8359 const ctl_t *ctl,
8360 const atm_t *atm,
8361 const int ip,
8362 const double pbl,
8363 const double ps) {
8364
8365 /* Get pressure range... */
8366 const double p1 = pbl - ctl->turb_pbl_trans * (ps - pbl);
8367 const double p0 = pbl;
8368
8369 /* Get weighting factor... */
8370 if (atm->p[ip] > p0)
8371 return 1;
8372 else if (atm->p[ip] < p1)
8373 return 0;
8374 else
8375 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
8376}
8377
8378/*****************************************************************************/
8379
8381 const char *filename,
8382 const ctl_t *ctl,
8383 atm_t *atm) {
8384
8385 /* Open file... */
8386 FILE *in;
8387 if (!(in = fopen(filename, "r"))) {
8388 WARN("Cannot open file!");
8389 return 0;
8390 }
8391
8392 /* Read line... */
8393 char line[LEN];
8394 while (fgets(line, LEN, in)) {
8395
8396 /* Read data... */
8397 char *tok;
8398 TOK(line, tok, "%lg", atm->time[atm->np]);
8399 TOK(NULL, tok, "%lg", atm->p[atm->np]);
8400 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
8401 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
8402 for (int iq = 0; iq < ctl->nq; iq++)
8403 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
8404
8405 /* Convert altitude to pressure... */
8406 atm->p[atm->np] = P(atm->p[atm->np]);
8407
8408 /* Increment data point counter... */
8409 if ((++atm->np) > NP)
8410 ERRMSG("Too many data points!");
8411 }
8412
8413 /* Close file... */
8414 fclose(in);
8415
8416 /* Return success... */
8417 return 1;
8418}
8419
8420/*****************************************************************************/
8421
8423 const char *filename,
8424 const ctl_t *ctl,
8425 atm_t *atm) {
8426
8427 /* Open file... */
8428 FILE *in;
8429 if (!(in = fopen(filename, "r")))
8430 return 0;
8431
8432 /* Check version of binary data... */
8433 int version;
8434 FREAD(&version, int,
8435 1,
8436 in);
8437 if (version != 100)
8438 ERRMSG("Wrong version of binary data!");
8439
8440 /* Read data... */
8441 FREAD(&atm->np, int,
8442 1,
8443 in);
8444 FREAD(atm->time, double,
8445 (size_t) atm->np,
8446 in);
8447 FREAD(atm->p, double,
8448 (size_t) atm->np,
8449 in);
8450 FREAD(atm->lon, double,
8451 (size_t) atm->np,
8452 in);
8453 FREAD(atm->lat, double,
8454 (size_t) atm->np,
8455 in);
8456 for (int iq = 0; iq < ctl->nq; iq++)
8457 FREAD(atm->q[iq], double,
8458 (size_t) atm->np,
8459 in);
8460
8461 /* Read final flag... */
8462 int final;
8463 FREAD(&final, int,
8464 1,
8465 in);
8466 if (final != 999)
8467 ERRMSG("Error while reading binary data!");
8468
8469 /* Close file... */
8470 fclose(in);
8471
8472 /* Return success... */
8473 return 1;
8474}
8475
8476/*****************************************************************************/
8477
8479 const char *filename,
8480 const ctl_t *ctl,
8481 atm_t *atm) {
8482
8483 if (ctl->met_coord_type != 0)
8484 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
8485
8486 int ncid, varid;
8487
8488 /* Open file... */
8489 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8490 return 0;
8491
8492 /* Get dimensions... */
8493 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
8494
8495 /* Get time... */
8496 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
8497 NC(nc_get_var_double(ncid, varid, atm->time));
8498 } else {
8499 WARN("TIME_INIT not found use time instead!");
8500 double time_init;
8501 NC_GET_DOUBLE("time", &time_init, 1);
8502 for (int ip = 0; ip < atm->np; ip++) {
8503 atm->time[ip] = time_init;
8504 }
8505 }
8506
8507 /* Read zeta coordinate, pressure is optional... */
8508 if (ctl->advect_vert_coord == 1) {
8509 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
8510 NC_GET_DOUBLE("PRESS", atm->p, 0);
8511 }
8512
8513 /* Read pressure, zeta coordinate is optional... */
8514 else {
8515 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
8516 NC(nc_get_var_double(ncid, varid, atm->p));
8517 } else {
8518 WARN("PRESS_INIT not found use PRESS instead!");
8519 nc_inq_varid(ncid, "PRESS", &varid);
8520 NC(nc_get_var_double(ncid, varid, atm->p));
8521 }
8522 }
8523
8524 /* Read further quantities if requested... */
8525 for (int iq = 0; iq < ctl->nq; iq++)
8526 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8527
8528 /* Read longitude and latitude... */
8529 NC_GET_DOUBLE("LON", atm->lon, 1);
8530 NC_GET_DOUBLE("LAT", atm->lat, 1);
8531
8532 /* Close file... */
8533 NC(nc_close(ncid));
8534
8535 /* Return success... */
8536 return 1;
8537}
8538
8539/*****************************************************************************/
8540
8542 const char *filename,
8543 const ctl_t *ctl,
8544 atm_t *atm) {
8545
8546 int ncid, varid;
8547
8548 /* Open file... */
8549 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8550 return 0;
8551
8552 /* Get dimensions... */
8553 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
8554
8555 /* Read geolocations... */
8556 NC_GET_DOUBLE("time", atm->time, 1);
8557 NC_GET_DOUBLE("press", atm->p, 1);
8558 NC_GET_DOUBLE("lon", atm->lon, 1);
8559 NC_GET_DOUBLE("lat", atm->lat, 1);
8560
8561 /* Read variables... */
8562 for (int iq = 0; iq < ctl->nq; iq++)
8563 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
8564
8565 /* Close file... */
8566 NC(nc_close(ncid));
8567
8568 /* Return success... */
8569 return 1;
8570}
8571
8572/*****************************************************************************/
8573
8575 const char *filename,
8576 clim_photo_t *photo) {
8577
8578 int ncid, varid;
8579
8580 /* Write info... */
8581 LOG(1, "Read photolysis rates: %s", filename);
8582
8583 /* Open netCDF file... */
8584 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8585 WARN("Photolysis rate data are missing!");
8586 return;
8587 }
8588
8589 /* Read pressure data... */
8590 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
8591 NC_GET_DOUBLE("press", photo->p, 1);
8592 if (photo->p[0] < photo->p[1])
8593 ERRMSG("Pressure data are not descending!");
8594
8595 /* Read total column ozone data... */
8596 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
8597 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
8598 if (photo->o3c[0] > photo->o3c[1])
8599 ERRMSG("Total column ozone data are not ascending!");
8600
8601 /* Read solar zenith angle data... */
8602 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
8603 NC_GET_DOUBLE("sza", photo->sza, 1);
8604 if (photo->sza[0] > photo->sza[1])
8605 ERRMSG("Solar zenith angle data are not ascending!");
8606
8607 /* Read data... */
8608 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
8609 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
8610 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
8611 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
8612 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
8613 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
8614 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
8615 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
8616 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
8617
8618 /* Close netCDF file... */
8619 NC(nc_close(ncid));
8620
8621 /* Write info... */
8622 LOG(2, "Number of pressure levels: %d", photo->np);
8623 LOG(2, "Altitude levels: %g, %g ... %g km",
8624 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
8625 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8626 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
8627 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
8628 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
8629 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
8630 RAD2DEG(photo->sza[photo->nsza - 1]));
8631 LOG(2, "Number of total column ozone values: %d", photo->no3c);
8632 LOG(2, "Total column ozone: %g, %g ... %g DU",
8633 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
8634 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
8635 photo->n2o[0][0][0], photo->n2o[1][0][0],
8636 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8637 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
8638 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
8639 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8640 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
8641 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
8642 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8643 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
8644 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
8645 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8646 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
8647 photo->o2[0][0][0], photo->o2[1][0][0],
8648 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8649 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
8650 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
8651 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8652 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
8653 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
8654 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8655 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
8656 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
8657 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8658 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
8659 photo->h2o[0][0][0], photo->h2o[1][0][0],
8660 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8661}
8662
8663/*****************************************************************************/
8664
8666 const int ncid,
8667 const char *varname,
8668 const clim_photo_t *photo,
8669 double var[CP][CSZA][CO3]) {
8670
8671 /* Allocate... */
8672 double *help;
8673 ALLOC(help, double,
8674 photo->np * photo->nsza * photo->no3c);
8675
8676 /* Read varible... */
8677 int varid;
8678 NC_GET_DOUBLE(varname, help, 1);
8679
8680 /* Copy data... */
8681 for (int ip = 0; ip < photo->np; ip++)
8682 for (int is = 0; is < photo->nsza; is++)
8683 for (int io = 0; io < photo->no3c; io++)
8684 var[ip][is][io] =
8685 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
8686
8687 /* Free... */
8688 free(help);
8689}
8690
8691/*****************************************************************************/
8692
8694 const char *filename,
8695 clim_ts_t *ts) {
8696
8697 /* Write info... */
8698 LOG(1, "Read climatological time series: %s", filename);
8699
8700 /* Open file... */
8701 FILE *in;
8702 if (!(in = fopen(filename, "r"))) {
8703 WARN("Cannot open file!");
8704 return 0;
8705 }
8706
8707 /* Read data... */
8708 char line[LEN];
8709 int nh = 0;
8710 while (fgets(line, LEN, in))
8711 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
8712
8713 /* Convert years to seconds... */
8714 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
8715
8716 /* Check data... */
8717 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
8718 ERRMSG("Time series must be ascending!");
8719
8720 /* Count time steps... */
8721 if ((++nh) >= CTS)
8722 ERRMSG("Too many data points!");
8723 }
8724
8725 /* Close file... */
8726 fclose(in);
8727
8728 /* Check number of data points... */
8729 ts->ntime = nh;
8730 if (nh < 2)
8731 ERRMSG("Not enough data points!");
8732
8733 /* Write info... */
8734 LOG(2, "Number of time steps: %d", ts->ntime);
8735 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
8736 ts->time[nh - 1]);
8737 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
8738 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
8739 (size_t) nh));
8740
8741 /* Exit success... */
8742 return 1;
8743}
8744
8745/*****************************************************************************/
8746
8748 const char *filename,
8749 const char *varname,
8750 clim_zm_t *zm) {
8751
8752 int ncid, varid, it, iy, iz, iz2, nt;
8753
8754 double *help, varmin = 1e99, varmax = -1e99;
8755
8756 /* Write info... */
8757 LOG(1, "Read %s data: %s", varname, filename);
8758
8759 /* Open netCDF file... */
8760 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8761 WARN("%s climatology data are missing!", varname);
8762 return;
8763 }
8764
8765 /* Read pressure data... */
8766 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
8767 NC_GET_DOUBLE("press", zm->p, 1);
8768 if (zm->p[0] < zm->p[1])
8769 ERRMSG("Pressure data are not descending!");
8770
8771 /* Read latitudes... */
8772 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
8773 NC_GET_DOUBLE("lat", zm->lat, 1);
8774 if (zm->lat[0] > zm->lat[1])
8775 ERRMSG("Latitude data are not ascending!");
8776
8777 /* Set time data (for monthly means)... */
8778 zm->ntime = 12;
8779 zm->time[0] = 1209600.00;
8780 zm->time[1] = 3888000.00;
8781 zm->time[2] = 6393600.00;
8782 zm->time[3] = 9072000.00;
8783 zm->time[4] = 11664000.00;
8784 zm->time[5] = 14342400.00;
8785 zm->time[6] = 16934400.00;
8786 zm->time[7] = 19612800.00;
8787 zm->time[8] = 22291200.00;
8788 zm->time[9] = 24883200.00;
8789 zm->time[10] = 27561600.00;
8790 zm->time[11] = 30153600.00;
8791
8792 /* Check number of timesteps... */
8793 NC_INQ_DIM("time", &nt, 12, 12, 1);
8794
8795 /* Read data... */
8796 ALLOC(help, double,
8797 zm->nlat * zm->np * zm->ntime);
8798 NC_GET_DOUBLE(varname, help, 1);
8799 for (it = 0; it < zm->ntime; it++)
8800 for (iz = 0; iz < zm->np; iz++)
8801 for (iy = 0; iy < zm->nlat; iy++)
8802 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
8803 free(help);
8804
8805 /* Fix data gaps... */
8806 for (it = 0; it < zm->ntime; it++)
8807 for (iy = 0; iy < zm->nlat; iy++)
8808 for (iz = 0; iz < zm->np; iz++) {
8809 if (zm->vmr[it][iz][iy] < 0) {
8810 for (iz2 = 0; iz2 < zm->np; iz2++)
8811 if (zm->vmr[it][iz2][iy] >= 0) {
8812 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8813 break;
8814 }
8815 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
8816 if (zm->vmr[it][iz2][iy] >= 0) {
8817 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8818 break;
8819 }
8820 }
8821 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
8822 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
8823 }
8824
8825 /* Close netCDF file... */
8826 NC(nc_close(ncid));
8827
8828 /* Write info... */
8829 LOG(2, "Number of time steps: %d", zm->ntime);
8830 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
8831 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
8832 LOG(2, "Number of pressure levels: %d", zm->np);
8833 LOG(2, "Altitude levels: %g, %g ... %g km",
8834 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
8835 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
8836 zm->p[1], zm->p[zm->np - 1]);
8837 LOG(2, "Number of latitudes: %d", zm->nlat);
8838 LOG(2, "Latitudes: %g, %g ... %g deg",
8839 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
8840 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
8841 varmax);
8842}
8843
8844/*****************************************************************************/
8845
8847 const char *filename,
8848 double kz[EP],
8849 double kw[EP],
8850 int *nk) {
8851
8852 /* Write info... */
8853 LOG(1, "Read kernel function: %s", filename);
8854
8855 /* Open file... */
8856 FILE *in;
8857 if (!(in = fopen(filename, "r")))
8858 ERRMSG("Cannot open file!");
8859
8860 /* Read data... */
8861 char line[LEN];
8862 int n = 0;
8863 while (fgets(line, LEN, in))
8864 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
8865 if (n > 0 && kz[n] < kz[n - 1])
8866 ERRMSG("Height levels must be ascending!");
8867 if ((++n) >= EP)
8868 ERRMSG("Too many height levels!");
8869 }
8870
8871 /* Close file... */
8872 fclose(in);
8873
8874 /* Check number of data points... */
8875 *nk = n;
8876 if (n < 2)
8877 ERRMSG("Not enough height levels!");
8878
8879 /* Normalize kernel function... */
8880 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
8881 for (int iz = 0; iz < n; iz++)
8882 kw[iz] /= kmax;
8883}
8884
8885/*****************************************************************************/
8886
8888 const char *filename,
8889 const ctl_t *ctl,
8890 met_t *met) {
8891
8892 FILE *in;
8893
8894 double r;
8895
8896 int year, mon, day, hour, min, sec;
8897
8898 /* Set timer... */
8899 SELECT_TIMER("READ_MET_BIN", "INPUT");
8900
8901 /* Open file... */
8902 if (!(in = fopen(filename, "r"))) {
8903 WARN("Cannot open file!");
8904 return 0;
8905 }
8906
8907 /* Check type of binary data... */
8908 int met_type;
8909 FREAD(&met_type, int,
8910 1,
8911 in);
8912 if (met_type != ctl->met_type)
8913 ERRMSG("Wrong MET_TYPE of binary data!");
8914
8915 /* Check version of binary data... */
8916 int version;
8917 FREAD(&version, int,
8918 1,
8919 in);
8920 if (version != 104)
8921 ERRMSG("Wrong version of binary data!");
8922
8923 /* Read time... */
8924 FREAD(&met->time, double,
8925 1,
8926 in);
8927 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8928 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8929 met->time, year, mon, day, hour, min);
8930 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8931 || day < 1 || day > 31 || hour < 0 || hour > 23)
8932 ERRMSG("Error while reading time!");
8933
8934 /* Read dimensions... */
8935 met->coord_type = ctl->met_coord_type;
8936
8937 FREAD(&met->nx, int,
8938 1,
8939 in);
8940 LOG(2, "Number of %s: %d",
8941 (met->coord_type == 0) ? "longitudes" : "x coordinates", met->nx);
8942 if (met->nx < 2 || met->nx > EX)
8943 ERRMSG(met->coord_type == 0
8944 ? "Number of longitudes out of range!"
8945 : "Number of x coordinates out of range!");
8946
8947 FREAD(&met->ny, int,
8948 1,
8949 in);
8950 LOG(2, "Number of %s: %d",
8951 (met->coord_type == 0) ? "latitudes" : "y coordinates", met->ny);
8952 if (met->ny < 2 || met->ny > EY)
8953 ERRMSG(met->coord_type == 0
8954 ? "Number of latitudes out of range!"
8955 : "Number of y coordinates out of range!");
8956
8957 FREAD(&met->np, int,
8958 1,
8959 in);
8960 LOG(2, "Number of levels: %d", met->np);
8961 if (met->np < 2 || met->np > EP)
8962 ERRMSG("Number of levels out of range!");
8963
8964 /* Read grid... */
8965 FREAD(met->lon, double,
8966 (size_t) met->nx,
8967 in);
8968 LOG(2, "%s: %g, %g ... %g %s",
8969 met->coord_type == 0 ? "Longitudes" : "X coordinates",
8970 met->lon[0], met->lon[1], met->lon[met->nx - 1],
8971 met->coord_type == 0 ? "deg" : "m");
8972
8973 FREAD(met->lat, double,
8974 (size_t) met->ny,
8975 in);
8976 LOG(2, "%s: %g, %g ... %g %s",
8977 met->coord_type == 0 ? "Latitudes" : "Y coordinates",
8978 met->lat[0], met->lat[1], met->lat[met->ny - 1],
8979 met->coord_type == 0 ? "deg" : "m");
8980
8981 FREAD(met->p, double,
8982 (size_t) met->np,
8983 in);
8984 LOG(2, "Altitude levels: %g, %g ... %g km",
8985 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
8986 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8987 met->p[0], met->p[1], met->p[met->np - 1]);
8988
8989 /* Read surface data... */
8990 read_met_bin_2d(in, met, met->ps, "PS");
8991 read_met_bin_2d(in, met, met->ts, "TS");
8992 read_met_bin_2d(in, met, met->zs, "ZS");
8993 read_met_bin_2d(in, met, met->us, "US");
8994 read_met_bin_2d(in, met, met->vs, "VS");
8995 read_met_bin_2d(in, met, met->ess, "ESS");
8996 read_met_bin_2d(in, met, met->nss, "NSS");
8997 read_met_bin_2d(in, met, met->shf, "SHF");
8998 read_met_bin_2d(in, met, met->lsm, "LSM");
8999 read_met_bin_2d(in, met, met->sst, "SST");
9000 read_met_bin_2d(in, met, met->pbl, "PBL");
9001 read_met_bin_2d(in, met, met->pt, "PT");
9002 read_met_bin_2d(in, met, met->tt, "TT");
9003 read_met_bin_2d(in, met, met->zt, "ZT");
9004 read_met_bin_2d(in, met, met->h2ot, "H2OT");
9005 read_met_bin_2d(in, met, met->pct, "PCT");
9006 read_met_bin_2d(in, met, met->pcb, "PCB");
9007 read_met_bin_2d(in, met, met->cl, "CL");
9008 read_met_bin_2d(in, met, met->plcl, "PLCL");
9009 read_met_bin_2d(in, met, met->plfc, "PLFC");
9010 read_met_bin_2d(in, met, met->pel, "PEL");
9011 read_met_bin_2d(in, met, met->cape, "CAPE");
9012 read_met_bin_2d(in, met, met->cin, "CIN");
9013 read_met_bin_2d(in, met, met->o3c, "O3C");
9014
9015 /* Read level data... */
9016 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
9017 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
9018 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
9019 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
9020 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
9021 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
9022 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
9023 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
9024 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
9025 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
9026 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
9027 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
9028 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
9029
9030 /* Read final flag... */
9031 int final;
9032 FREAD(&final, int,
9033 1,
9034 in);
9035 if (final != 999)
9036 ERRMSG("Error while reading binary data!");
9037
9038 /* Close file... */
9039 fclose(in);
9040
9041 /* Return success... */
9042 return 1;
9043}
9044
9045/*****************************************************************************/
9046
9048 FILE *in,
9049 const met_t *met,
9050 float var[EX][EY],
9051 const char *varname) {
9052
9053 float *help;
9054
9055 /* Allocate... */
9056 ALLOC(help, float,
9057 EX * EY);
9058
9059 /* Read uncompressed... */
9060 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
9061 FREAD(help, float,
9062 (size_t) (met->nx * met->ny),
9063 in);
9064
9065 /* Copy data... */
9066 for (int ix = 0; ix < met->nx; ix++)
9067 for (int iy = 0; iy < met->ny; iy++)
9068 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
9069
9070 /* Free... */
9071 free(help);
9072}
9073
9074/*****************************************************************************/
9075
9077 FILE *in,
9078 const ctl_t *ctl,
9079 const met_t *met,
9080 float var[EX][EY][EP],
9081 const char *varname,
9082 const float bound_min,
9083 const float bound_max) {
9084
9085 float *help;
9086
9087 /* Allocate... */
9088 ALLOC(help, float,
9089 EX * EY * EP);
9090
9091 /* Read uncompressed data... */
9092 if (ctl->met_type == 1) {
9093 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
9094 FREAD(help, float,
9095 (size_t) (met->nx * met->ny * met->np),
9096 in);
9097 }
9098
9099 /* Read packed data... */
9100 else if (ctl->met_type == 2)
9101 compress_pck(ctl, met, varname, help, 1, NULL, in);
9102
9103 /* Read ZFP data... */
9104 else if (ctl->met_type == 3) {
9105#ifdef ZFP
9106 int precision;
9107 FREAD(&precision, int,
9108 1,
9109 in);
9110
9111 double tolerance;
9112 FREAD(&tolerance, double,
9113 1,
9114 in);
9115
9116 compress_zfp(ctl, met, varname, help, 1, NULL, in);
9117#else
9118 ERRMSG("MPTRAC was compiled without ZFP compression!");
9119#endif
9120 }
9121
9122 /* Read zstd data... */
9123 else if (ctl->met_type == 4) {
9124#ifdef ZSTD
9125 compress_zstd(ctl, met, varname, help, 1, NULL, in);
9126#else
9127 ERRMSG("MPTRAC was compiled without ZSTD compression!");
9128#endif
9129 }
9130
9131 /* Read LZ4 data... */
9132 else if (ctl->met_type == 8) {
9133#ifdef LZ4
9134 compress_lz4(ctl, met, varname, help, 1, NULL, in);
9135#else
9136 ERRMSG("MPTRAC was compiled without LZ4 compression!");
9137#endif
9138 }
9139
9140 /* Read cmultiscale data... */
9141 else if (ctl->met_type == 5) {
9142#ifdef CMS
9143 compress_cms(ctl, met, varname, help, 1, NULL, in);
9144#else
9145 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
9146#endif
9147 }
9148
9149 /* Read SZ3 data... */
9150 else if (ctl->met_type == 7) {
9151#ifdef SZ3
9152 int precision;
9153 FREAD(&precision, int,
9154 1,
9155 in);
9156
9157 double tolerance;
9158 FREAD(&tolerance, double,
9159 1,
9160 in);
9161
9162 compress_sz3(ctl, met, varname, help, 1, NULL, in);
9163#else
9164 ERRMSG("MPTRAC was compiled without sz3 compression!");
9165#endif
9166 }
9167
9168 /* Copy data... */
9169#pragma omp parallel for default(shared) collapse(2)
9170 for (int ix = 0; ix < met->nx; ix++)
9171 for (int iy = 0; iy < met->ny; iy++)
9172 for (int ip = 0; ip < met->np; ip++) {
9173 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9174 if (var[ix][iy][ip] < bound_min)
9175 var[ix][iy][ip] = bound_min;
9176 else if (var[ix][iy][ip] > bound_max)
9177 var[ix][iy][ip] = bound_max;
9178 }
9179
9180 /* Free... */
9181 free(help);
9182}
9183
9184/*****************************************************************************/
9185
9187 const ctl_t *ctl,
9188 const clim_t *clim,
9189 met_t *met) {
9190
9191 /* Check parameters... */
9192 if (ctl->met_cape != 1)
9193 return;
9194
9195 if (ctl->met_coord_type != 0)
9196 ERRMSG("Only lat/lon grid supported");
9197
9198 /* Set timer... */
9199 SELECT_TIMER("READ_MET_CAPE", "METPROC");
9200 LOG(2, "Calculate CAPE...");
9201
9202 /* Vertical spacing (about 100 m)... */
9203 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
9204
9205 /* Loop over columns... */
9206#pragma omp parallel for default(shared) collapse(2)
9207 for (int ix = 0; ix < met->nx; ix++)
9208 for (int iy = 0; iy < met->ny; iy++) {
9209
9210 /* Get potential temperature and water vapor at lowest 50 hPa... */
9211 int n = 0;
9212 double h2o = 0, t, theta = 0;
9213 double pbot = MIN(met->ps[ix][iy], met->p[0]);
9214 double ptop = pbot - 50.;
9215 for (int ip = 0; ip < met->np; ip++) {
9216 if (met->p[ip] <= pbot) {
9217 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
9218 h2o += met->h2o[ix][iy][ip];
9219 n++;
9220 }
9221 if (met->p[ip] < ptop && n > 0)
9222 break;
9223 }
9224 theta /= n;
9225 h2o /= n;
9226
9227 /* Cannot compute anything if water vapor is missing... */
9228 met->plcl[ix][iy] = NAN;
9229 met->plfc[ix][iy] = NAN;
9230 met->pel[ix][iy] = NAN;
9231 met->cape[ix][iy] = NAN;
9232 met->cin[ix][iy] = NAN;
9233 if (h2o <= 0)
9234 continue;
9235
9236 /* Find lifted condensation level (LCL)... */
9237 ptop = P(20.);
9238 pbot = met->ps[ix][iy];
9239 do {
9240 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
9241 t = theta / pow(1000. / met->plcl[ix][iy], KAPPA);
9242 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
9243 ptop = met->plcl[ix][iy];
9244 else
9245 pbot = met->plcl[ix][iy];
9246 } while (pbot - ptop > 0.1);
9247
9248 /* Calculate CIN up to LCL... */
9250 double dcape, dz, h2o_env, t_env;
9251 double p = met->ps[ix][iy];
9252 met->cape[ix][iy] = met->cin[ix][iy] = 0;
9253 do {
9254 dz = dz0 * TVIRT(t, h2o);
9255 p /= pfac;
9256 t = theta / pow(1000. / p, KAPPA);
9257 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
9258 &t_env, ci, cw, 1);
9259 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
9260 &h2o_env, ci, cw, 0);
9261 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
9262 TVIRT(t_env, h2o_env) * dz;
9263 if (dcape < 0)
9264 met->cin[ix][iy] += fabsf((float) dcape);
9265 } while (p > met->plcl[ix][iy]);
9266
9267 /* Calculate level of free convection (LFC), equilibrium level (EL),
9268 and convective available potential energy (CAPE)... */
9269 dcape = 0;
9270 p = met->plcl[ix][iy];
9271 t = theta / pow(1000. / p, KAPPA);
9272 ptop = 0.75 * clim_tropo(clim, met->time,
9273 ctl->met_coord_type ==
9274 0 ? met->lat[iy] : ctl->met_utm_ref_lat);
9275 do {
9276 dz = dz0 * TVIRT(t, h2o);
9277 p /= pfac;
9278 t -= lapse_rate(t, h2o) * dz;
9279 double psat = PSAT(t);
9280 h2o = psat / (p - (1. - EPS) * psat);
9281 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
9282 &t_env, ci, cw, 1);
9283 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
9284 &h2o_env, ci, cw, 0);
9285 double dcape_old = dcape;
9286 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
9287 TVIRT(t_env, h2o_env) * dz;
9288 if (dcape > 0) {
9289 met->cape[ix][iy] += (float) dcape;
9290 if (!isfinite(met->plfc[ix][iy]))
9291 met->plfc[ix][iy] = (float) p;
9292 } else if (dcape_old > 0)
9293 met->pel[ix][iy] = (float) p;
9294 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
9295 met->cin[ix][iy] += fabsf((float) dcape);
9296 } while (p > ptop);
9297
9298 /* Check results... */
9299 if (!isfinite(met->plfc[ix][iy]))
9300 met->cin[ix][iy] = NAN;
9301 }
9302}
9303
9304/*****************************************************************************/
9305
9307 met_t *met) {
9308
9309 /* Set timer... */
9310 SELECT_TIMER("READ_MET_CLOUD", "METPROC");
9311 LOG(2, "Calculate cloud data...");
9312
9313 /* Thresholds for cloud detection... */
9314 const double ccmin = 0.01, cwmin = 1e-6;
9315
9316 /* Loop over columns... */
9317#pragma omp parallel for default(shared) collapse(2)
9318 for (int ix = 0; ix < met->nx; ix++)
9319 for (int iy = 0; iy < met->ny; iy++) {
9320
9321 /* Init... */
9322 met->pct[ix][iy] = NAN;
9323 met->pcb[ix][iy] = NAN;
9324 met->cl[ix][iy] = 0;
9325
9326 /* Loop over pressure levels... */
9327 for (int ip = 0; ip < met->np - 1; ip++) {
9328
9329 /* Check pressure... */
9330 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
9331 continue;
9332
9333 /* Check ice water and liquid water content... */
9334 if (met->cc[ix][iy][ip] > ccmin
9335 && (met->lwc[ix][iy][ip] > cwmin
9336 || met->rwc[ix][iy][ip] > cwmin
9337 || met->iwc[ix][iy][ip] > cwmin
9338 || met->swc[ix][iy][ip] > cwmin)) {
9339
9340 /* Get cloud top pressure ... */
9341 met->pct[ix][iy]
9342 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
9343
9344 /* Get cloud bottom pressure ... */
9345 if (!isfinite(met->pcb[ix][iy]))
9346 met->pcb[ix][iy]
9347 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
9348 }
9349
9350 /* Get cloud water... */
9351 met->cl[ix][iy] += (float)
9352 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
9353 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
9354 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
9355 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
9356 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
9357 }
9358 }
9359}
9360
9361/*****************************************************************************/
9362
9364 const ctl_t *ctl,
9365 met_t *met) {
9366
9367 met_t *help;
9368
9369 /* Check parameters... */
9370 if (ctl->met_detrend <= 0)
9371 return;
9372
9373 if (ctl->met_coord_type != 0)
9374 ERRMSG("Only lat/lon grid supported");
9375
9376 /* Set timer... */
9377 SELECT_TIMER("READ_MET_DETREND", "METPROC");
9378 LOG(2, "Detrend meteo data...");
9379
9380 /* Allocate... */
9381 ALLOC(help, met_t, 1);
9382
9383 /* Calculate standard deviation... */
9384 const double sigma = ctl->met_detrend / 2.355;
9385 const double tssq = 2. * SQR(sigma);
9386
9387 /* Calculate box size in latitude... */
9388 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
9389 sy = MIN(MAX(1, sy), met->ny / 2);
9390
9391 /* Calculate background... */
9392#pragma omp parallel for default(shared) collapse(2)
9393 for (int ix = 0; ix < met->nx; ix++) {
9394 for (int iy = 0; iy < met->ny; iy++) {
9395
9396 /* Calculate Cartesian coordinates... */
9397 double x0[3];
9398 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
9399
9400 /* Calculate box size in longitude... */
9401 int sx =
9402 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
9403 fabs(met->lon[1] - met->lon[0]));
9404 sx = MIN(MAX(1, sx), met->nx / 2);
9405
9406 /* Init... */
9407 float wsum = 0;
9408 for (int ip = 0; ip < met->np; ip++) {
9409 help->t[ix][iy][ip] = 0;
9410 help->u[ix][iy][ip] = 0;
9411 help->v[ix][iy][ip] = 0;
9412 help->w[ix][iy][ip] = 0;
9413 }
9414
9415 /* Loop over neighboring grid points... */
9416 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
9417 int ix3 = ix2;
9418 if (ix3 < 0)
9419 ix3 += met->nx;
9420 else if (ix3 >= met->nx)
9421 ix3 -= met->nx;
9422 for (int iy2 = MAX(iy - sy, 0);
9423 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
9424
9425 /* Calculate Cartesian coordinates... */
9426 double x1[3];
9427 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
9428
9429 /* Calculate weighting factor... */
9430 const float w = (float) exp(-DIST2(x0, x1) / tssq);
9431
9432 /* Add data... */
9433 wsum += w;
9434 for (int ip = 0; ip < met->np; ip++) {
9435 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
9436 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
9437 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
9438 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
9439 }
9440 }
9441 }
9442
9443 /* Normalize... */
9444 for (int ip = 0; ip < met->np; ip++) {
9445 help->t[ix][iy][ip] /= wsum;
9446 help->u[ix][iy][ip] /= wsum;
9447 help->v[ix][iy][ip] /= wsum;
9448 help->w[ix][iy][ip] /= wsum;
9449 }
9450 }
9451 }
9452
9453 /* Subtract background... */
9454#pragma omp parallel for default(shared) collapse(3)
9455 for (int ix = 0; ix < met->nx; ix++)
9456 for (int iy = 0; iy < met->ny; iy++)
9457 for (int ip = 0; ip < met->np; ip++) {
9458 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
9459 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
9460 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
9461 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
9462 }
9463
9464 /* Free... */
9465 free(help);
9466}
9467
9468/*****************************************************************************/
9469
9471 met_t *met) {
9472
9473 /* Set timer... */
9474 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC");
9475 LOG(2, "Extrapolate meteo data...");
9476
9477 /* Loop over columns... */
9478#pragma omp parallel for default(shared) collapse(2)
9479 for (int ix = 0; ix < met->nx; ix++)
9480 for (int iy = 0; iy < met->ny; iy++) {
9481
9482 /* Find lowest valid data point... */
9483 int ip0;
9484 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
9485 if (!isfinite(met->t[ix][iy][ip0])
9486 || !isfinite(met->u[ix][iy][ip0])
9487 || !isfinite(met->v[ix][iy][ip0])
9488 || !isfinite(met->w[ix][iy][ip0]))
9489 break;
9490
9491 /* Extrapolate... */
9492 for (int ip = ip0; ip >= 0; ip--) {
9493 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
9494 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
9495 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
9496 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
9497 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
9498 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
9499 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
9500 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
9501 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
9502 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
9503 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
9504 }
9505 }
9506}
9507
9508/*****************************************************************************/
9509
9511 const ctl_t *ctl,
9512 met_t *met) {
9513
9514 float *help;
9515
9516 double logp[EP];
9517
9518 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
9519
9520 /* Set timer... */
9521 SELECT_TIMER("READ_MET_GEOPOT", "METPROC");
9522 LOG(2, "Calculate geopotential heights...");
9523
9524 /* Allocate... */
9525 ALLOC(help, float,
9526 EX * EY * EP);
9527
9528 /* Calculate log pressure... */
9529#pragma omp parallel for default(shared)
9530 for (int ip = 0; ip < met->np; ip++)
9531 logp[ip] = log(met->p[ip]);
9532
9533 /* Apply hydrostatic equation to calculate geopotential heights... */
9534#pragma omp parallel for default(shared) collapse(2)
9535 for (int ix = 0; ix < met->nx; ix++)
9536 for (int iy = 0; iy < met->ny; iy++) {
9537
9538 /* Get surface height and pressure... */
9539 const double zs = met->zs[ix][iy];
9540 const double lnps = log(met->ps[ix][iy]);
9541
9542 /* Get temperature and water vapor at the surface... */
9543 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
9544 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
9545 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
9546 const double h2os =
9547 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
9548 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
9549
9550 /* Upper part of profile... */
9551 met->z[ix][iy][ip0 + 1]
9552 = (float) (zs +
9553 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
9554 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
9555 for (int ip = ip0 + 2; ip < met->np; ip++)
9556 met->z[ix][iy][ip]
9557 = (float) (met->z[ix][iy][ip - 1] +
9558 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
9559 met->h2o[ix][iy][ip - 1], logp[ip],
9560 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
9561
9562 /* Lower part of profile... */
9563 met->z[ix][iy][ip0]
9564 = (float) (zs +
9565 ZDIFF(lnps, ts, h2os, logp[ip0],
9566 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
9567 for (int ip = ip0 - 1; ip >= 0; ip--)
9568 met->z[ix][iy][ip]
9569 = (float) (met->z[ix][iy][ip + 1] +
9570 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
9571 met->h2o[ix][iy][ip + 1], logp[ip],
9572 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
9573 }
9574
9575 /* Check control parameters... */
9576 if (dx == 0 || dy == 0)
9577 return;
9578
9579 /* Default smoothing parameters... */
9580 if (dx < 0 || dy < 0) {
9581 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
9582 dx = 3;
9583 dy = 2;
9584 } else {
9585 dx = 6;
9586 dy = 4;
9587 }
9588 }
9589
9590 /* Calculate weights for smoothing... */
9591 float ws[dx + 1][dy + 1];
9592#pragma omp parallel for default(shared) collapse(2)
9593 for (int ix = 0; ix <= dx; ix++)
9594 for (int iy = 0; iy < dy; iy++)
9595 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
9596 * (1.0f - (float) iy / (float) dy);
9597
9598 /* Copy data... */
9599#pragma omp parallel for default(shared) collapse(3)
9600 for (int ix = 0; ix < met->nx; ix++)
9601 for (int iy = 0; iy < met->ny; iy++)
9602 for (int ip = 0; ip < met->np; ip++)
9603 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
9604
9605 /* Horizontal smoothing... */
9606#pragma omp parallel for default(shared) collapse(3)
9607 for (int ip = 0; ip < met->np; ip++)
9608 for (int ix = 0; ix < met->nx; ix++)
9609 for (int iy = 0; iy < met->ny; iy++) {
9610 float res = 0, wsum = 0;
9611 int iy0 = MAX(iy - dy + 1, 0);
9612 int iy1 = MIN(iy + dy - 1, met->ny - 1);
9613 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
9614 int ix3 = ix2;
9615 if (ix3 < 0)
9616 ix3 += met->nx;
9617 else if (ix3 >= met->nx)
9618 ix3 -= met->nx;
9619 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
9620 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
9621 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
9622 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
9623 wsum += w;
9624 }
9625 }
9626 if (wsum > 0)
9627 met->z[ix][iy][ip] = res / wsum;
9628 else
9629 met->z[ix][iy][ip] = NAN;
9630 }
9631
9632 /* Free... */
9633 free(help);
9634}
9635
9636/*****************************************************************************/
9637
9639 const char *filename,
9640 const int ncid,
9641 const ctl_t *ctl,
9642 met_t *met,
9643 dd_t *dd) {
9644
9645 char levname[LEN], tstr[10];
9646
9647 double rtime = 0, r, r2;
9648
9649 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
9650 year, mon, day, hour, min, sec;
9651
9652 size_t dimlen;
9653
9654 /* Set timer... */
9655 SELECT_TIMER("READ_MET_NC_GRID", "INPUT");
9656 LOG(2, "Read meteo grid information...");
9657
9658 /* MPTRAC meteo files... */
9659 if (!ctl->met_clams) {
9660
9661 /* Get time from filename... */
9662 met->time = time_from_filename(filename, 16, 0);
9663
9664 /* Check time information from data file... */
9665 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
9666 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
9667 NC(nc_get_var_double(ncid, varid, &rtime));
9668 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
9669 WARN("Time information in meteo file does not match filename!");
9670 } else
9671 WARN("Time information in meteo file is missing!");
9672 }
9673
9674 /* CLaMS meteo files... */
9675 else {
9676
9677 /* Read time from file... */
9678 NC_GET_DOUBLE("time", &rtime, 0);
9679
9680 /* Get time from filename (considering the century)... */
9681 if (rtime < 0)
9682 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
9683 else
9684 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
9685 year = atoi(tstr);
9686 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
9687 mon = atoi(tstr);
9688 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
9689 day = atoi(tstr);
9690 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
9691 hour = atoi(tstr);
9692 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
9693 }
9694
9695 /* Check time... */
9696 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
9697 || day < 1 || day > 31 || hour < 0 || hour > 23)
9698 ERRMSG("Cannot read time from filename!");
9699 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
9700 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
9701 met->time, year2, mon2, day2, hour2, min2);
9702
9703 /* Get vertical dimension... */
9704 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
9705 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
9706 ERRMSG
9707 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
9708
9709 NC(nc_inq_varndims(ncid, varid, &ndims));
9710 NC(nc_inq_vardimid(ncid, varid, dimids));
9711
9712 if (ndims == 4) {
9713 NC(nc_inq_dim
9714 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
9715 } else if (ndims == 3) {
9716 NC(nc_inq_dim
9717 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
9718 } else
9719 ERRMSG("Cannot determine vertical dimension!")
9720 met->np = (int) dimlen;
9721
9722 LOG(2, "Number of levels: %d", met->np);
9723 if (met->np < 2 || met->np > EP)
9724 ERRMSG("Number of levels out of range!");
9725
9726 if (!ctl->dd) {
9727
9728 /* Get grid dimensions and coordinates... */
9729 if (met->coord_type == 0) {
9730 /* Longitude/latitude grid... */
9731 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
9732 LOG(2, "Number of longitudes: %d", met->nx);
9733
9734 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
9735 LOG(2, "Number of latitudes: %d", met->ny);
9736
9737 NC_GET_DOUBLE("lon", met->lon, 1);
9738 LOG(2, "Longitudes: %g, %g ... %g deg",
9739 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9740 NC_GET_DOUBLE("lat", met->lat, 1);
9741 LOG(2, "Latitudes: %g, %g ... %g deg",
9742 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9743
9744 } else {
9745 /* UTM grid... */
9746 NC_INQ_DIM("x", &met->nx, 2, EX, 1);
9747 LOG(2, "Number of x coordinates: %d", met->nx);
9748
9749 NC_INQ_DIM("y", &met->ny, 2, EY, 1);
9750 LOG(2, "Number of y coordinates: %d", met->ny);
9751
9752 NC_GET_DOUBLE("x", met->lon, 1);
9753 LOG(2, "X coordinates: %g, %g ... %g m",
9754 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9755 NC_GET_DOUBLE("y", met->lat, 1);
9756 LOG(2, "Y coordinates: %g, %g ... %g m",
9757 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9758 }
9759
9760 } else {
9761
9762 if (met->coord_type != 0)
9763 ERRMSG("Domain decomposition is only supported for lat/lon grids!");
9764
9765 /* Use equidistant lat-lon domain decomposition... */
9766 dd_read_met_nc_grid(dd, ctl, met, ncid);
9767
9768 }
9769
9770 /* Read pressure levels... */
9771 if (ctl->met_np <= 0) {
9772 NC_GET_DOUBLE(levname, met->p, 1);
9773 for (int ip = 0; ip < met->np; ip++)
9774 met->p[ip] /= 100.;
9775 LOG(2, "Altitude levels: %g, %g ... %g km",
9776 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
9777 LOG(2, "Pressure levels: %g, %g ... %g hPa",
9778 met->p[0], met->p[1], met->p[met->np - 1]);
9779 }
9780
9781 /* Read hybrid levels... */
9782 if (strcasecmp(levname, "hybrid") == 0)
9783 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
9784
9785 /* Read model level coefficients from file... */
9786 if (ctl->met_vert_coord == 2) {
9787 NC_GET_DOUBLE("hyam", met->hyam, 1);
9788 NC_GET_DOUBLE("hybm", met->hybm, 1);
9789 }
9790
9791 /* Copy model level coefficients from control parameters... */
9792 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
9793 if (ctl->met_nlev <= 0)
9794 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
9795 for (int ip = 0; ip < ctl->met_nlev; ip++) {
9796 met->hyam[ip] = ctl->met_lev_hyam[ip];
9797 met->hybm[ip] = ctl->met_lev_hybm[ip];
9798 }
9799 }
9800
9801 /* Calculate eta levels... */
9802 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
9803 met->eta[k] = met->hyam[k] / 100000.0 + met->hybm[k];
9804 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
9805 ERRMSG("Eta levels must be ascending!");
9806 }
9807
9808 /* Check horizontal grid spacing... */
9809 for (int ix = 2; ix < met->nx; ix++)
9810 if (fabs
9811 (fabs(met->lon[ix] - met->lon[ix - 1]) -
9812 fabs(met->lon[1] - met->lon[0])) > 0.001)
9813 ERRMSG("No regular grid spacing in longitudes!");
9814 for (int iy = 2; iy < met->ny; iy++)
9815 if (fabs
9816 (fabs(met->lat[iy] - met->lat[iy - 1]) -
9817 fabs(met->lat[1] - met->lat[0])) > 0.001) {
9818 WARN("No regular grid spacing in latitudes!");
9819 break;
9820 }
9821}
9822
9823/*****************************************************************************/
9824
9826 const int ncid,
9827 const ctl_t *ctl,
9828 met_t *met,
9829 dd_t *dd) {
9830
9831 /* Set timer... */
9832 SELECT_TIMER("READ_MET_SURFACE", "INPUT");
9833 LOG(2, "Read surface data...");
9834
9835 /* Read surface pressure... */
9836 if (read_met_nc_2d
9837 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
9838 1.0f, 1)) {
9839 for (int ix = 0; ix < met->nx; ix++)
9840 for (int iy = 0; iy < met->ny; iy++)
9841 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
9842 } else
9843 if (!read_met_nc_2d
9844 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
9845 0.01f, 1)) {
9846 WARN("Cannot not read surface pressure data (use lowest level)!");
9847 for (int ix = 0; ix < met->nx; ix++)
9848 for (int iy = 0; iy < met->ny; iy++)
9849 met->ps[ix][iy]
9850 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
9851 }
9852
9853 /* MPTRAC meteo data... */
9854 if (ctl->met_clams == 0) {
9855
9856 /* Read geopotential height at the surface... */
9857 if (!read_met_nc_2d
9858 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
9859 (float) (1. / (1000. * G0)), 1))
9860 if (!read_met_nc_2d
9861 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
9862 (ctl->met_gp2z ? (float) (1e-3 / G0) : (float) (1. / 1000.)), 1))
9863 WARN("Cannot read surface geopotential height!");
9864 }
9865
9866 /* CLaMS meteo data... */
9867 else {
9868
9869 /* Read geopotential height at the surface
9870 (use lowermost level of 3-D data field)... */
9871 float *help;
9872 ALLOC(help, float,
9873 EX * EY * EP);
9874 memcpy(help, met->pl, sizeof(met->pl));
9875 if (!read_met_nc_3d
9876 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
9877 (float) (1e-3 / G0)))
9878 ERRMSG("Cannot read geopotential height!");
9879 for (int ix = 0; ix < met->nx; ix++)
9880 for (int iy = 0; iy < met->ny; iy++)
9881 met->zs[ix][iy] = met->pl[ix][iy][0];
9882 memcpy(met->pl, help, sizeof(met->pl));
9883 free(help);
9884 }
9885
9886 /* Read temperature at the surface... */
9887 if (!read_met_nc_2d
9888 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
9889 1))
9890 WARN("Cannot read surface temperature!");
9891
9892 /* Read zonal wind at the surface... */
9893 if (!read_met_nc_2d
9894 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
9895 met->us, 1.0, 1))
9896 WARN("Cannot read surface zonal wind!");
9897
9898 /* Read meridional wind at the surface... */
9899 if (!read_met_nc_2d
9900 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
9901 met->vs, 1.0, 1))
9902 WARN("Cannot read surface meridional wind!");
9903
9904 /* Read eastward turbulent surface stress... */
9905 if (!read_met_nc_2d
9906 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
9907 1.0, 1))
9908 WARN("Cannot read eastward turbulent surface stress!");
9909
9910 /* Read northward turbulent surface stress... */
9911 if (!read_met_nc_2d
9912 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
9913 1.0, 1))
9914 WARN("Cannot read nothward turbulent surface stress!");
9915
9916 /* Read surface sensible heat flux... */
9917 if (!read_met_nc_2d
9918 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
9919 1.0, 1))
9920 WARN("Cannot read surface sensible heat flux!");
9921
9922 /* Read land-sea mask... */
9923 if (!read_met_nc_2d
9924 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
9925 1.0, 1))
9926 WARN("Cannot read land-sea mask!");
9927
9928 /* Read sea surface temperature... */
9929 if (!read_met_nc_2d
9930 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
9931 1.0, 1))
9932 WARN("Cannot read sea surface temperature!");
9933
9934 /* Read PBL... */
9935 if (ctl->met_pbl == 0)
9936 if (!read_met_nc_2d
9937 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
9938 0.01f, 1))
9939 WARN("Cannot read planetary boundary layer pressure!");
9940 if (ctl->met_pbl == 1)
9941 if (!read_met_nc_2d
9942 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
9943 0.001f, 1))
9944 WARN("Cannot read planetary boundary layer height!");
9945
9946 /* Read CAPE... */
9947 if (ctl->met_cape == 0)
9948 if (!read_met_nc_2d
9949 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
9950 met->cape, 1.0, 1))
9951 WARN("Cannot read CAPE!");
9952
9953 /* Read CIN... */
9954 if (ctl->met_cape == 0)
9955 if (!read_met_nc_2d
9956 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
9957 1.0, 1))
9958 WARN("Cannot read convective inhibition!");
9959}
9960
9961/*****************************************************************************/
9962
9964 const int ncid,
9965 const ctl_t *ctl,
9966 met_t *met,
9967 dd_t *dd) {
9968
9969 /* Set timer... */
9970 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT");
9971 LOG(2, "Read level data...");
9972
9973 /* Read temperature... */
9974 if (!read_met_nc_3d
9975 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
9976 ERRMSG("Cannot read temperature!");
9977
9978 /* Read horizontal wind and vertical velocity... */
9979 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
9980 ERRMSG("Cannot read zonal wind!");
9981 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
9982 ERRMSG("Cannot read meridional wind!");
9983 if (!read_met_nc_3d
9984 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
9985 WARN("Cannot read vertical velocity!");
9986
9987 /* Read water vapor... */
9988 if (!ctl->met_relhum) {
9989 if (!read_met_nc_3d
9990 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
9991 (float) (MA / MH2O)))
9992 WARN("Cannot read specific humidity!");
9993 } else {
9994 if (!read_met_nc_3d
9995 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
9996 WARN("Cannot read relative humidity!");
9997#pragma omp parallel for default(shared) collapse(2)
9998 for (int ix = 0; ix < met->nx; ix++)
9999 for (int iy = 0; iy < met->ny; iy++)
10000 for (int ip = 0; ip < met->np; ip++) {
10001 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
10002 met->h2o[ix][iy][ip] =
10003 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
10004 }
10005 }
10006
10007 /* Read ozone... */
10008 if (!read_met_nc_3d
10009 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
10010 (float) (MA / MO3)))
10011 WARN("Cannot read ozone data!");
10012
10013 /* Read cloud data... */
10014 if (!read_met_nc_3d
10015 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
10016 WARN("Cannot read cloud liquid water content!");
10017 if (!read_met_nc_3d
10018 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
10019 WARN("Cannot read cloud rain water content!");
10020 if (!read_met_nc_3d
10021 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
10022 WARN("Cannot read cloud ice water content!");
10023 if (!read_met_nc_3d
10024 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
10025 WARN("Cannot read cloud snow water content!");
10026 if (!read_met_nc_3d
10027 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
10028 WARN("Cannot read cloud cover!");
10029
10030 /* Read zeta and zeta_dot... */
10031 if (ctl->advect_vert_coord == 1) {
10032 if (!read_met_nc_3d
10033 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
10034 WARN("Cannot read ZETA!");
10035 if (!read_met_nc_3d
10036 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
10037 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
10038 WARN("Cannot read ZETA_DOT!");
10039 }
10040
10041 /* Read eta and eta_dot... */
10042 else if (ctl->advect_vert_coord == 3) {
10043#pragma omp parallel for default(shared)
10044 for (int ix = 0; ix < met->nx; ix++)
10045 for (int iy = 0; iy < met->ny; iy++)
10046 for (int ip = 0; ip < met->np; ip++)
10047 met->zetal[ix][iy][ip] =
10048 (float) (met->hyam[ip] / 100000.0 + met->hybm[ip]);
10049 if (!read_met_nc_3d
10050 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
10051 1.0))
10052 WARN("Cannot read eta vertical velocity!");
10053 }
10054
10055 /* Store velocities on model levels... */
10056 if (ctl->met_vert_coord != 0) {
10057#pragma omp parallel for default(shared)
10058 for (int ix = 0; ix < met->nx; ix++)
10059 for (int iy = 0; iy < met->ny; iy++)
10060 for (int ip = 0; ip < met->np; ip++) {
10061 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
10062 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
10063 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
10064 }
10065
10066 /* Save number of model levels... */
10067 met->npl = met->np;
10068 }
10069
10070 /* Get pressure on model levels... */
10071 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
10072
10073 /* Read 3-D pressure field... */
10074 if (ctl->met_vert_coord == 1) {
10075 if (!read_met_nc_3d
10076 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
10077 0.01f))
10078 if (!read_met_nc_3d
10079 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
10080 ERRMSG("Cannot read pressure on model levels!");
10081 }
10082
10083 /* Use a and b coefficients for full levels (at layer midpoints)... */
10084 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
10085
10086 /* Check number of levels... */
10087 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
10088 ERRMSG("Mismatch in number of model levels!");
10089
10090 /* Calculate pressure... */
10091 for (int ix = 0; ix < met->nx; ix++)
10092 for (int iy = 0; iy < met->ny; iy++)
10093 for (int ip = 0; ip < met->np; ip++)
10094 met->pl[ix][iy][ip] =
10095 (float) (met->hyam[ip] / 100. +
10096 met->hybm[ip] * met->ps[ix][iy]);
10097 }
10098
10099 /* Use a and b coefficients for half levels (at layer interfaces)... */
10100 else if (ctl->met_vert_coord == 4) {
10101
10102 /* Check number of levels... */
10103 if (met->np + 1 != ctl->met_nlev)
10104 ERRMSG("Mismatch in number of model levels!");
10105
10106 /* Calculate pressure... */
10107#pragma omp parallel for default(shared) collapse(2)
10108 for (int ix = 0; ix < met->nx; ix++)
10109 for (int iy = 0; iy < met->ny; iy++)
10110 for (int ip = 0; ip < met->np; ip++) {
10111 const double p0 =
10112 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
10113 const double p1 =
10114 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
10115 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
10116 }
10117 }
10118
10119 /* Check ordering of pressure levels... */
10120 for (int ix = 0; ix < met->nx; ix++)
10121 for (int iy = 0; iy < met->ny; iy++)
10122 for (int ip = 1; ip < met->np; ip++)
10123 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
10124 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
10125 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
10126 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
10127 ERRMSG("Pressure profiles are not monotonic!");
10128 }
10129
10130 /* Interpolate from model levels to pressure levels... */
10131 if (ctl->met_np > 0) {
10132
10133 /* Interpolate variables... */
10134 read_met_ml2pl(ctl, met, met->t, "T");
10135 read_met_ml2pl(ctl, met, met->u, "U");
10136 read_met_ml2pl(ctl, met, met->v, "V");
10137 read_met_ml2pl(ctl, met, met->w, "W");
10138 read_met_ml2pl(ctl, met, met->h2o, "H2O");
10139 read_met_ml2pl(ctl, met, met->o3, "O3");
10140 read_met_ml2pl(ctl, met, met->lwc, "LWC");
10141 read_met_ml2pl(ctl, met, met->rwc, "RWC");
10142 read_met_ml2pl(ctl, met, met->iwc, "IWC");
10143 read_met_ml2pl(ctl, met, met->swc, "SWC");
10144 read_met_ml2pl(ctl, met, met->cc, "CC");
10145
10146 /* Set new pressure levels... */
10147 met->np = ctl->met_np;
10148 for (int ip = 0; ip < met->np; ip++)
10149 met->p[ip] = ctl->met_p[ip];
10150 }
10151
10152 /* Check ordering of pressure levels... */
10153 for (int ip = 1; ip < met->np; ip++)
10154 if (met->p[ip - 1] < met->p[ip])
10155 ERRMSG("Pressure levels must be descending!");
10156}
10157
10158/*****************************************************************************/
10159
10161 const int ncid,
10162 const char *varname,
10163 const char *varname2,
10164 const char *varname3,
10165 const char *varname4,
10166 const char *varname5,
10167 const char *varname6,
10168 const ctl_t *ctl,
10169 const met_t *met,
10170 dd_t *dd,
10171 float dest[EX][EY],
10172 const float scl,
10173 const int init) {
10174
10175 char varsel[LEN];
10176
10177 float offset, scalfac;
10178
10179 int varid;
10180
10181 /* Check if variable exists... */
10182 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
10183 sprintf(varsel, "%s", varname);
10184 else if (varname2 != NULL
10185 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
10186 sprintf(varsel, "%s", varname2);
10187 else if (varname3 != NULL
10188 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
10189 sprintf(varsel, "%s", varname3);
10190 else if (varname4 != NULL
10191 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
10192 sprintf(varsel, "%s", varname4);
10193 else if (varname5 != NULL
10194 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
10195 sprintf(varsel, "%s", varname5);
10196 else if (varname6 != NULL
10197 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
10198 sprintf(varsel, "%s", varname6);
10199 else
10200 return 0;
10201
10202 /* Read packed data... */
10203 if (ctl->met_nc_scale && !ctl->dd
10204 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
10205 && nc_get_att_float(ncid, varid, "scale_factor",
10206 &scalfac) == NC_NOERR) {
10207
10208 /* Allocate... */
10209 short *help;
10210 ALLOC(help, short,
10211 EX * EY * EP);
10212
10213 /* Read fill value and missing value... */
10214 short fillval, missval;
10215 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10216 fillval = 0;
10217 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
10218 missval = 0;
10219
10220 /* Write info... */
10221 LOG(2, "Read 2-D variable: %s"
10222 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
10223 varsel, fillval, missval, scalfac, offset);
10224
10225 /* Read data... */
10226 NC(nc_get_var_short(ncid, varid, help));
10227
10228 /* Check meteo data layout... */
10229 if (ctl->met_convention != 0)
10230 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
10231
10232 /* Copy and check data... */
10233 omp_set_dynamic(1);
10234#pragma omp parallel for default(shared)
10235 for (int ix = 0; ix < met->nx; ix++)
10236 for (int iy = 0; iy < met->ny; iy++) {
10237 if (init)
10238 dest[ix][iy] = 0;
10239 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
10240 if ((fillval == 0 || aux != fillval)
10241 && (missval == 0 || aux != missval)
10242 && fabsf(aux * scalfac + offset) < 1e14f)
10243 dest[ix][iy] += scl * (aux * scalfac + offset);
10244 else
10245 dest[ix][iy] = NAN;
10246 }
10247 omp_set_dynamic(0);
10248
10249 /* Free... */
10250 free(help);
10251 }
10252
10253 /* Unpacked data... */
10254 else if (!ctl->dd) {
10255
10256 /* Allocate... */
10257 float *help;
10258 ALLOC(help, float,
10259 EX * EY);
10260
10261 /* Read fill value and missing value... */
10262 float fillval, missval;
10263 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10264 fillval = 0;
10265 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10266 missval = 0;
10267
10268 /* Write info... */
10269 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
10270 varsel, fillval, missval);
10271
10272 /* Read data... */
10273 NC(nc_get_var_float(ncid, varid, help));
10274
10275 /* Check meteo data layout... */
10276 if (ctl->met_convention == 0) {
10277
10278 /* Copy and check data (ordering: lat, lon)... */
10279 omp_set_dynamic(1);
10280#pragma omp parallel for default(shared)
10281 for (int ix = 0; ix < met->nx; ix++)
10282 for (int iy = 0; iy < met->ny; iy++) {
10283 if (init)
10284 dest[ix][iy] = 0;
10285 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
10286 if ((fillval == 0 || aux != fillval)
10287 && (missval == 0 || aux != missval)
10288 && fabsf(aux) < 1e14f)
10289 dest[ix][iy] += scl * aux;
10290 else
10291 dest[ix][iy] = NAN;
10292 }
10293 omp_set_dynamic(0);
10294
10295 } else {
10296
10297 /* Copy and check data (ordering: lon, lat)... */
10298 omp_set_dynamic(1);
10299#pragma omp parallel for default(shared)
10300 for (int iy = 0; iy < met->ny; iy++)
10301 for (int ix = 0; ix < met->nx; ix++) {
10302 if (init)
10303 dest[ix][iy] = 0;
10304 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
10305 if ((fillval == 0 || aux != fillval)
10306 && (missval == 0 || aux != missval)
10307 && fabsf(aux) < 1e14f)
10308 dest[ix][iy] += scl * aux;
10309 else
10310 dest[ix][iy] = NAN;
10311 }
10312 omp_set_dynamic(0);
10313 }
10314
10315 /* Free... */
10316 free(help);
10317 }
10318
10319 /* Domain decomposed data... */
10320 else {
10321
10322 /* Read fill value and missing value... */
10323 float fillval, missval;
10324 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10325 fillval = 0;
10326 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10327 missval = 0;
10328
10329 /* Write info... */
10330 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
10331 varsel, fillval, missval);
10332
10333 /* Define hyperslab... */
10334 float *help;
10335 size_t help_subdomain_start[3];
10336 size_t help_subdomain_count[3];
10337
10338 help_subdomain_start[0] = 0;
10339 if (ctl->met_convention == 0) {
10340 help_subdomain_start[1] = dd->subdomain_start[2];
10341 help_subdomain_start[2] = dd->subdomain_start[3];
10342 } else {
10343 help_subdomain_start[1] = dd->subdomain_start[3];
10344 help_subdomain_start[2] = dd->subdomain_start[2];
10345 }
10346
10347 help_subdomain_count[0] = 1;
10348 if (ctl->met_convention == 0) {
10349 help_subdomain_count[1] = dd->subdomain_count[2]; //y
10350 help_subdomain_count[2] = dd->subdomain_count[3]; //x
10351 } else {
10352 help_subdomain_count[1] = dd->subdomain_count[3]; //x
10353 help_subdomain_count[2] = dd->subdomain_count[2]; //y
10354 }
10355
10356 ALLOC(help, float,
10357 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
10358
10359 /* Read data... */
10360#ifdef DD
10361 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
10362#endif
10363 NC(nc_get_vara_float
10364 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
10365
10366 /* Read halos at boundaries... */
10367 size_t help_halo_bnd_start[3];
10368 size_t help_halo_bnd_count[3];
10369
10370 help_halo_bnd_start[0] = 0;
10371 if (ctl->met_convention == 0) {
10372 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
10373 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
10374 } else {
10375 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
10376 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
10377 }
10378
10379 help_halo_bnd_count[0] = 1;
10380 if (ctl->met_convention == 0) {
10381 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
10382 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
10383 } else {
10384 help_halo_bnd_count[1] = dd->halo_bnd_count[3]; //x
10385 help_halo_bnd_count[2] = dd->halo_bnd_count[2]; //y
10386 }
10387
10388 float *help_halo;
10389 ALLOC(help_halo, float,
10390 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
10391
10392#ifdef DD
10393 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
10394#endif
10395 NC(nc_get_vara_float
10396 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
10397
10398 /* Check meteo data layout... */
10399 if (ctl->met_convention == 0) {
10400
10401 /* Copy and check data (ordering: lat, lon)... */
10402 omp_set_dynamic(1);
10403#pragma omp parallel for default(shared)
10404 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
10405 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
10406 if (init == 1)
10407 dest[ix + dd->halo_offset_start][iy] = 0;
10408 const float aux =
10409 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
10410 if ((fillval == 0 || aux != fillval)
10411 && (missval == 0 || aux != missval)
10412 && fabsf(aux) < 1e14f) {
10413 dest[ix + dd->halo_offset_start][iy] += scl * aux;
10414 } else
10415 dest[ix + dd->halo_offset_start][iy] = NAN;
10416 }
10417
10418#pragma omp parallel for default(shared)
10419 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
10420 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
10421 if (init == 1)
10422 dest[ix + dd->halo_offset_end][iy] = 0;
10423 const float aux =
10424 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
10425 if ((fillval == 0 || aux != fillval)
10426 && (missval == 0 || aux != missval)
10427 && fabsf(aux) < 1e14f)
10428 dest[ix + dd->halo_offset_end][iy] += scl * aux;
10429 else {
10430 dest[ix + dd->halo_offset_end][iy] = NAN;
10431 }
10432 }
10433 omp_set_dynamic(0);
10434
10435 } else {
10436
10437 /* Copy and check data (ordering: lon, lat)... */
10438 omp_set_dynamic(1);
10439#pragma omp parallel for default(shared)
10440 for (int ix = 0; ix < (int) help_subdomain_count[1]; ix++)
10441 for (int iy = 0; iy < (int) help_subdomain_count[2]; iy++) {
10442 if (init == 1)
10443 dest[ix + dd->halo_offset_start][iy] = 0;
10444 const float aux =
10445 help[ARRAY_2D(ix, iy, (int) help_subdomain_count[1])];
10446 if ((fillval == 0 || aux != fillval)
10447 && (missval == 0 || aux != missval)
10448 && fabsf(aux) < 1e14f)
10449 dest[ix + dd->halo_offset_start][iy] += scl * aux;
10450 else
10451 dest[ix + dd->halo_offset_start][iy] = NAN;
10452 }
10453
10454#pragma omp parallel for default(shared)
10455 for (int ix = 0; ix < (int) help_halo_bnd_count[1]; ix++)
10456 for (int iy = 0; iy < (int) help_halo_bnd_count[2]; iy++) {
10457 if (init == 1)
10458 dest[ix + dd->halo_offset_end][iy] = 0;
10459 const float aux =
10460 help_halo[ARRAY_2D(ix, iy, (int) help_halo_bnd_count[1])];
10461 if ((fillval == 0 || aux != fillval)
10462 && (missval == 0 || aux != missval)
10463 && fabsf(aux) < 1e14f)
10464 dest[ix + dd->halo_offset_end][iy] += scl * aux;
10465 else
10466 dest[ix + dd->halo_offset_end][iy] = NAN;
10467 }
10468 omp_set_dynamic(0);
10469 }
10470
10471 /* Free... */
10472 free(help);
10473 free(help_halo);
10474 }
10475
10476 /* Return... */
10477 return 1;
10478}
10479
10480/*****************************************************************************/
10481
10483 const int ncid,
10484 const char *varname,
10485 const char *varname2,
10486 const char *varname3,
10487 const char *varname4,
10488 const ctl_t *ctl,
10489 const met_t *met,
10490 dd_t *dd,
10491 float dest[EX][EY][EP],
10492 const float scl) {
10493
10494 char varsel[LEN];
10495
10496 float offset, scalfac;
10497
10498 int varid;
10499
10500 /* Check if variable exists... */
10501 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
10502 sprintf(varsel, "%s", varname);
10503 else if (varname2 != NULL
10504 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
10505 sprintf(varsel, "%s", varname2);
10506 else if (varname3 != NULL
10507 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
10508 sprintf(varsel, "%s", varname3);
10509 else if (varname4 != NULL
10510 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
10511 sprintf(varsel, "%s", varname4);
10512 else
10513 return 0;
10514
10515 /* Read packed data... */
10516 if (ctl->met_nc_scale && !ctl->dd
10517 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
10518 && nc_get_att_float(ncid, varid, "scale_factor",
10519 &scalfac) == NC_NOERR) {
10520
10521 /* Allocate... */
10522 short *help;
10523 ALLOC(help, short,
10524 EX * EY * EP);
10525
10526 /* Read fill value and missing value... */
10527 short fillval, missval;
10528 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10529 fillval = 0;
10530 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
10531 missval = 0;
10532
10533 /* Write info... */
10534 LOG(2, "Read 3-D variable: %s "
10535 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
10536 varsel, fillval, missval, scalfac, offset);
10537
10538 /* Read data... */
10539 NC(nc_get_var_short(ncid, varid, help));
10540
10541 /* Check meteo data layout... */
10542 if (ctl->met_convention != 0)
10543 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
10544
10545 /* Copy and check data... */
10546 omp_set_dynamic(1);
10547#pragma omp parallel for default(shared)
10548 for (int ix = 0; ix < met->nx; ix++)
10549 for (int iy = 0; iy < met->ny; iy++)
10550 for (int ip = 0; ip < met->np; ip++) {
10551 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
10552 if ((fillval == 0 || aux != fillval)
10553 && (missval == 0 || aux != missval)
10554 && fabsf(aux * scalfac + offset) < 1e14f)
10555 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
10556 else
10557 dest[ix][iy][ip] = NAN;
10558 }
10559 omp_set_dynamic(0);
10560
10561 /* Free... */
10562 free(help);
10563 }
10564
10565 /* Unpacked data... */
10566 else if (!ctl->dd) {
10567
10568 /* Allocate... */
10569 float *help;
10570 ALLOC(help, float,
10571 EX * EY * EP);
10572
10573 /* Read fill value and missing value... */
10574 float fillval, missval;
10575 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10576 fillval = 0;
10577 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10578 missval = 0;
10579
10580 /* Write info... */
10581 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
10582 varsel, fillval, missval);
10583
10584 /* Read data... */
10585 NC(nc_get_var_float(ncid, varid, help));
10586
10587 /* Check meteo data layout... */
10588 if (ctl->met_convention == 0) {
10589
10590 /* Copy and check data (ordering: lev, lat, lon)... */
10591 omp_set_dynamic(1);
10592#pragma omp parallel for default(shared)
10593 for (int ix = 0; ix < met->nx; ix++)
10594 for (int iy = 0; iy < met->ny; iy++)
10595 for (int ip = 0; ip < met->np; ip++) {
10596 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
10597 if ((fillval == 0 || aux != fillval)
10598 && (missval == 0 || aux != missval)
10599 && fabsf(aux) < 1e14f)
10600 dest[ix][iy][ip] = scl * aux;
10601 else
10602 dest[ix][iy][ip] = NAN;
10603 }
10604 omp_set_dynamic(0);
10605
10606 } else {
10607
10608 /* Copy and check data (ordering: lon, lat, lev)... */
10609 omp_set_dynamic(1);
10610#pragma omp parallel for default(shared)
10611 for (int ip = 0; ip < met->np; ip++)
10612 for (int iy = 0; iy < met->ny; iy++)
10613 for (int ix = 0; ix < met->nx; ix++) {
10614 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
10615 if ((fillval == 0 || aux != fillval)
10616 && (missval == 0 || aux != missval)
10617 && fabsf(aux) < 1e14f)
10618 dest[ix][iy][ip] = scl * aux;
10619 else
10620 dest[ix][iy][ip] = NAN;
10621 }
10622 omp_set_dynamic(0);
10623 }
10624
10625 /* Free... */
10626 free(help);
10627 }
10628
10629 /* Domain decomposed data... */
10630 else {
10631
10632 /* Read fill value and missing value... */
10633 float fillval, missval;
10634 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10635 fillval = 0;
10636 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10637 missval = 0;
10638
10639 /* Write info... */
10640 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
10641 varsel, fillval, missval);
10642
10643 /* Define hyperslab... */
10644 size_t help_subdomain_start[4];
10645 size_t help_subdomain_count[4];
10646 size_t help_halo_bnd_start[4];
10647 size_t help_halo_bnd_count[4];
10648
10649 if (ctl->met_convention == 0) {
10650 for (int i = 0; i < 4; i++) {
10651 help_subdomain_start[i] = dd->subdomain_start[i];
10652 help_subdomain_count[i] = dd->subdomain_count[i];
10653 help_halo_bnd_start[i] = dd->halo_bnd_start[i];
10654 help_halo_bnd_count[i] = dd->halo_bnd_count[i];
10655 }
10656 } else {
10657 help_subdomain_start[0] = dd->subdomain_start[0];
10658 help_subdomain_start[1] = dd->subdomain_start[3];
10659 help_subdomain_start[2] = dd->subdomain_start[2];
10660 help_subdomain_start[3] = dd->subdomain_start[1];
10661
10662 help_subdomain_count[0] = dd->subdomain_count[0];
10663 help_subdomain_count[1] = dd->subdomain_count[3];
10664 help_subdomain_count[2] = dd->subdomain_count[2];
10665 help_subdomain_count[3] = dd->subdomain_count[1];
10666
10667 help_halo_bnd_start[0] = dd->halo_bnd_start[0];
10668 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
10669 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
10670 help_halo_bnd_start[3] = dd->halo_bnd_start[1];
10671
10672 help_halo_bnd_count[0] = dd->halo_bnd_count[0];
10673 help_halo_bnd_count[1] = dd->halo_bnd_count[3];
10674 help_halo_bnd_count[2] = dd->halo_bnd_count[2];
10675 help_halo_bnd_count[3] = dd->halo_bnd_count[1];
10676 }
10677
10678 /* Allocate... */
10679 float *help;
10680 ALLOC(help, float,
10681 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
10682 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
10683
10684 /* Use default NetCDF parallel I/O behavior */
10685#ifdef DD
10686 NC(nc_var_par_access(ncid, varid, NC_INDEPENDENT));
10687#endif
10688 NC(nc_get_vara_float
10689 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
10690
10691 /* Read halos separately at boundaries... */
10692 float *help_halo;
10693 ALLOC(help_halo, float,
10694 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
10695 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
10696
10697#ifdef DD
10698 NC(nc_var_par_access(ncid, varid, NC_INDEPENDENT));
10699#endif
10700 if (dd->halo_bnd_count[1] > 0 && dd->halo_bnd_count[2] > 0
10701 && dd->halo_bnd_count[3] > 0) {
10702 NC(nc_get_vara_float
10703 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
10704 }
10705
10706 /* Check meteo data layout... */
10707 if (ctl->met_convention == 0) {
10708
10709 /* Copy and check data (ordering: lev, lat, lon)... */
10710 omp_set_dynamic(1);
10711#pragma omp parallel for default(shared)
10712 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
10713 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10714 for (int ip = 0; ip < met->np; ip++) {
10715 const float aux =
10716 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
10717 (int) dd->subdomain_count[3])];
10718 if ((fillval == 0 || aux != fillval)
10719 && (missval == 0 || aux != missval)
10720 && fabsf(aux) < 1e14f) {
10721 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10722
10723 } else
10724 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10725 }
10726
10727#pragma omp parallel for default(shared)
10728 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
10729 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10730 for (int ip = 0; ip < met->np; ip++) {
10731 const float aux =
10732 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
10733 (int) dd->halo_bnd_count[3])];
10734 if ((fillval == 0 || aux != fillval)
10735 && (missval == 0 || aux != missval)
10736 && fabsf(aux) < 1e14f)
10737 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10738 else
10739 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10740 }
10741 omp_set_dynamic(0);
10742
10743 } else {
10744
10745 /* Copy and check data (ordering: lon, lat, lev)... */
10746 omp_set_dynamic(1);
10747#pragma omp parallel for default(shared)
10748 for (int ip = 0; ip < met->np; ip++)
10749 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10750 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
10751 const float aux =
10752 help[ARRAY_3D
10753 (ix, iy, (int) dd->subdomain_count[2], ip, met->np)];
10754 if ((fillval == 0 || aux != fillval)
10755 && (missval == 0 || aux != missval)
10756 && fabsf(aux) < 1e14f)
10757 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10758 else
10759 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10760 }
10761
10762#pragma omp parallel for default(shared)
10763 for (int ip = 0; ip < met->np; ip++)
10764 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10765 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
10766 const float aux =
10767 help_halo[ARRAY_3D(ix, iy, (int) dd->halo_bnd_count[2], ip,
10768 met->np)];
10769 if ((fillval == 0 || aux != fillval)
10770 && (missval == 0 || aux != missval)
10771 && fabsf(aux) < 1e14f)
10772 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10773 else
10774 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10775 }
10776 omp_set_dynamic(0);
10777 }
10778
10779 /* Free... */
10780 free(help);
10781 free(help_halo);
10782 }
10783
10784 /* Return... */
10785 return 1;
10786}
10787
10788/*****************************************************************************/
10789
10790#ifdef ECCODES
10791int read_met_grib(
10792 const char *filename,
10793 const ctl_t *ctl,
10794 met_t *met) {
10795
10796 /* Set filenames... */
10797 size_t filename_len = strlen(filename) + 1;
10798 char sf_filename[filename_len];
10799 char ml_filename[filename_len];
10800 strcpy(sf_filename, filename);
10801 strcpy(ml_filename, filename);
10802 get_met_replace(ml_filename, "XX", "ml");
10803 get_met_replace(sf_filename, "XX", "sf");
10804
10805 /* Open files... */
10806 FILE *ml_file = fopen(ml_filename, "rb");
10807 FILE *sf_file = fopen(sf_filename, "rb");
10808 if (ml_file == NULL || sf_file == NULL) {
10809 if (ml_file != NULL) {
10810 fclose(ml_file);
10811 WARN("Cannot open file: %s", sf_filename);
10812 }
10813 if (sf_file != NULL) {
10814 fclose(sf_file);
10815 WARN("Cannot open file: %s", ml_filename);
10816 }
10817 return 0;
10818 }
10819
10820 /* Get handles for model level data... */
10821 int ml_num_messages = 0, err = 0;
10822 ECC(codes_count_in_file(0, ml_file, &ml_num_messages));
10823 codes_handle **ml_handles =
10824 (codes_handle **) malloc(sizeof(codes_handle *) *
10825 (size_t) ml_num_messages);
10826 for (int i = 0; i < ml_num_messages; i++) {
10827 codes_handle *h = NULL;
10828 if ((h = codes_grib_handle_new_from_file(0, ml_file, &err)) != NULL)
10829 ml_handles[i] = h;
10830 }
10831
10832 /* Get handles for surface data... */
10833 int sf_num_messages = 0;
10834 ECC(codes_count_in_file(0, sf_file, &sf_num_messages));
10835 codes_handle **sf_handles =
10836 (codes_handle **) malloc(sizeof(codes_handle *) *
10837 (size_t) sf_num_messages);
10838 for (int i = 0; i < sf_num_messages; i++) {
10839 codes_handle *h = NULL;
10840 if ((h = codes_grib_handle_new_from_file(0, sf_file, &err)) != NULL)
10841 sf_handles[i] = h;
10842 }
10843
10844 /* Close files... */
10845 fclose(ml_file);
10846 fclose(sf_file);
10847
10848 /* Read grid data... */
10849 read_met_grib_grid(ml_handles, ml_num_messages, met);
10850
10851 /* Read surface data... */
10852 read_met_grib_surface(sf_handles, sf_num_messages, ctl, met);
10853 for (int i = 0; i < sf_num_messages; i++)
10854 codes_handle_delete(sf_handles[i]);
10855 free(sf_handles);
10856
10857 /* Compute 3D pressure field... */
10858 size_t value_count = 0;
10859 ECC(codes_get_size(ml_handles[0], "pv", &value_count));
10860 if (value_count % 2 != 0)
10861 ERRMSG("Unexpected pv array length!");
10862 size_t nlevels = value_count / 2 - 1; /* number of full model levels */
10863 double *values;
10864 ALLOC(values, double,
10865 value_count);
10866 ECC(codes_get_double_array(ml_handles[0], "pv", values, &value_count));
10867 double *a_vals = values;
10868 double *b_vals = values + nlevels;
10869 if (met->npl > (int) nlevels)
10870 ERRMSG("met->npl exceeds number of pressure levels in GRIB!");
10871 for (int nx = 0; nx < met->nx; nx++)
10872 for (int ny = 0; ny < met->ny; ny++)
10873 for (int level = 0; level <= met->npl; level++) {
10874 const float p1 = (float) (a_vals[level] * 0.01f +
10875 met->ps[nx][ny] * b_vals[level]);
10876 const float p2 = (float) (a_vals[level + 1] * 0.01f +
10877 met->ps[nx][ny] * b_vals[level + 1]);
10878 met->pl[nx][ny][level] = 0.5f * (p1 + p2);
10879 }
10880 free(values);
10881
10882 /* Read model level data... */
10883 read_met_grib_levels(ml_handles, ml_num_messages, ctl, met);
10884 for (int i = 0; i < ml_num_messages; i++)
10885 codes_handle_delete(ml_handles[i]);
10886 free(ml_handles);
10887
10888 /* Return success... */
10889 return 1;
10890}
10891#endif
10892
10893/*****************************************************************************/
10894
10895#ifdef ECCODES
10897 codes_handle **handles,
10898 int count_handles,
10899 met_t *met) {
10900
10901 /* Set timer... */
10902 SELECT_TIMER("READ_MET_GRIB_GRID", "INPUT");
10903 LOG(2, "Read meteo grid information...");
10904
10905 /* Read date and time... */
10906 char datestr[LEN], timestr[LEN];
10907 size_t s_date = sizeof(datestr);
10908 ECC(codes_get_string(handles[0], "dataDate", datestr, &s_date));
10909 size_t s_time = sizeof(timestr);
10910 ECC(codes_get_string(handles[0], "dataTime", timestr, &s_time));
10911 int year, month, day, hour;
10912 if (sscanf(datestr, "%4d%2d%2d", &year, &month, &day) != 3)
10913 ERRMSG("Failed to parse dataDate: %s", datestr);
10914 if (sscanf(timestr, "%2d", &hour) != 1)
10915 ERRMSG("Failed to parse dataTime: %s", timestr);
10916 time2jsec(year, month, day, hour, 0, 0, 0, &(met->time));
10917 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)", met->time, year, month,
10918 day, hour, 0);
10919
10920 /* Read grid information... */
10921 long count_lat = 0, count_lon = 0;
10922 ECC(codes_get_long(handles[0], "Nj", &count_lat));
10923 ECC(codes_get_long(handles[0], "Ni", &count_lon));
10924 met->ny = (int) count_lat;
10925 met->nx = (int) count_lon;
10926
10927 /* Check grid dimensions... */
10928 LOG(2, "Number of longitudes: %d", met->nx);
10929 if (met->nx < 2 || met->nx > EX)
10930 ERRMSG("Number of longitudes out of range!");
10931 LOG(2, "Number of latitudes: %d", met->ny);
10932 if (met->ny < 2 || met->ny > EY)
10933 ERRMSG("Number of latitudes out of range!");
10934
10935 double first_lon, last_lon, first_lat, last_lat, inc_lon, inc_lat;
10936 ECC(codes_get_double
10937 (handles[0], "longitudeOfFirstGridPointInDegrees", &first_lon));
10938 ECC(codes_get_double
10939 (handles[0], "latitudeOfFirstGridPointInDegrees", &first_lat));
10940 ECC(codes_get_double
10941 (handles[0], "longitudeOfLastGridPointInDegrees", &last_lon));
10942 ECC(codes_get_double
10943 (handles[0], "latitudeOfLastGridPointInDegrees", &last_lat));
10944 ECC(codes_get_double(handles[0], "iDirectionIncrementInDegrees", &inc_lon));
10945 ECC(codes_get_double(handles[0], "jDirectionIncrementInDegrees", &inc_lat));
10946
10947 long jscanpos, iscanneg;
10948 ECC(codes_get_long(handles[0], "iScansNegatively", &iscanneg));
10949 ECC(codes_get_long(handles[0], "jScansPositively", &jscanpos));
10950
10951 /* Compute longitude-latitude grid... */
10952 int counter = 0;
10953 if (iscanneg == 0)
10954 for (double i = first_lon; i <= last_lon + 1e-6; i += inc_lon) {
10955 met->lon[counter] = i;
10956 counter++;
10957 } else
10958 for (double i = first_lon; i > last_lon - 1e-6; i -= inc_lon) {
10959 met->lon[counter] = i;
10960 counter++;
10961 }
10962
10963 counter = 0;
10964 if (jscanpos == 0)
10965 for (double i = first_lat; i > last_lat - 1e-6; i -= inc_lat) {
10966 met->lat[counter] = i;
10967 counter++;
10968 } else
10969 for (double i = first_lat; i <= last_lat + 1e-6; i += inc_lat) {
10970 met->lat[counter] = i;
10971 counter++;
10972 }
10973
10974 /* Write info... */
10975 LOG(2, "Longitudes: %g, %g ... %g deg",
10976 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
10977 LOG(2, "Latitudes: %g, %g ... %g deg",
10978 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
10979
10980 /* Read vertical levels... */
10981 int max_level = 0;
10982 for (int i = 0; i < count_handles; i++) {
10983 long level;
10984 ECC(codes_get_long(handles[i], "level", &level));
10985 if (level > max_level)
10986 max_level = (int) level;
10987 }
10988 met->npl = max_level;
10989
10990 /* Check number of levels... */
10991 LOG(2, "Number of levels: %d", met->npl);
10992 if (met->npl < 2 || met->npl > EP)
10993 ERRMSG("Number of levels out of range!");
10994}
10995#endif
10996
10997/*****************************************************************************/
10998
10999#ifdef ECCODES
11001 codes_handle **handles,
11002 const int num_messages,
11003 const ctl_t *ctl,
11004 met_t *met) {
11005
11006 /* Set timer... */
11007 SELECT_TIMER("READ_MET_GRIB_LEVELS", "INPUT");
11008 LOG(2, "Read level data...");
11009
11010 /* Init... */
11011 int t_flag = 0, u_flag = 0, v_flag = 0, w_flag = 0, o3_flag = 0, h2o_flag =
11012 0, lwc_flag = 0, rwc_flag = 0, iwc_flag = 0, swc_flag = 0, cc_flag = 0;
11013
11014 /* Iterate over all messages... */
11015 for (int i = 0; i < num_messages; i++) {
11016
11017 size_t max_size = LEN;
11018 char short_name[max_size];
11019 size_t value_count;
11020 double *values;
11021
11022 /* Get the current level */
11023 long current_level;
11024 ECC(codes_get_long(handles[i], "level", &current_level));
11025 current_level -= 1;
11026
11027 /* Retrieve data from current message */
11028 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
11029 ECC(codes_get_size(handles[i], "values", &value_count));
11030 ALLOC(values, double,
11031 value_count);
11032 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
11033
11034 /* Read temperature... */
11035 ECC_READ_3D("t", current_level, met->t, 1.0, t_flag);
11036
11037 /* Read horizontal wind and vertical velocity... */
11038 ECC_READ_3D("u", current_level, met->u, 1.0, u_flag);
11039 ECC_READ_3D("v", current_level, met->v, 1.0, v_flag);
11040 ECC_READ_3D("w", current_level, met->w, 0.01f, w_flag);
11041
11042 /* Read water vapor and ozone... */
11043 ECC_READ_3D("q", current_level, met->h2o, (float) (MA / MH2O), h2o_flag);
11044 ECC_READ_3D("o3", current_level, met->o3, (float) (MA / MO3), o3_flag);
11045
11046 /* Read cloud data... */
11047 ECC_READ_3D("clwc", current_level, met->lwc, 1.0, lwc_flag);
11048 ECC_READ_3D("crwc", current_level, met->rwc, 1.0, rwc_flag);
11049 ECC_READ_3D("ciwc", current_level, met->iwc, 1.0, iwc_flag);
11050 ECC_READ_3D("cswc", current_level, met->swc, 1.0, swc_flag);
11051 ECC_READ_3D("cc", current_level, met->cc, 1.0, cc_flag);
11052
11053 /*Free allocated array */
11054 free(values);
11055 }
11056
11057 /* Check whether data were found... */
11058 if (t_flag != met->npl)
11059 ERRMSG("Cannot read temperature!");
11060 if (u_flag != met->npl)
11061 ERRMSG("Cannot read zonal wind!");
11062 if (v_flag != met->npl)
11063 ERRMSG("Cannot read meridional wind!");
11064 if (w_flag != met->npl)
11065 WARN("Cannot read vertical velocity!");
11066 if (h2o_flag != met->npl)
11067 WARN("Cannot read specific humidity!");
11068 if (o3_flag != met->npl)
11069 WARN("Cannot read ozone data!");
11070 if (lwc_flag != met->npl)
11071 WARN("Cannot read cloud liquid water content!");
11072 if (rwc_flag != met->npl)
11073 WARN("Cannot read cloud rain water content!");
11074 if (iwc_flag != met->npl)
11075 WARN("Cannot read cloud ice water content!");
11076 if (swc_flag != met->npl)
11077 WARN("Cannot read cloud snow water content!");
11078 if (cc_flag != met->npl)
11079 WARN("Cannot read cloud cover!");
11080
11081 /* Check ordering of pressure levels... */
11082 for (int ix = 0; ix < met->nx; ix++)
11083 for (int iy = 0; iy < met->ny; iy++)
11084 for (int ip = 1; ip < met->np; ip++)
11085 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
11086 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
11087 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
11088 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip])) {
11089 LOG(1, "%f %f %f %f", met->pl[ix][iy][0], met->pl[ix][iy][1],
11090 met->pl[ix][iy][ip - 1], met->pl[ix][iy][ip]);
11091 ERRMSG("Pressure profiles are not monotonic!");
11092 }
11093
11094 /* Interpolate from model levels to pressure levels... */
11095 if (ctl->met_np > 0) {
11096 met->np = ctl->met_np;
11097
11098 /* Interpolate variables... */
11099 read_met_ml2pl(ctl, met, met->t, "T");
11100 read_met_ml2pl(ctl, met, met->u, "U");
11101 read_met_ml2pl(ctl, met, met->v, "V");
11102 read_met_ml2pl(ctl, met, met->w, "W");
11103 read_met_ml2pl(ctl, met, met->h2o, "H2O");
11104 read_met_ml2pl(ctl, met, met->o3, "O3");
11105 read_met_ml2pl(ctl, met, met->lwc, "LWC");
11106 read_met_ml2pl(ctl, met, met->rwc, "RWC");
11107 read_met_ml2pl(ctl, met, met->iwc, "IWC");
11108 read_met_ml2pl(ctl, met, met->swc, "SWC");
11109 read_met_ml2pl(ctl, met, met->cc, "CC");
11110
11111 /* Set new pressure levels... */
11112 for (int ip = 0; ip < met->np; ip++)
11113 met->p[ip] = ctl->met_p[ip];
11114 }
11115
11116 /* Check ordering of pressure levels... */
11117 for (int ip = 1; ip < met->np; ip++)
11118 if (met->p[ip - 1] < met->p[ip])
11119 ERRMSG("Pressure levels must be descending!");
11120}
11121#endif
11122
11123/*****************************************************************************/
11124
11125#ifdef ECCODES
11127 codes_handle **handles,
11128 const int num_messages,
11129 const ctl_t *ctl,
11130 met_t *met) {
11131
11132 /* Set timer... */
11133 SELECT_TIMER("READ_MET_GRIB_SURFACE", "INPUT");
11134 LOG(2, "Read surface data...");
11135
11136 /* Init... */
11137 int sp_flag = 0, z_flag = 0, t_flag = 0, u_flag = 0, v_flag = 0, ess_flag =
11138 0, nss_flag = 0, shf_flag = 0, lsm_flag = 0, sst_flag = 0, cape_flag = 0,
11139 cin_flag = 0, pbl_flag = 0;
11140
11141 /* Iterate over all messages... */
11142 for (int i = 0; i < num_messages; i++) {
11143
11144 size_t max_size = LEN, value_count;
11145
11146 char short_name[max_size];
11147
11148 /* Store values with shortname... */
11149 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
11150 ECC(codes_get_size(handles[i], "values", &value_count));
11151 double *values = (double *) malloc(value_count * sizeof(double));
11152 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
11153
11154 /*Read surface pressure... */
11155 ECC_READ_2D("sp", met->ps, 0.01f, sp_flag);
11156
11157 /*Read geopotential height at the surface... */
11158 ECC_READ_2D("z", met->zs, (float) (1. / (1000. * G0)), z_flag);
11159
11160 /* Read temperature at the surface... */
11161 ECC_READ_2D("2t", met->ts, 1.0f, t_flag);
11162
11163 /* Read zonal wind at the surface... */
11164 ECC_READ_2D("10u", met->us, 1.0f, u_flag);
11165
11166 /* Read meridional wind at the surface... */
11167 ECC_READ_2D("10v", met->vs, 1.0f, v_flag);
11168
11169 /* Read eastward turbulent surface stress... */
11170 ECC_READ_2D("iews", met->ess, 1.0f, ess_flag);
11171
11172 /* Read northward turbulent surface stress... */
11173 ECC_READ_2D("inss", met->nss, 1.0f, nss_flag);
11174
11175 /* Read surface sensible heat flux... */
11176 ECC_READ_2D("ishf", met->shf, 1.0f, shf_flag);
11177
11178 /* Read land-sea mask... */
11179 ECC_READ_2D("lsm", met->lsm, 1.0f, lsm_flag);
11180
11181 /* Read sea surface temperature... */
11182 ECC_READ_2D("sst", met->sst, 1.0f, sst_flag);
11183 if (ctl->met_cape == 0) {
11184
11185 /* Read CAPE... */
11186 ECC_READ_2D("cape", met->cape, 1.0f, cape_flag);
11187
11188 /* Read CIN... */
11189 ECC_READ_2D("cin", met->cin, 1.0f, cin_flag);
11190 }
11191
11192 /* Read PBL... */
11193 if (ctl->met_pbl == 1)
11194 ECC_READ_2D("blh", met->pbl, 0.001f, pbl_flag);
11195 }
11196
11197 /* Check whether data have been read... */
11198 if (sp_flag == 0)
11199 WARN("Cannot read surface pressure data!");
11200 if (z_flag == 0)
11201 WARN("Cannot read surface geopotential height!");
11202 if (t_flag == 0)
11203 WARN("Cannot read surface temperature!");
11204 if (u_flag == 0)
11205 WARN("Cannot read surface zonal wind!");
11206 if (v_flag == 0)
11207 WARN("Cannot read surface meridional wind!");
11208 if (ess_flag == 0)
11209 WARN("Cannot read eastward turbulent surface stress!");
11210 if (nss_flag == 0)
11211 WARN("Cannot read northward turbulent surface stress!");
11212 if (shf_flag == 0)
11213 WARN("Cannot read surface sensible heat flux!");
11214 if (lsm_flag == 0)
11215 WARN("Cannot read land-sea mask!");
11216 if (sst_flag == 0)
11217 WARN("Cannot read sea surface temperature!");
11218 if (ctl->met_cape == 0) {
11219 if (cape_flag == 0)
11220 WARN("Cannot read CAPE!");
11221 if (cin_flag == 0)
11222 WARN("Cannot read convective inhibition!");
11223 }
11224 if (ctl->met_pbl == 1 && pbl_flag == 0)
11225 WARN("Cannot read planetary boundary layer height!");
11226}
11227#endif
11228
11229/*****************************************************************************/
11230
11232 const ctl_t *ctl,
11233 const met_t *met,
11234 float var[EX][EY][EP],
11235 const char *varname) {
11236
11237 double aux[EP], p[EP];
11238
11239 /* Set timer... */
11240 SELECT_TIMER("READ_MET_ML2PL", "METPROC");
11241 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
11242
11243 /* Loop over columns... */
11244#pragma omp parallel for default(shared) private(aux,p) collapse(2)
11245 for (int ix = 0; ix < met->nx; ix++)
11246 for (int iy = 0; iy < met->ny; iy++) {
11247
11248 /* Copy pressure profile... */
11249 for (int ip = 0; ip < met->np; ip++)
11250 p[ip] = met->pl[ix][iy][ip];
11251
11252 /* Interpolate... */
11253 for (int ip = 0; ip < ctl->met_np; ip++) {
11254 double pt = ctl->met_p[ip];
11255 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
11256 pt = p[0];
11257 else if ((pt > p[met->np - 1] && p[1] > p[0])
11258 || (pt < p[met->np - 1] && p[1] < p[0]))
11259 pt = p[met->np - 1];
11260 const int ip2 = locate_irr(p, met->np, pt);
11261 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
11262 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
11263 }
11264
11265 /* Copy data... */
11266 for (int ip = 0; ip < ctl->met_np; ip++)
11267 var[ix][iy][ip] = (float) aux[ip];
11268 }
11269}
11270
11271/*****************************************************************************/
11272
11274 const ctl_t *ctl,
11275 met_t *met) {
11276
11277 /* Check parameters... */
11278 if (ctl->advect_vert_coord != 1)
11279 return;
11280
11281 /* Set timer... */
11282 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC");
11283 LOG(2, "Make zeta profiles monotone...");
11284
11285 /* Create monotone zeta profiles... */
11286#pragma omp parallel for default(shared) collapse(2)
11287 for (int i = 0; i < met->nx; i++)
11288 for (int j = 0; j < met->ny; j++) {
11289 int k = 1;
11290
11291 while (k < met->npl) { /* Check if there is an inversion at level k... */
11292 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
11293 /* Find the upper level k+l over the inversion... */
11294 int l = 0;
11295 do {
11296 l++;
11297 }
11298 while ((met->zetal[i][j][k - 1] >=
11299 met->zetal[i][j][k + l]) & (k + l < met->npl));
11300
11301 /* Interpolate linear between the top and bottom
11302 of the inversion... */
11303 float s =
11304 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
11305 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
11306
11307 for (int m = k; m < k + l; m++) {
11308 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
11309 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
11310 }
11311
11312 /* Search for more inversions above the last inversion ... */
11313 k = k + l;
11314 } else {
11315 k++;
11316 }
11317 }
11318 }
11319
11320 /* Create monotone pressure profiles... */
11321#pragma omp parallel for default(shared) collapse(2)
11322 for (int i = 0; i < met->nx; i++)
11323 for (int j = 0; j < met->ny; j++) {
11324 int k = 1;
11325
11326 while (k < met->npl) { /* Check if there is an inversion at level k... */
11327 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
11328
11329 /* Find the upper level k+l over the inversion... */
11330 int l = 0;
11331 do {
11332 l++;
11333 }
11334 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
11335 met->npl));
11336
11337 /* Interpolate linear between the top and bottom
11338 of the inversion... */
11339 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
11340 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
11341
11342 for (int m = k; m < k + l; m++) {
11343 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
11344 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
11345 }
11346
11347 /* Search for more inversions above the last inversion ... */
11348 k += l;
11349 } else {
11350 k++;
11351 }
11352 }
11353 }
11354}
11355
11356/*****************************************************************************/
11357
11359 const char *filename,
11360 const ctl_t *ctl,
11361 met_t *met,
11362 dd_t *dd) {
11363
11364 int ncid;
11365
11366 /* Open file... */
11367#ifdef DD
11368 if (ctl->dd) {
11369 NC(nc_open_par
11370 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
11371 &ncid))
11372 }
11373#else
11374 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
11375 WARN("Cannot open file!");
11376 return 0;
11377 }
11378#endif
11379
11380 /* Set coordinate system of meteo data... */
11381 met->coord_type = ctl->met_coord_type;
11382
11383 /* Read coordinates of meteo data... */
11384 read_met_nc_grid(filename, ncid, ctl, met, dd);
11385
11386 /* Read surface data... */
11387 read_met_nc_surface(ncid, ctl, met, dd);
11388
11389 /* Read meteo data on vertical levels... */
11390 read_met_nc_levels(ncid, ctl, met, dd);
11391
11392 /* Close file... */
11393 NC(nc_close(ncid));
11394
11395 /* Return success... */
11396 return 1;
11397}
11398
11399/*****************************************************************************/
11400
11402 dd_t *dd,
11403 const ctl_t *ctl,
11404 met_t *met,
11405 const int ncid) {
11406
11407 int varid;
11408
11409 /* Get the MPI information... */
11410 int rank = 0, size = 1;
11411#ifdef MPI
11412 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
11413 MPI_Comm_size(MPI_COMM_WORLD, &size);
11414#endif
11415
11416 /* Get grid dimensions... */
11417 NC_INQ_DIM("lon", &dd->nx_glob, 0, 0, 0);
11418 NC_INQ_DIM("lat", &dd->ny_glob, 0, 0, 0);
11419
11420 LOG(2, "Number of longitudes: %d", dd->nx_glob);
11421 LOG(2, "Number of latitudes: %d", dd->ny_glob);
11422
11423 /* Check grid... */
11424 if (dd->nx_glob > DD_EX_GLOB || dd->ny_glob > DD_EY_GLOB)
11425 ERRMSG("Global grid is too large!");
11426
11427 if (ctl->dd_subdomains_zonal > dd->nx_glob)
11428 ERRMSG("Too many zonal subdomains for global x grid!");
11429
11430 if (ctl->dd_subdomains_meridional > dd->ny_glob)
11431 ERRMSG("Too many meridional subdomains for global y grid!");
11432
11433 /* Read global longitudes and latitudes... */
11434 NC_GET_DOUBLE("lon", dd->lon_glob, 1);
11435 NC_GET_DOUBLE("lat", dd->lat_glob, 1);
11436
11437 LOG(2, "Longitudes: %g, %g ... %g deg",
11438 dd->lon_glob[0], dd->lon_glob[1], dd->lon_glob[dd->nx_glob - 1]);
11439 LOG(2, "Latitudes: %g, %g ... %g deg",
11440 dd->lat_glob[0], dd->lat_glob[1], dd->lat_glob[dd->ny_glob - 1]);
11441
11442 /* Rank coordinates in DD layout... */
11443 const int zonal_rank = rank / ctl->dd_subdomains_meridional;
11444 const int merid_rank = rank % ctl->dd_subdomains_meridional;
11445
11446 /* Check for edge cases... */
11447 const int left = (zonal_rank == 0);
11448 const int right = (zonal_rank == ctl->dd_subdomains_zonal - 1);
11449 const int top = (merid_rank == 0);
11450 const int bottom = (merid_rank == ctl->dd_subdomains_meridional - 1);
11451
11452 /* Core owned block (without halos)... */
11453 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
11454 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
11455
11456 const int ix0 = zonal_rank * nx_block;
11457 const int iy0 = merid_rank * ny_block;
11458
11459 int nx_core = nx_block;
11460 int ny_core = ny_block;
11461
11462 if (right)
11463 nx_core += dd->nx_glob - ctl->dd_subdomains_zonal * nx_block;
11464 if (bottom)
11465 ny_core += dd->ny_glob - ctl->dd_subdomains_meridional * ny_block;
11466
11467 /* Store core met size first... */
11468 met->nx = nx_core;
11469 met->ny = ny_core;
11470
11471 /* Set hyperslab for core subdomain... */
11472 dd->subdomain_start[0] = 0;
11473 dd->subdomain_start[1] = 0;
11474 dd->subdomain_start[2] = (size_t) iy0;
11475 dd->subdomain_start[3] = (size_t) ix0;
11476
11477 dd->subdomain_count[0] = 1;
11478 dd->subdomain_count[1] = (size_t) met->np;
11479 dd->subdomain_count[2] = (size_t) ny_core;
11480 dd->subdomain_count[3] = (size_t) nx_core;
11481
11482 /* Add inner halos to read window... */
11483 if (!left && !right) {
11484 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
11485 dd->subdomain_count[3] += (size_t) (2 * ctl->dd_halos_size);
11486 } else if (left ^ right) {
11487 dd->subdomain_count[3] += (size_t) ctl->dd_halos_size;
11488 if (!left)
11489 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
11490 }
11491
11492 if (!top && !bottom) {
11493 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
11494 dd->subdomain_count[2] += (size_t) (2 * ctl->dd_halos_size);
11495 } else if (top ^ bottom) {
11496 dd->subdomain_count[2] += (size_t) ctl->dd_halos_size;
11497 if (!top)
11498 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
11499 }
11500
11501 /* Set boundary halo hyperslabs... */
11502 double lon_shift = 0.0;
11503
11504 if (left ^ right) {
11505 dd->halo_bnd_start[0] = 0;
11506 dd->halo_bnd_start[1] = 0;
11507 dd->halo_bnd_start[2] = dd->subdomain_start[2];
11508 dd->halo_bnd_start[3] =
11509 (size_t) (left ? (dd->nx_glob - ctl->dd_halos_size) : 0);
11510
11511 dd->halo_bnd_count[0] = 1;
11512 dd->halo_bnd_count[1] = (size_t) met->np;
11513 dd->halo_bnd_count[2] =
11514 (size_t) met->ny +
11515 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
11516 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
11517
11518 dd->halo_offset_start = left ? (int) dd->halo_bnd_count[3] : 0;
11519 dd->halo_offset_end = left ? 0 : (int) dd->subdomain_count[3];
11520 lon_shift = left ? -360.0 : 360.0;
11521 } else {
11522 dd->halo_bnd_start[0] = 0;
11523 dd->halo_bnd_start[1] = 0;
11524 dd->halo_bnd_start[2] = 0;
11525 dd->halo_bnd_start[3] = 0;
11526
11527 dd->halo_bnd_count[0] = 0;
11528 dd->halo_bnd_count[1] = 0;
11529 dd->halo_bnd_count[2] = 0;
11530 dd->halo_bnd_count[3] = 0;
11531
11532 dd->halo_offset_start = 0;
11533 dd->halo_offset_end = 0;
11534 }
11535
11536 /* Focus on subdomain latitudes... */
11537 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
11538 met->lat[iy] = dd->lat_glob[(int) dd->subdomain_start[2] + iy];
11539
11540 /* Focus on subdomain longitudes... */
11541 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
11542 met->lon[ix + dd->halo_offset_start] =
11543 dd->lon_glob[(int) dd->subdomain_start[3] + ix];
11544
11545 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
11546 met->lon[ix + dd->halo_offset_end] =
11547 dd->lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
11548
11549 /* Reset halo-extended grid dimensions... */
11550 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
11551 met->ny = (int) dd->subdomain_count[2];
11552
11553 LOG(2, "Define subdomain properties.");
11554 LOG(2, "MPI information: Rank %d, Size %d", rank, size);
11555 LOG(2, "Edge position: l=%d,r=%d,t=%d,b=%d", left, right, top, bottom);
11556 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d",
11557 met->nx, met->ny, met->np);
11558 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
11559 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
11560 (int) dd->halo_bnd_count[1]);
11561 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
11562 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
11563 (int) dd->subdomain_count[1]);
11564 LOG(2, "Subdomain start: nx %ld ny %ld np %ld",
11565 dd->subdomain_start[3], dd->subdomain_start[2], dd->subdomain_start[1]);
11566 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld",
11567 dd->halo_bnd_start[3], dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
11568 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
11569 LOG(2, "%d Subdomain longitudes: %g, %g ... %g deg",
11570 rank, met->lon[0], met->lon[1], met->lon[met->nx - 1]);
11571 LOG(2, "%d Subdomain latitudes: %g, %g ... %g deg",
11572 rank, met->lat[0], met->lat[1], met->lat[met->ny - 1]);
11573}
11574
11575/*****************************************************************************/
11576
11578 const ctl_t *ctl,
11579 met_t *met) {
11580
11581 /* Set timer... */
11582 SELECT_TIMER("READ_MET_PBL", "METPROC");
11583 LOG(2, "Calculate planetary boundary layer...");
11584
11585 /* Convert PBL height from meteo file to pressure... */
11586 if (ctl->met_pbl == 1) {
11587
11588 /* Loop over grid points... */
11589#pragma omp parallel for default(shared) collapse(2)
11590 for (int ix = 0; ix < met->nx; ix++)
11591 for (int iy = 0; iy < met->ny; iy++) {
11592
11593 /* Get pressure at top of PBL... */
11594 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
11595 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
11596 met->pbl[ix][iy] =
11597 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
11598 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
11599 }
11600 }
11601
11602 /* Determine PBL based on Richardson number... */
11603 else if (ctl->met_pbl == 2) {
11604
11605 /* Parameters used to estimate the height of the PBL
11606 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
11607 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
11608
11609 /* Loop over grid points... */
11610#pragma omp parallel for default(shared) collapse(2)
11611 for (int ix = 0; ix < met->nx; ix++)
11612 for (int iy = 0; iy < met->ny; iy++) {
11613
11614 /* Set bottom level of PBL... */
11615 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
11616
11617 /* Find lowest level near the bottom... */
11618 int ip;
11619 for (ip = 1; ip < met->np; ip++)
11620 if (met->p[ip] < pbl_bot)
11621 break;
11622
11623 /* Get near surface data... */
11624 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
11625 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
11626 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
11627
11628 /* Init... */
11629 double rib_old = 0;
11630
11631 /* Loop over levels... */
11632 for (; ip < met->np; ip++) {
11633
11634 /* Get squared horizontal wind speed... */
11635 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
11636 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
11637 vh2 = MAX(vh2, SQR(umin));
11638
11639 /* Calculate bulk Richardson number... */
11640 const double rib =
11641 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
11642 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
11643 met->h2o[ix][iy][ip]) - tvs) / vh2;
11644
11645 /* Check for critical value... */
11646 if (rib >= rib_crit) {
11647 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
11648 rib, met->p[ip], rib_crit));
11649 if (met->pbl[ix][iy] > pbl_bot)
11650 met->pbl[ix][iy] = (float) pbl_bot;
11651 break;
11652 }
11653
11654 /* Save Richardson number... */
11655 rib_old = rib;
11656 }
11657 }
11658 }
11659
11660 /* Determine PBL based on potential temperature... */
11661 if (ctl->met_pbl == 3) {
11662
11663 /* Parameters used to estimate the height of the PBL
11664 (following HYSPLIT model)... */
11665 const double dtheta = 2.0, zmin = 0.1;
11666
11667 /* Loop over grid points... */
11668#pragma omp parallel for default(shared) collapse(2)
11669 for (int ix = 0; ix < met->nx; ix++)
11670 for (int iy = 0; iy < met->ny; iy++) {
11671
11672 /* Potential temperature at the surface... */
11673 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
11674
11675 /* Find topmost level where theta exceeds surface value by 2 K... */
11676 int ip;
11677 for (ip = met->np - 2; ip > 0; ip--)
11678 if (met->p[ip] >= 300.)
11679 if (met->p[ip] > met->ps[ix][iy]
11680 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
11681 break;
11682
11683 /* Interpolate... */
11684 met->pbl[ix][iy]
11685 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
11686 met->p[ip + 1],
11687 THETA(met->p[ip], met->t[ix][iy][ip]),
11688 met->p[ip], theta0 + dtheta));
11689
11690 /* Check minimum value... */
11691 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
11692 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
11693 met->pbl[ix][iy] = (float) pbl_min;
11694 }
11695 }
11696
11697 /* Loop over grid points... */
11698#pragma omp parallel for default(shared) collapse(2)
11699 for (int ix = 0; ix < met->nx; ix++)
11700 for (int iy = 0; iy < met->ny; iy++) {
11701
11702 /* Check minimum value... */
11703 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
11704 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
11705
11706 /* Check maximum value... */
11707 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
11708 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
11709 }
11710}
11711
11712/*****************************************************************************/
11713
11715 met_t *met) {
11716
11717 /* Set timer... */
11718 SELECT_TIMER("READ_MET_PERIODIC", "METPROC");
11719 LOG(2, "Apply periodic boundary conditions...");
11720
11721 /* Check longitudes... */
11722 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
11723 + met->lon[1] - met->lon[0] - 360) < 0.01))
11724 return;
11725
11726 /* Increase longitude counter... */
11727 if ((++met->nx) >= EX)
11728 ERRMSG("Cannot create periodic boundary conditions!");
11729
11730 /* Set longitude... */
11731 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
11732
11733 /* Loop over latitudes and pressure levels... */
11734#pragma omp parallel for default(shared)
11735 for (int iy = 0; iy < met->ny; iy++) {
11736 met->ps[met->nx - 1][iy] = met->ps[0][iy];
11737 met->zs[met->nx - 1][iy] = met->zs[0][iy];
11738 met->ts[met->nx - 1][iy] = met->ts[0][iy];
11739 met->us[met->nx - 1][iy] = met->us[0][iy];
11740 met->vs[met->nx - 1][iy] = met->vs[0][iy];
11741 met->ess[met->nx - 1][iy] = met->ess[0][iy];
11742 met->nss[met->nx - 1][iy] = met->nss[0][iy];
11743 met->shf[met->nx - 1][iy] = met->shf[0][iy];
11744 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
11745 met->sst[met->nx - 1][iy] = met->sst[0][iy];
11746 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
11747 met->cape[met->nx - 1][iy] = met->cape[0][iy];
11748 met->cin[met->nx - 1][iy] = met->cin[0][iy];
11749 for (int ip = 0; ip < met->np; ip++) {
11750 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
11751 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
11752 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
11753 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
11754 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
11755 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
11756 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
11757 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
11758 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
11759 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
11760 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
11761 }
11762 for (int ip = 0; ip < met->npl; ip++) {
11763 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
11764 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
11765 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
11766 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
11767 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
11768 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
11769 }
11770 }
11771}
11772
11773/*****************************************************************************/
11774
11776 met_t *met) {
11777
11778 /* Set timer... */
11779 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC");
11780 LOG(2, "Apply fix for polar winds...");
11781
11782 if (met->coord_type != 0)
11783 return;
11784
11785 /* Check latitudes... */
11786 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
11787 return;
11788
11789 /* Loop over hemispheres... */
11790 for (int ihem = 0; ihem < 2; ihem++) {
11791
11792 /* Set latitude indices... */
11793 int i89 = 1, i90 = 0, sign = 1;
11794 if (ihem == 1) {
11795 i89 = met->ny - 2;
11796 i90 = met->ny - 1;
11797 }
11798 if (met->lat[i90] < 0)
11799 sign = -1;
11800
11801 /* Look-up table of cosinus and sinus... */
11802 double clon[EX], slon[EX];
11803#pragma omp parallel for default(shared)
11804 for (int ix = 0; ix < met->nx; ix++) {
11805 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
11806 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
11807 }
11808
11809 /* Loop over levels... */
11810#pragma omp parallel for default(shared)
11811 for (int ip = 0; ip < met->np; ip++) {
11812
11813 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
11814 double vel89x = 0, vel89y = 0;
11815 for (int ix = 0; ix < met->nx; ix++) {
11816 vel89x +=
11817 (met->u[ix][i89][ip] * clon[ix] -
11818 met->v[ix][i89][ip] * slon[ix]) / met->nx;
11819 vel89y +=
11820 (met->u[ix][i89][ip] * slon[ix] +
11821 met->v[ix][i89][ip] * clon[ix]) / met->nx;
11822 }
11823
11824 /* Replace 90 degree winds by 89 degree mean... */
11825 for (int ix = 0; ix < met->nx; ix++) {
11826 met->u[ix][i90][ip]
11827 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
11828 met->v[ix][i90][ip]
11829 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
11830 }
11831 }
11832 }
11833}
11834
11835/*****************************************************************************/
11836
11838 met_t *met) {
11839
11840 double pows[EP];
11841
11842 /* Set timer... */
11843 SELECT_TIMER("READ_MET_PV", "METPROC");
11844 LOG(2, "Calculate potential vorticity...");
11845
11846 /* Set powers... */
11847#pragma omp parallel for default(shared)
11848 for (int ip = 0; ip < met->np; ip++)
11849 pows[ip] = pow(1000. / met->p[ip], KAPPA);
11850
11851 /* Loop over grid points... */
11852#pragma omp parallel for default(shared)
11853 for (int ix = 0; ix < met->nx; ix++) {
11854
11855 /* Set indices... */
11856 const int ix0 = MAX(ix - 1, 0);
11857 const int ix1 = MIN(ix + 1, met->nx - 1);
11858
11859 /* Loop over grid points... */
11860 for (int iy = 0; iy < met->ny; iy++) {
11861
11862 /* Set indices... */
11863 const int iy0 = MAX(iy - 1, 0);
11864 const int iy1 = MIN(iy + 1, met->ny - 1);
11865
11866 /* Set auxiliary variables... */
11867 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
11868 double dx, dy, c0, c1, cr, vort;
11869
11870 // Calculate potential vorticity..
11871 if (met->coord_type == 0) { // coords are lat/lon
11872 dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
11873 dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
11874 c0 = cos(DEG2RAD(met->lat[iy0]));
11875 c1 = cos(DEG2RAD(met->lat[iy1]));
11876 cr = cos(DEG2RAD(latr));
11877 vort = 2 * OMEGA_EARTH * sin(DEG2RAD(latr));
11878 } else { // coords are in meters
11879 dx = met->lon[ix1] - met->lon[ix0];
11880 dy = met->lat[iy1] - met->lat[iy0];
11881
11882 c0 = 1.0;
11883 c1 = 1.0;
11884 cr = 1.0;
11885
11886 vort = 2 * OMEGA_EARTH * sin(latr / (RE * 1000));
11887 }
11888
11889 /* Loop over grid points... */
11890 for (int ip = 0; ip < met->np; ip++) {
11891
11892 /* Get gradients in longitude... */
11893 const double dtdx
11894 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
11895 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
11896
11897 /* Get gradients in latitude... */
11898 const double dtdy
11899 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
11900 const double dudy
11901 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
11902
11903 /* Set indices... */
11904 const int ip0 = MAX(ip - 1, 0);
11905 const int ip1 = MIN(ip + 1, met->np - 1);
11906
11907 /* Get gradients in pressure... */
11908 double dtdp, dudp, dvdp;
11909 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
11910 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
11911 if (ip != ip0 && ip != ip1) {
11912 double denom = dp0 * dp1 * (dp0 + dp1);
11913 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
11914 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
11915 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
11916 / denom;
11917 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
11918 - dp1 * dp1 * met->u[ix][iy][ip0]
11919 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
11920 / denom;
11921 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
11922 - dp1 * dp1 * met->v[ix][iy][ip0]
11923 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
11924 / denom;
11925 } else {
11926 const double denom = dp0 + dp1;
11927 dtdp =
11928 (met->t[ix][iy][ip1] * pows[ip1] -
11929 met->t[ix][iy][ip0] * pows[ip0]) / denom;
11930 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
11931 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
11932 }
11933
11934 /* Calculate PV... */
11935 met->pv[ix][iy][ip] = (float)
11936 (1e6 * G0 *
11937 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
11938 }
11939 }
11940 }
11941
11942 /* Fix for polar regions... */
11943#pragma omp parallel for default(shared)
11944 for (int ix = 0; ix < met->nx; ix++)
11945 for (int ip = 0; ip < met->np; ip++) {
11946 met->pv[ix][0][ip]
11947 = met->pv[ix][1][ip]
11948 = met->pv[ix][2][ip];
11949 met->pv[ix][met->ny - 1][ip]
11950 = met->pv[ix][met->ny - 2][ip]
11951 = met->pv[ix][met->ny - 3][ip];
11952 }
11953}
11954
11955/*****************************************************************************/
11956
11958 met_t *met) {
11959
11960 /* Set timer... */
11961 SELECT_TIMER("READ_MET_OZONE", "METPROC");
11962 LOG(2, "Calculate total column ozone...");
11963
11964 /* Loop over columns... */
11965#pragma omp parallel for default(shared) collapse(2)
11966 for (int ix = 0; ix < met->nx; ix++)
11967 for (int iy = 0; iy < met->ny; iy++) {
11968
11969 /* Integrate... */
11970 double cd = 0;
11971 for (int ip = 1; ip < met->np; ip++)
11972 if (met->p[ip - 1] <= met->ps[ix][iy]) {
11973 const double vmr =
11974 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
11975 const double dp = met->p[ip - 1] - met->p[ip];
11976 cd += vmr * MO3 / MA * dp * 1e2 / G0;
11977 }
11978
11979 /* Convert to Dobson units... */
11980 met->o3c[ix][iy] = (float) (cd / DOBSON_UNIT);
11981 }
11982}
11983
11984/*****************************************************************************/
11985
11987 const ctl_t *ctl,
11988 met_t *met) {
11989
11990 met_t *help;
11991
11992 /* Check parameters... */
11993 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
11994 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
11995 return;
11996
11997 /* Set timer... */
11998 SELECT_TIMER("READ_MET_SAMPLE", "METPROC");
11999 LOG(2, "Downsampling of meteo data...");
12000
12001 /* Allocate... */
12002 ALLOC(help, met_t, 1);
12003
12004 /* Copy data... */
12005 help->nx = met->nx;
12006 help->ny = met->ny;
12007 help->np = met->np;
12008 memcpy(help->lon, met->lon, sizeof(met->lon));
12009 memcpy(help->lat, met->lat, sizeof(met->lat));
12010 memcpy(help->p, met->p, sizeof(met->p));
12011
12012 /* Smoothing... */
12013 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
12014 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
12015 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
12016 help->ps[ix][iy] = 0;
12017 help->zs[ix][iy] = 0;
12018 help->ts[ix][iy] = 0;
12019 help->us[ix][iy] = 0;
12020 help->vs[ix][iy] = 0;
12021 help->ess[ix][iy] = 0;
12022 help->nss[ix][iy] = 0;
12023 help->shf[ix][iy] = 0;
12024 help->lsm[ix][iy] = 0;
12025 help->sst[ix][iy] = 0;
12026 help->pbl[ix][iy] = 0;
12027 help->cape[ix][iy] = 0;
12028 help->cin[ix][iy] = 0;
12029 help->t[ix][iy][ip] = 0;
12030 help->u[ix][iy][ip] = 0;
12031 help->v[ix][iy][ip] = 0;
12032 help->w[ix][iy][ip] = 0;
12033 help->h2o[ix][iy][ip] = 0;
12034 help->o3[ix][iy][ip] = 0;
12035 help->lwc[ix][iy][ip] = 0;
12036 help->rwc[ix][iy][ip] = 0;
12037 help->iwc[ix][iy][ip] = 0;
12038 help->swc[ix][iy][ip] = 0;
12039 help->cc[ix][iy][ip] = 0;
12040 float wsum = 0;
12041 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
12042 ix2++) {
12043 int ix3 = ix2;
12044 if (ix3 < 0)
12045 ix3 += met->nx;
12046 else if (ix3 >= met->nx)
12047 ix3 -= met->nx;
12048
12049 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
12050 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
12051 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
12052 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
12053 const float w =
12054 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
12055 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
12056 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
12057 help->ps[ix][iy] += w * met->ps[ix3][iy2];
12058 help->zs[ix][iy] += w * met->zs[ix3][iy2];
12059 help->ts[ix][iy] += w * met->ts[ix3][iy2];
12060 help->us[ix][iy] += w * met->us[ix3][iy2];
12061 help->vs[ix][iy] += w * met->vs[ix3][iy2];
12062 help->ess[ix][iy] += w * met->ess[ix3][iy2];
12063 help->nss[ix][iy] += w * met->nss[ix3][iy2];
12064 help->shf[ix][iy] += w * met->shf[ix3][iy2];
12065 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
12066 help->sst[ix][iy] += w * met->sst[ix3][iy2];
12067 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
12068 help->cape[ix][iy] += w * met->cape[ix3][iy2];
12069 help->cin[ix][iy] += w * met->cin[ix3][iy2];
12070 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
12071 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
12072 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
12073 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
12074 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
12075 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
12076 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
12077 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
12078 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
12079 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
12080 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
12081 wsum += w;
12082 }
12083 }
12084 help->ps[ix][iy] /= wsum;
12085 help->zs[ix][iy] /= wsum;
12086 help->ts[ix][iy] /= wsum;
12087 help->us[ix][iy] /= wsum;
12088 help->vs[ix][iy] /= wsum;
12089 help->ess[ix][iy] /= wsum;
12090 help->nss[ix][iy] /= wsum;
12091 help->shf[ix][iy] /= wsum;
12092 help->lsm[ix][iy] /= wsum;
12093 help->sst[ix][iy] /= wsum;
12094 help->pbl[ix][iy] /= wsum;
12095 help->cape[ix][iy] /= wsum;
12096 help->cin[ix][iy] /= wsum;
12097 help->t[ix][iy][ip] /= wsum;
12098 help->u[ix][iy][ip] /= wsum;
12099 help->v[ix][iy][ip] /= wsum;
12100 help->w[ix][iy][ip] /= wsum;
12101 help->h2o[ix][iy][ip] /= wsum;
12102 help->o3[ix][iy][ip] /= wsum;
12103 help->lwc[ix][iy][ip] /= wsum;
12104 help->rwc[ix][iy][ip] /= wsum;
12105 help->iwc[ix][iy][ip] /= wsum;
12106 help->swc[ix][iy][ip] /= wsum;
12107 help->cc[ix][iy][ip] /= wsum;
12108 }
12109 }
12110 }
12111
12112 /* Downsampling... */
12113 met->nx = 0;
12114 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
12115 met->lon[met->nx] = help->lon[ix];
12116 met->ny = 0;
12117 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
12118 met->lat[met->ny] = help->lat[iy];
12119 met->ps[met->nx][met->ny] = help->ps[ix][iy];
12120 met->zs[met->nx][met->ny] = help->zs[ix][iy];
12121 met->ts[met->nx][met->ny] = help->ts[ix][iy];
12122 met->us[met->nx][met->ny] = help->us[ix][iy];
12123 met->vs[met->nx][met->ny] = help->vs[ix][iy];
12124 met->ess[met->nx][met->ny] = help->ess[ix][iy];
12125 met->nss[met->nx][met->ny] = help->nss[ix][iy];
12126 met->shf[met->nx][met->ny] = help->shf[ix][iy];
12127 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
12128 met->sst[met->nx][met->ny] = help->sst[ix][iy];
12129 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
12130 met->cape[met->nx][met->ny] = help->cape[ix][iy];
12131 met->cin[met->nx][met->ny] = help->cin[ix][iy];
12132 met->np = 0;
12133 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
12134 met->p[met->np] = help->p[ip];
12135 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
12136 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
12137 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
12138 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
12139 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
12140 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
12141 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
12142 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
12143 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
12144 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
12145 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
12146 met->np++;
12147 }
12148 met->ny++;
12149 }
12150 met->nx++;
12151 }
12152
12153 /* Free... */
12154 free(help);
12155}
12156
12157/*****************************************************************************/
12158
12160 const ctl_t *ctl,
12161 const clim_t *clim,
12162 met_t *met) {
12163
12164 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
12165 th2[200], z[EP], z2[200];
12166
12167 /* Set timer... */
12168 SELECT_TIMER("READ_MET_TROPO", "METPROC");
12169 LOG(2, "Calculate tropopause...");
12170
12171 /* Get altitude and pressure profiles... */
12172#pragma omp parallel for default(shared)
12173 for (int iz = 0; iz < met->np; iz++)
12174 z[iz] = Z(met->p[iz]);
12175#pragma omp parallel for default(shared)
12176 for (int iz = 0; iz <= 190; iz++) {
12177 z2[iz] = 4.5 + 0.1 * iz;
12178 p2[iz] = P(z2[iz]);
12179 }
12180
12181 /* Do not calculate tropopause... */
12182 if (ctl->met_tropo == 0)
12183#pragma omp parallel for default(shared) collapse(2)
12184 for (int ix = 0; ix < met->nx; ix++)
12185 for (int iy = 0; iy < met->ny; iy++)
12186 met->pt[ix][iy] = NAN;
12187
12188 /* Use tropopause climatology... */
12189 else if (ctl->met_tropo == 1) {
12190 if (met->coord_type != 0)
12191 ERRMSG("Only lat/lon grid supported");
12192#pragma omp parallel for default(shared) collapse(2)
12193 for (int ix = 0; ix < met->nx; ix++)
12194 for (int iy = 0; iy < met->ny; iy++)
12195 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
12196 }
12197
12198 /* Use cold point... */
12199 else if (ctl->met_tropo == 2) {
12200
12201 /* Loop over grid points... */
12202#pragma omp parallel for default(shared) private(t,t2) collapse(2)
12203 for (int ix = 0; ix < met->nx; ix++)
12204 for (int iy = 0; iy < met->ny; iy++) {
12205
12206 /* Interpolate temperature profile... */
12207 for (int iz = 0; iz < met->np; iz++)
12208 t[iz] = met->t[ix][iy][iz];
12209 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
12210
12211 /* Find minimum... */
12212 int iz = (int) gsl_stats_min_index(t2, 1, 171);
12213 if (iz > 0 && iz < 170)
12214 met->pt[ix][iy] = (float) p2[iz];
12215 else
12216 met->pt[ix][iy] = NAN;
12217 }
12218 }
12219
12220 /* Use WMO definition... */
12221 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
12222
12223 /* Loop over grid points... */
12224#pragma omp parallel for default(shared) private(t,t2) collapse(2)
12225 for (int ix = 0; ix < met->nx; ix++)
12226 for (int iy = 0; iy < met->ny; iy++) {
12227
12228 /* Interpolate temperature profile... */
12229 int iz;
12230 for (iz = 0; iz < met->np; iz++)
12231 t[iz] = met->t[ix][iy][iz];
12232 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
12233
12234 /* Find 1st tropopause... */
12235 met->pt[ix][iy] = NAN;
12236 for (iz = 0; iz <= 170; iz++) {
12237 int found = 1;
12238 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
12239 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
12240 found = 0;
12241 break;
12242 }
12243 if (found) {
12244 if (iz > 0 && iz < 170)
12245 met->pt[ix][iy] = (float) p2[iz];
12246 break;
12247 }
12248 }
12249
12250 /* Find 2nd tropopause... */
12251 if (ctl->met_tropo == 4) {
12252 met->pt[ix][iy] = NAN;
12253 for (; iz <= 170; iz++) {
12254 int found = 1;
12255 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
12256 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
12257 found = 0;
12258 break;
12259 }
12260 if (found)
12261 break;
12262 }
12263 for (; iz <= 170; iz++) {
12264 int found = 1;
12265 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
12266 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
12267 found = 0;
12268 break;
12269 }
12270 if (found) {
12271 if (iz > 0 && iz < 170)
12272 met->pt[ix][iy] = (float) p2[iz];
12273 break;
12274 }
12275 }
12276 }
12277 }
12278 }
12279
12280 /* Use dynamical tropopause... */
12281 else if (ctl->met_tropo == 5) {
12282
12283 /* Loop over grid points... */
12284#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
12285 for (int ix = 0; ix < met->nx; ix++)
12286 for (int iy = 0; iy < met->ny; iy++) {
12287
12288 /* Interpolate potential vorticity profile... */
12289 for (int iz = 0; iz < met->np; iz++)
12290 pv[iz] = met->pv[ix][iy][iz];
12291 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
12292
12293 /* Interpolate potential temperature profile... */
12294 for (int iz = 0; iz < met->np; iz++)
12295 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
12296 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
12297
12298 /* Find dynamical tropopause... */
12299 met->pt[ix][iy] = NAN;
12300 for (int iz = 0; iz <= 170; iz++)
12301 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
12302 || th2[iz] >= ctl->met_tropo_theta) {
12303 if (iz > 0 && iz < 170)
12304 met->pt[ix][iy] = (float) p2[iz];
12305 break;
12306 }
12307 }
12308 }
12309
12310 else
12311 ERRMSG("Cannot calculate tropopause!");
12312
12313 /* Interpolate temperature, geopotential height, and water vapor... */
12314#pragma omp parallel for default(shared) collapse(2)
12315 for (int ix = 0; ix < met->nx; ix++)
12316 for (int iy = 0; iy < met->ny; iy++) {
12317 double h2ot, tt, zt;
12319 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
12320 met->lat[iy], &tt, ci, cw, 1);
12321 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
12322 met->lat[iy], &zt, ci, cw, 0);
12323 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
12324 met->lat[iy], &h2ot, ci, cw, 0);
12325 met->tt[ix][iy] = (float) tt;
12326 met->zt[ix][iy] = (float) zt;
12327 met->h2ot[ix][iy] = (float) h2ot;
12328 }
12329}
12330
12331/*****************************************************************************/
12332
12334 const char *filename,
12335 const ctl_t *ctl,
12336 double *rt,
12337 double *rz,
12338 double *rlon,
12339 double *rlat,
12340 double *robs,
12341 int *nobs) {
12342
12343 /* Write info... */
12344 LOG(1, "Read observation data: %s", filename);
12345
12346 /* Read data... */
12347 if (ctl->obs_type == 0)
12348 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
12349 else if (ctl->obs_type == 1)
12350 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
12351 else
12352 ERRMSG("Set OBS_TYPE to 0 or 1!");
12353
12354 /* Check time... */
12355 for (int i = 1; i < *nobs; i++)
12356 if (rt[i] < rt[i - 1])
12357 ERRMSG("Time must be ascending!");
12358
12359 /* Write info... */
12360 int n = *nobs;
12361 double mini, maxi;
12362 LOG(2, "Number of observations: %d", *nobs);
12363 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
12364 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
12365 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
12366 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
12367 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
12368 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
12369 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
12370 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
12371 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
12372 LOG(2, "Observation range: %g ... %g", mini, maxi);
12373}
12374
12375/*****************************************************************************/
12376
12378 const char *filename,
12379 double *rt,
12380 double *rz,
12381 double *rlon,
12382 double *rlat,
12383 double *robs,
12384 int *nobs) {
12385
12386 /* Open observation data file... */
12387 FILE *in;
12388 if (!(in = fopen(filename, "r")))
12389 ERRMSG("Cannot open file!");
12390
12391 /* Read observations... */
12392 char line[LEN];
12393 while (fgets(line, LEN, in))
12394 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
12395 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
12396 if ((++(*nobs)) >= NOBS)
12397 ERRMSG("Too many observations!");
12398
12399 /* Close observation data file... */
12400 fclose(in);
12401}
12402
12403/*****************************************************************************/
12404
12406 const char *filename,
12407 double *rt,
12408 double *rz,
12409 double *rlon,
12410 double *rlat,
12411 double *robs,
12412 int *nobs) {
12413
12414 int ncid, varid;
12415
12416 /* Open netCDF file... */
12417 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
12418 ERRMSG("Cannot open file!");
12419
12420 /* Read the observations from the NetCDF file... */
12421 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
12422 NC_GET_DOUBLE("time", rt, 1);
12423 NC_GET_DOUBLE("alt", rz, 1);
12424 NC_GET_DOUBLE("lon", rlon, 1);
12425 NC_GET_DOUBLE("lat", rlat, 1);
12426 NC_GET_DOUBLE("obs", robs, 1);
12427
12428 /* Close file... */
12429 NC(nc_close(ncid));
12430}
12431
12432/*****************************************************************************/
12433
12435 const char *filename,
12436 int argc,
12437 char *argv[],
12438 const char *varname,
12439 const int arridx,
12440 const char *defvalue,
12441 char *value) {
12442
12443 FILE *in = NULL;
12444
12445 char fullname1[LEN], fullname2[LEN], rval[LEN];
12446
12447 int contain = 0, i;
12448
12449 /* Open file... */
12450 if (filename[strlen(filename) - 1] != '-')
12451 if (!(in = fopen(filename, "r")))
12452 ERRMSG("Cannot open file!");
12453
12454 /* Set full variable name... */
12455 if (arridx >= 0) {
12456 sprintf(fullname1, "%s[%d]", varname, arridx);
12457 sprintf(fullname2, "%s[*]", varname);
12458 } else {
12459 sprintf(fullname1, "%s", varname);
12460 sprintf(fullname2, "%s", varname);
12461 }
12462
12463 /* Read data... */
12464 if (in != NULL) {
12465 char dummy[LEN], line[LEN], rvarname[LEN];
12466 while (fgets(line, LEN, in)) {
12467 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
12468 if (strcasecmp(rvarname, fullname1) == 0 ||
12469 strcasecmp(rvarname, fullname2) == 0) {
12470 contain = 1;
12471 break;
12472 }
12473 }
12474 }
12475 for (i = 1; i < argc - 1; i++)
12476 if (strcasecmp(argv[i], fullname1) == 0 ||
12477 strcasecmp(argv[i], fullname2) == 0) {
12478 sprintf(rval, "%s", argv[i + 1]);
12479 contain = 1;
12480 break;
12481 }
12482
12483 /* Close file... */
12484 if (in != NULL)
12485 fclose(in);
12486
12487 /* Check for missing variables... */
12488 if (!contain) {
12489 if (strlen(defvalue) > 0)
12490 sprintf(rval, "%s", defvalue);
12491 else
12492 ERRMSG("Missing variable %s!\n", fullname1);
12493 }
12494
12495 /* Write info... */
12496 LOG(1, "%s = %s", fullname1, rval);
12497
12498 /* Return values... */
12499 if (value != NULL)
12500 sprintf(value, "%s", rval);
12501 return atof(rval);
12502}
12503
12504/*****************************************************************************/
12505
12506double sedi(
12507 const double p,
12508 const double T,
12509 const double rp,
12510 const double rhop) {
12511
12512 /* Convert particle radius from microns to m... */
12513 const double rp_help = rp * 1e-6;
12514
12515 /* Density of dry air [kg / m^3]... */
12516 const double rho = RHO(p, T);
12517
12518 /* Dynamic viscosity of air [kg / (m s)]... */
12519 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
12520
12521 /* Thermal velocity of an air molecule [m / s]... */
12522 const double v = sqrt(8. * KB * T / (M_PI * M_AIR_MOLECULE));
12523
12524 /* Mean free path of an air molecule [m]... */
12525 const double lambda = 2. * eta / (rho * v);
12526
12527 /* Knudsen number for air (dimensionless)... */
12528 const double K = lambda / rp_help;
12529
12530 /* Cunningham slip-flow correction (dimensionless)... */
12531 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
12532
12533 /* Sedimentation velocity [m / s]... */
12534 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
12535}
12536
12537/*****************************************************************************/
12538
12540 const double *x,
12541 const double *y,
12542 const int n,
12543 const double *x2,
12544 double *y2,
12545 const int n2,
12546 const int method) {
12547
12548 /* Cubic spline interpolation... */
12549 if (method == 1) {
12550
12551 /* Allocate... */
12552 gsl_interp_accel *acc = gsl_interp_accel_alloc();
12553 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
12554
12555 /* Interpolate profile... */
12556 gsl_spline_init(s, x, y, (size_t) n);
12557 for (int i = 0; i < n2; i++)
12558 if (x2[i] <= x[0])
12559 y2[i] = y[0];
12560 else if (x2[i] >= x[n - 1])
12561 y2[i] = y[n - 1];
12562 else
12563 y2[i] = gsl_spline_eval(s, x2[i], acc);
12564
12565 /* Free... */
12566 gsl_spline_free(s);
12567 gsl_interp_accel_free(acc);
12568 }
12569
12570 /* Linear interpolation... */
12571 else {
12572 for (int i = 0; i < n2; i++)
12573 if (x2[i] <= x[0])
12574 y2[i] = y[0];
12575 else if (x2[i] >= x[n - 1])
12576 y2[i] = y[n - 1];
12577 else {
12578 const int idx = locate_irr(x, n, x2[i]);
12579 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
12580 }
12581 }
12582}
12583
12584/*****************************************************************************/
12585
12587 const float *data,
12588 const int n) {
12589
12590 if (n <= 0)
12591 return 0;
12592
12593 float mean = 0, var = 0;
12594
12595 for (int i = 0; i < n; ++i) {
12596 mean += data[i];
12597 var += SQR(data[i]);
12598 }
12599
12600 var = var / (float) n - SQR(mean / (float) n);
12601
12602 return (var > 0 ? sqrtf(var) : 0);
12603}
12604
12605/*****************************************************************************/
12606
12608 const int year,
12609 const int mon,
12610 const int day,
12611 const int hour,
12612 const int min,
12613 const int sec,
12614 const double remain,
12615 double *jsec) {
12616
12617 struct tm t0, t1;
12618
12619 t0.tm_year = 100;
12620 t0.tm_mon = 0;
12621 t0.tm_mday = 1;
12622 t0.tm_hour = 0;
12623 t0.tm_min = 0;
12624 t0.tm_sec = 0;
12625
12626 t1.tm_year = year - 1900;
12627 t1.tm_mon = mon - 1;
12628 t1.tm_mday = day;
12629 t1.tm_hour = hour;
12630 t1.tm_min = min;
12631 t1.tm_sec = sec;
12632
12633 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
12634}
12635
12636/*****************************************************************************/
12637
12639 const char *name,
12640 const char *group,
12641 const int output) {
12642
12643 static char names[NTIMER][100], groups[NTIMER][100];
12644
12645 static double rt_name[NTIMER], rt_group[NTIMER],
12646 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
12647
12648 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
12649
12650 /* Get time... */
12651 t1 = omp_get_wtime();
12652 dt = t1 - t0;
12653
12654 /* Add elapsed time to current timers... */
12655 if (iname >= 0) {
12656 rt_name[iname] += dt;
12657 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
12658 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
12659 ct_name[iname]++;
12660 }
12661 if (igroup >= 0)
12662 rt_group[igroup] += t1 - t0;
12663
12664 /* Report timers... */
12665 if (output) {
12666 for (int i = 0; i < nname; i++)
12667 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
12668 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
12669 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
12670 for (int i = 0; i < ngroup; i++)
12671 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
12672 double total = 0.0;
12673 for (int i = 0; i < nname; i++)
12674 total += rt_name[i];
12675 LOG(1, "TIMER_TOTAL = %.3f s", total);
12676 }
12677
12678 /* Identify IDs of next timer... */
12679 for (iname = 0; iname < nname; iname++)
12680 if (strcasecmp(name, names[iname]) == 0)
12681 break;
12682 for (igroup = 0; igroup < ngroup; igroup++)
12683 if (strcasecmp(group, groups[igroup]) == 0)
12684 break;
12685
12686 /* Check whether this is a new timer... */
12687 if (iname >= nname) {
12688 sprintf(names[iname], "%s", name);
12689 if ((++nname) >= NTIMER)
12690 ERRMSG("Too many timers!");
12691 }
12692
12693 /* Check whether this is a new group... */
12694 if (igroup >= ngroup) {
12695 sprintf(groups[igroup], "%s", group);
12696 if ((++ngroup) >= NTIMER)
12697 ERRMSG("Too many groups!");
12698 }
12699
12700 /* Save starting time... */
12701 t0 = t1;
12702}
12703
12704/*****************************************************************************/
12705
12707 const char *filename,
12708 const int offset,
12709 const int with_seconds) {
12710
12711 char tstr[10];
12712
12713 double t;
12714
12715 /* Get time from filename... */
12716 int len = (int) strlen(filename);
12717 sprintf(tstr, "%.4s", &filename[len - offset]);
12718 int year = atoi(tstr);
12719 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
12720 int mon = atoi(tstr);
12721 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
12722 int day = atoi(tstr);
12723 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
12724 int hour = atoi(tstr);
12725 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
12726 int min = atoi(tstr);
12727
12728 int sec = 0;
12729 if (with_seconds) {
12730 sprintf(tstr, "%.2s", &filename[len - offset + 17]);
12731 sec = atoi(tstr);
12732 }
12733
12734 /* Check time... */
12735 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
12736 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
12737 ERRMSG("Cannot read time from filename!");
12738
12739 /* Convert time to Julian seconds... */
12740 time2jsec(year, mon, day, hour, min, sec, 0.0, &t);
12741
12742 /* Return time... */
12743 return t;
12744}
12745
12746/*****************************************************************************/
12747
12749 const ctl_t *ctl,
12750 const clim_t *clim,
12751 const atm_t *atm,
12752 const int ip) {
12753
12754 /* Get tropopause pressure... */
12755 const double pt = clim_tropo(clim, atm->time[ip],
12756 ctl->met_coord_type ==
12757 0 ? atm->lat[ip] : ctl->met_utm_ref_lat);
12758
12759 /* Get pressure range... */
12760 const double p1 = pt * 0.866877899;
12761 const double p0 = pt / 0.866877899;
12762
12763 /* Get weighting factor... */
12764 if (atm->p[ip] > p0)
12765 return 1;
12766 else if (atm->p[ip] < p1)
12767 return 0;
12768 else
12769 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
12770}
12771
12772/*****************************************************************************/
12773
12775 const char *filename,
12776 const ctl_t *ctl,
12777 const atm_t *atm,
12778 const double t) {
12779
12780 FILE *out;
12781
12782 /* Set time interval for output... */
12783 const double t0 = t - 0.5 * ctl->dt_mod;
12784 const double t1 = t + 0.5 * ctl->dt_mod;
12785
12786 /* Check if gnuplot output is requested... */
12787 if (ctl->atm_gpfile[0] != '-') {
12788
12789 /* Create gnuplot pipe... */
12790 if (!(out = popen("gnuplot", "w")))
12791 ERRMSG("Cannot create pipe to gnuplot!");
12792
12793 /* Set plot filename... */
12794 fprintf(out, "set out \"%s.png\"\n", filename);
12795
12796 /* Set time string... */
12797 double r;
12798 int year, mon, day, hour, min, sec;
12799 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12800 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12801 year, mon, day, hour, min);
12802
12803 /* Dump gnuplot file to pipe... */
12804 FILE *in;
12805 if (!(in = fopen(ctl->atm_gpfile, "r")))
12806 ERRMSG("Cannot open file!");
12807 char line[LEN];
12808 while (fgets(line, LEN, in))
12809 fprintf(out, "%s", line);
12810 fclose(in);
12811 }
12812
12813 else {
12814
12815 /* Create file... */
12816 if (!(out = fopen(filename, "w")))
12817 ERRMSG("Cannot create file!");
12818 }
12819
12820 /* Write header... */
12821
12822 if (ctl->met_coord_type == 0) {
12823 fprintf(out,
12824 "# $1 = time [s]\n"
12825 "# $2 = altitude [km]\n"
12826 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12827 } else {
12828 fprintf(out,
12829 "# $1 = time [s]\n"
12830 "# $2 = altitude [km]\n" "# $3 = x [m]\n" "# $4 = y [m]\n");
12831 }
12832
12833 for (int iq = 0; iq < ctl->nq; iq++)
12834 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
12835 ctl->qnt_unit[iq]);
12836 fprintf(out, "\n");
12837
12838 /* Write data... */
12839 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
12840
12841 /* Check time... */
12842 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12843 continue;
12844
12845 /* Write output... */
12846 if (ctl->met_coord_type == 0) {
12847 fprintf(out, "%.2f %g %g %g",
12848 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]
12849 );
12850 } else {
12851 fprintf(out, "%.2f %g %.2f %.2f",
12852 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]
12853 );
12854 }
12855
12856 for (int iq = 0; iq < ctl->nq; iq++) {
12857 fprintf(out, " ");
12858 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12859 fprintf(out, ctl->qnt_format[iq], NAN);
12860 else
12861 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
12862 }
12863 fprintf(out, "\n");
12864 }
12865
12866 /* Close file... */
12867 fclose(out);
12868}
12869
12870/*****************************************************************************/
12871
12873 const char *filename,
12874 const ctl_t *ctl,
12875 const atm_t *atm) {
12876
12877 FILE *out;
12878
12879 /* Create file... */
12880 if (!(out = fopen(filename, "w")))
12881 ERRMSG("Cannot create file!");
12882
12883 /* Write version of binary data... */
12884 int version = 100;
12885 FWRITE(&version, int,
12886 1,
12887 out);
12888
12889 /* Write data... */
12890 FWRITE(&atm->np, int,
12891 1,
12892 out);
12893 FWRITE(atm->time, double,
12894 (size_t) atm->np,
12895 out);
12896 FWRITE(atm->p, double,
12897 (size_t) atm->np,
12898 out);
12899 FWRITE(atm->lon, double,
12900 (size_t) atm->np,
12901 out);
12902 FWRITE(atm->lat, double,
12903 (size_t) atm->np,
12904 out);
12905 for (int iq = 0; iq < ctl->nq; iq++)
12906 FWRITE(atm->q[iq], double,
12907 (size_t) atm->np,
12908 out);
12909
12910 /* Write final flag... */
12911 int final = 999;
12912 FWRITE(&final, int,
12913 1,
12914 out);
12915
12916 /* Close file... */
12917 fclose(out);
12918}
12919
12920/*****************************************************************************/
12921
12923 const char *filename,
12924 const ctl_t *ctl,
12925 const atm_t *atm) {
12926
12927 if (ctl->met_coord_type != 0)
12928 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
12929
12930 int tid, pid, ncid, varid;
12931 size_t start[2], count[2];
12932
12933 /* Create file... */
12934 NC(nc_create(filename, NC_NETCDF4, &ncid));
12935
12936 /* Define dimensions... */
12937 NC(nc_def_dim(ncid, "time", 1, &tid));
12938 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
12939
12940 /* Define variables and their attributes... */
12941 int dim_ids[2] = { tid, pid };
12942 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
12943 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12944 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
12945 ctl->atm_nc_level, 0);
12946 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
12947 ctl->atm_nc_level, 0);
12948 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
12949 ctl->atm_nc_level, 0);
12950 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
12951 for (int iq = 0; iq < ctl->nq; iq++)
12952 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
12953 ctl->qnt_name[iq], ctl->qnt_unit[iq],
12954 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12955
12956 /* Define global attributes... */
12957 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
12958 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
12959
12960 /* End definitions... */
12961 NC(nc_enddef(ncid));
12962
12963 /* Write data... */
12964 NC_PUT_DOUBLE("time", atm->time, 0);
12965 NC_PUT_DOUBLE("LAT", atm->lat, 0);
12966 NC_PUT_DOUBLE("LON", atm->lon, 0);
12967 NC_PUT_DOUBLE("PRESS", atm->p, 0);
12968 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
12969 for (int iq = 0; iq < ctl->nq; iq++)
12970 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
12971
12972 /* Close file... */
12973 NC(nc_close(ncid));
12974}
12975
12976/*****************************************************************************/
12977
12979 const char *dirname,
12980 const ctl_t *ctl,
12981 const atm_t *atm,
12982 const double t) {
12983
12984 if (ctl->met_coord_type != 0)
12985 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
12986
12987 /* Global Counter... */
12988 static size_t out_cnt = 0;
12989
12990 double r, r_start, r_stop;
12991 int year, mon, day, hour, min, sec;
12992 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
12993 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
12994 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
12995
12996 int ncid, varid, tid, pid, cid;
12997 int dim_ids[2];
12998
12999 /* time, nparc */
13000 size_t start[2];
13001 size_t count[2];
13002
13003 /* Determine start and stop times of calculation... */
13004 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
13005 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
13006 &min_start, &sec_start, &r_start);
13007 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
13008 &min_stop, &sec_stop, &r_stop);
13009
13010 sprintf(filename_out,
13011 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
13012 year_start % 100, mon_start, day_start, hour_start,
13013 year_stop % 100, mon_stop, day_stop, hour_stop);
13014 LOG(1, "Write traj file: %s", filename_out);
13015
13016 /* Define hyperslap for the traj_file... */
13017 start[0] = out_cnt;
13018 start[1] = 0;
13019 count[0] = 1;
13020 count[1] = (size_t) atm->np;
13021
13022 /* Create the file at the first timestep... */
13023 if (out_cnt == 0) {
13024
13025 /* Create file... */
13026 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
13027
13028 /* Define dimensions... */
13029 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
13030 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
13031 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
13032 dim_ids[0] = tid;
13033 dim_ids[1] = pid;
13034
13035 /* Define variables and their attributes... */
13036 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
13037 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
13038 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
13039 ctl->atm_nc_level, 0);
13040 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
13041 ctl->atm_nc_level, 0);
13042 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
13043 ctl->atm_nc_level, 0);
13044 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
13045 ctl->atm_nc_level, 0);
13046 for (int iq = 0; iq < ctl->nq; iq++)
13047 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
13048 ctl->qnt_name[iq], ctl->qnt_unit[iq],
13049 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
13050
13051 /* Define global attributes... */
13052 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
13053 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
13054
13055 /* End definitions... */
13056 NC(nc_enddef(ncid));
13057 NC(nc_close(ncid));
13058 }
13059
13060 /* Increment global counter to change hyperslap... */
13061 out_cnt++;
13062
13063 /* Open file... */
13064 NC(nc_open(filename_out, NC_WRITE, &ncid));
13065
13066 /* Write data... */
13067 NC_PUT_DOUBLE("time", atm->time, 1);
13068 NC_PUT_DOUBLE("LAT", atm->lat, 1);
13069 NC_PUT_DOUBLE("LON", atm->lon, 1);
13070 NC_PUT_DOUBLE("PRESS", atm->p, 1);
13071 if (ctl->advect_vert_coord == 1) {
13072 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
13073 } else if (ctl->qnt_zeta >= 0) {
13074 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
13075 }
13076 for (int iq = 0; iq < ctl->nq; iq++)
13077 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
13078
13079 /* Close file... */
13080 NC(nc_close(ncid));
13081
13082 /* At the last time step create the init_fix_YYYYMMDDHH file... */
13083 if ((year == year_stop) && (mon == mon_stop)
13084 && (day == day_stop) && (hour == hour_stop)) {
13085
13086 /* Set filename... */
13087 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
13088 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
13089 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
13090 LOG(1, "Write init file: %s", filename_init);
13091
13092 /* Create file... */
13093 NC(nc_create(filename_init, NC_NETCDF4, &ncid));
13094
13095 /* Define dimensions... */
13096 NC(nc_def_dim(ncid, "time", 1, &tid));
13097 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
13098 dim_ids[0] = tid;
13099 dim_ids[1] = pid;
13100
13101 /* Define variables and their attributes... */
13102 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
13103 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
13104 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
13105 ctl->atm_nc_level, 0);
13106 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
13107 ctl->atm_nc_level, 0);
13108 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
13109 ctl->atm_nc_level, 0);
13110 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
13111 for (int iq = 0; iq < ctl->nq; iq++)
13112 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
13113 ctl->qnt_name[iq], ctl->qnt_unit[iq],
13114 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
13115
13116 /* Define global attributes... */
13117 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
13118 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
13119
13120 /* End definitions... */
13121 NC(nc_enddef(ncid));
13122
13123 /* Write data... */
13124 NC_PUT_DOUBLE("time", atm->time, 0);
13125 NC_PUT_DOUBLE("LAT", atm->lat, 0);
13126 NC_PUT_DOUBLE("LON", atm->lon, 0);
13127 NC_PUT_DOUBLE("PRESS", atm->p, 0);
13128 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
13129 for (int iq = 0; iq < ctl->nq; iq++)
13130 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
13131
13132 /* Close file... */
13133 NC(nc_close(ncid));
13134 }
13135}
13136
13137/*****************************************************************************/
13138
13140 const char *filename,
13141 const ctl_t *ctl,
13142 const atm_t *atm) {
13143
13144 int ncid, obsid, varid;
13145
13146 size_t start[2], count[2];
13147
13148 /* Create file... */
13149 NC(nc_create(filename, NC_NETCDF4, &ncid));
13150
13151 /* Define dimensions... */
13152 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
13153
13154 /* Define variables and their attributes... */
13155 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
13156 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
13157 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
13158 ctl->atm_nc_level, 0);
13159 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
13160 ctl->atm_nc_level, 0);
13161 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
13162 ctl->atm_nc_level, 0);
13163 for (int iq = 0; iq < ctl->nq; iq++)
13164 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
13165 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
13166 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
13167
13168 /* Define global attributes... */
13169 NC_PUT_ATT_GLOBAL("featureType", "point");
13170
13171 /* End definitions... */
13172 NC(nc_enddef(ncid));
13173
13174 /* Write data... */
13175 NC_PUT_DOUBLE("time", atm->time, 0);
13176 NC_PUT_DOUBLE("press", atm->p, 0);
13177 NC_PUT_DOUBLE("lon", atm->lon, 0);
13178 NC_PUT_DOUBLE("lat", atm->lat, 0);
13179 for (int iq = 0; iq < ctl->nq; iq++)
13180 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
13181
13182 /* Close file... */
13183 NC(nc_close(ncid));
13184}
13185
13186/*****************************************************************************/
13187
13189 const char *filename,
13190 const ctl_t *ctl,
13191 const atm_t *atm,
13192 const double t) {
13193
13194 if (ctl->met_coord_type != 0)
13195 ERRMSG("Only lat/lon grid supported");
13196
13197 static FILE *out;
13198
13199 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
13200 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
13201
13202 static int *obscount, nobs, nk;
13203
13204 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
13205
13206 const int ensemble = (ctl->nens > 0);
13207
13208 /* Set timer */
13209 SELECT_TIMER("WRITE_CSI", "OUTPUT");
13210
13211 /* Check quantities... */
13212 if (ctl->qnt_m < 0)
13213 ERRMSG("Need quantity mass!");
13214 if (ensemble) {
13215 if (ctl->qnt_ens < 0)
13216 ERRMSG("Missing ensemble IDs!");
13217 if (ctl->nens > NENS)
13218 ERRMSG("Too many ensembles!");
13219 }
13220
13221 /* Init... */
13222 if (t == ctl->t_start) {
13223
13224 /* Allocate.. */
13225 ALLOC(area, double,
13226 ctl->csi_ny);
13227 ALLOC(rt, double,
13228 NOBS);
13229 ALLOC(rz, double,
13230 NOBS);
13231 ALLOC(rlon, double,
13232 NOBS);
13233 ALLOC(rlat, double,
13234 NOBS);
13235 ALLOC(robs, double,
13236 NOBS);
13237
13238 /* Read observation data... */
13239 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13240
13241 /* Read kernel data... */
13242 if (ctl->csi_kernel[0] != '-')
13243 read_kernel(ctl->csi_kernel, kz, kw, &nk);
13244
13245 /* Create new file... */
13246 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
13247 if (!(out = fopen(filename, "w")))
13248 ERRMSG("Cannot create file!");
13249
13250 /* Write header... */
13251 fprintf(out,
13252 "# $1 = time [s]\n"
13253 "# $2 = ensemble ID\n"
13254 "# $3 = number of hits (cx)\n"
13255 "# $4 = number of misses (cy)\n"
13256 "# $5 = number of false alarms (cz)\n"
13257 "# $6 = number of observations (cx + cy)\n"
13258 "# $7 = number of forecasts (cx + cz)\n"
13259 "# $8 = bias (%%)\n"
13260 "# $9 = POD (%%)\n"
13261 "# $10 = FAR (%%)\n"
13262 "# $11 = CSI (%%)\n"
13263 "# $12 = hits by random chance\n"
13264 "# $13 = ETS (%%)\n"
13265 "# $14 = Pearson R\n"
13266 "# $15 = Spearman R\n"
13267 "# $16 = mean error [kg/m²]\n"
13268 "# $17 = RMSE [kg/m²]\n"
13269 "# $18 = MAE [kg/m²]\n"
13270 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
13271
13272 /* Set grid box size... */
13273 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
13274 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
13275 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
13276
13277 /* Set horizontal coordinates... */
13278 for (int iy = 0; iy < ctl->csi_ny; iy++) {
13279 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
13280 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
13281 }
13282 }
13283
13284 /* Set time interval... */
13285 const double t0 = t - 0.5 * ctl->dt_mod;
13286 const double t1 = t + 0.5 * ctl->dt_mod;
13287
13288 /* Allocate... */
13289 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
13290 ALLOC(modmean, double,
13291 (ensemble ? ctl->nens : 1) * grid_size);
13292 ALLOC(obsmean, double,
13293 grid_size);
13294 ALLOC(obscount, int,
13295 grid_size);
13296 ALLOC(obsstd, double,
13297 grid_size);
13298
13299 /* Init... */
13300 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
13301 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
13302
13303 /* Loop over observations... */
13304 for (int i = 0; i < nobs; i++) {
13305 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
13306 continue;
13307
13308 /* Check grid boundaries and calculate indices... */
13309 if (rlon[i] < ctl->csi_lon0 || rlon[i] >= ctl->csi_lon1
13310 || rlat[i] < ctl->csi_lat0 || rlat[i] >= ctl->csi_lat1
13311 || rz[i] < ctl->csi_z0 || rz[i] >= ctl->csi_z1)
13312 continue;
13313 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
13314 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
13315 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
13316 if (ix >= ctl->csi_nx || iy >= ctl->csi_ny || iz >= ctl->csi_nz)
13317 continue;
13318
13319 /* Get mean observation index... */
13320 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
13321 obsmean[idx] += robs[i];
13322 obsstd[idx] += SQR(robs[i]);
13323 obscount[idx]++;
13324 }
13325
13326 /* Analyze model data... */
13327 for (int ip = 0; ip < atm->np; ip++) {
13328
13329 /* Check time... */
13330 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13331 continue;
13332
13333 /* Get ensemble ID... */
13334 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
13335 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
13336 ERRMSG("Ensemble ID out of range!");
13337
13338 /* Check grid boundaries and get indices... */
13339 const double zpart = Z(atm->p[ip]);
13340 if (atm->lon[ip] < ctl->csi_lon0
13341 || atm->lon[ip] >= ctl->csi_lon1
13342 || atm->lat[ip] < ctl->csi_lat0
13343 || atm->lat[ip] >= ctl->csi_lat1
13344 || zpart < ctl->csi_z0 || zpart >= ctl->csi_z1)
13345 continue;
13346 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
13347 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
13348 const int iz = (int) ((zpart - ctl->csi_z0) / dz);
13349 if (ix >= ctl->csi_nx || iy >= ctl->csi_ny || iz >= ctl->csi_nz)
13350 continue;
13351
13352 /* Get total mass in grid cell... */
13353 const int idx =
13354 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
13355 modmean[idx] +=
13356 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13357 }
13358 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
13359 /* Analyze all grid cells... */
13360 for (int ix = 0; ix < ctl->csi_nx; ix++)
13361 for (int iy = 0; iy < ctl->csi_ny; iy++)
13362 for (int iz = 0; iz < ctl->csi_nz; iz++) {
13363
13364 /* Calculate mean observation index... */
13365 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
13366 if (e == 0)
13367 if (obscount[idx]) {
13368 obsmean[idx] /= obscount[idx];
13369 obsstd[idx] =
13370 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
13371 }
13372
13373 /* Calculate model mean per ensemble... */
13374 const int midx = e * grid_size + idx;
13375 if (modmean[midx] > 0)
13376 modmean[midx] /= (1e6 * area[iy]);
13377
13378 /* Check number of observations... */
13379 if (obscount[idx]) {
13380
13381 /* Calculate CSI... */
13382 ct[e]++;
13383 if (obsmean[idx] >= ctl->csi_obsmin
13384 && modmean[midx] >= ctl->csi_modmin)
13385 cx[e]++;
13386 else if (obsmean[idx] >= ctl->csi_obsmin)
13387 cy[e]++;
13388 else if (modmean[midx] >= ctl->csi_modmin)
13389 cz[e]++;
13390
13391 /* Save data for other verification statistics... */
13392 if (obsmean[idx] >= ctl->csi_obsmin
13393 || modmean[midx] >= ctl->csi_modmin) {
13394 x[n[e]] = modmean[midx];
13395 y[n[e]] = obsmean[idx];
13396 if (modmean[midx] >= ctl->csi_modmin)
13397 obsstdn[n[e]] = obsstd[idx];
13398 if ((++n[e]) >= NCSI)
13399 ERRMSG("Too many points for statistics!");
13400 }
13401 }
13402 }
13403 /* Write output... */
13404 if (fmod(t, ctl->csi_dt_out) == 0) {
13405
13406 if (n[e] == 0)
13407 continue;
13408
13409 /* Calculate verification statistics
13410 (https://www.cawcr.gov.au/projects/verification/) ... */
13411 static double work[2 * NCSI], work2[2 * NCSI];
13412 const int n_obs = cx[e] + cy[e];
13413 const int n_for = cx[e] + cz[e];
13414 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
13415 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
13416 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
13417 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
13418 const double csi =
13419 (cx[e] + cy[e] + cz[e] >
13420 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
13421 const double ets =
13422 (cx[e] + cy[e] + cz[e] - cx_rd >
13423 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
13424 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
13425 const double rho_s =
13426 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
13427 for (int i = 0; i < n[e]; i++) {
13428 work[i] = x[i] - y[i];
13429 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
13430 }
13431 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
13432 const double rmse =
13433 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
13434 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
13435 const double loglikelihood =
13436 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
13437
13438 /* Write... */
13439 fprintf(out,
13440 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
13441 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
13442 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
13443 loglikelihood, n[e]);
13444
13445 /* Set counters to zero... */
13446 for (int i = 0; i < n[e]; i++)
13447 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
13448 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
13449 }
13450 }
13451 /* Free... */
13452 free(modmean);
13453 free(obsmean);
13454 free(obscount);
13455 free(obsstd);
13456
13457 /* Finalize... */
13458 if (t == ctl->t_stop) {
13459
13460 /* Close output file... */
13461 fclose(out);
13462
13463 /* Free... */
13464 free(area);
13465 free(rt);
13466 free(rz);
13467 free(rlon);
13468 free(rlat);
13469 free(robs);
13470 }
13471}
13472
13473/*****************************************************************************/
13474
13476 const char *filename,
13477 const ctl_t *ctl,
13478 const atm_t *atm,
13479 const double t) {
13480
13481 if (ctl->met_coord_type != 0)
13482 ERRMSG("Only lat/lon grid supported");
13483
13484 static FILE *out;
13485
13486 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
13487 x[3], zm[NENS];
13488
13489 static int n[NENS];
13490
13491 /* Set timer... */
13492 SELECT_TIMER("WRITE_ENS", "OUTPUT");
13493
13494 /* Check quantities... */
13495 if (ctl->qnt_ens < 0)
13496 ERRMSG("Missing ensemble IDs!");
13497
13498 /* Set time interval... */
13499 const double t0 = t - 0.5 * ctl->dt_mod;
13500 const double t1 = t + 0.5 * ctl->dt_mod;
13501
13502 /* Init... */
13503 for (int i = 0; i < NENS; i++) {
13504 for (int iq = 0; iq < ctl->nq; iq++)
13505 qm[iq][i] = qs[iq][i] = 0;
13506 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
13507 n[i] = 0;
13508 }
13509
13510 /* Loop over air parcels... */
13511 for (int ip = 0; ip < atm->np; ip++) {
13512
13513 /* Check time... */
13514 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13515 continue;
13516
13517 /* Check ensemble ID... */
13518 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
13519 ERRMSG("Ensemble ID is out of range!");
13520
13521 /* Get means... */
13522 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
13523 for (int iq = 0; iq < ctl->nq; iq++) {
13524 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
13525 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
13526 }
13527 xm[ctl->qnt_ens][0] += x[0];
13528 xm[ctl->qnt_ens][1] += x[1];
13529 xm[ctl->qnt_ens][2] += x[2];
13530 zm[ctl->qnt_ens] += Z(atm->p[ip]);
13531 n[ctl->qnt_ens]++;
13532 }
13533
13534 /* Create file... */
13535 LOG(1, "Write ensemble data: %s", filename);
13536 if (!(out = fopen(filename, "w")))
13537 ERRMSG("Cannot create file!");
13538
13539 /* Write header... */
13540 fprintf(out,
13541 "# $1 = time [s]\n"
13542 "# $2 = altitude [km]\n"
13543 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13544 for (int iq = 0; iq < ctl->nq; iq++)
13545 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
13546 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13547 for (int iq = 0; iq < ctl->nq; iq++)
13548 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
13549 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13550 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
13551
13552 /* Write data... */
13553 for (int i = 0; i < NENS; i++)
13554 if (n[i] > 0) {
13555 cart2geo(xm[i], &dummy, &lon, &lat);
13556 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
13557 for (int iq = 0; iq < ctl->nq; iq++) {
13558 fprintf(out, " ");
13559 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
13560 }
13561 for (int iq = 0; iq < ctl->nq; iq++) {
13562 fprintf(out, " ");
13563 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
13564 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
13565 }
13566 fprintf(out, " %d\n", n[i]);
13567 }
13568
13569 /* Close file... */
13570 fclose(out);
13571}
13572
13573/*****************************************************************************/
13574
13576 const char *filename,
13577 const ctl_t *ctl,
13578 const depo_t *depo,
13579 const double t) {
13580
13581 double *area, *data, *lat, *lon;
13582
13583 /* Set timer... */
13584 SELECT_TIMER("WRITE_DEPO", "OUTPUT");
13585 LOG(1, "Write radioactive deposition data: %s", filename);
13586
13587 /* Allocate output arrays... */
13588 const int nxy = ctl->grid_nx * ctl->grid_ny;
13589 ALLOC(area, double,
13590 ctl->grid_ny);
13591 ALLOC(data, double,
13592 4 * nxy);
13593 ALLOC(lat, double,
13594 ctl->grid_ny);
13595 ALLOC(lon, double,
13596 ctl->grid_nx);
13597
13598 /* Set horizontal coordinates and grid-cell areas... */
13599 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
13600 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
13601 for (int ix = 0; ix < ctl->grid_nx; ix++)
13602 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
13603 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13604 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
13605 area[iy] = 1e6 * dlat * dlon * SQR(RE * M_PI / 180.)
13606 * cos(DEG2RAD(lat[iy]));
13607 }
13608
13609 /* Convert inventories to activity densities at output time... */
13610 const double lambda[4] = {
13611 log(2.0) / RADIO_HALF_LIFE_PB210,
13612 log(2.0) / RADIO_HALF_LIFE_BE7,
13613 log(2.0) / RADIO_HALF_LIFE_CS137,
13614 log(2.0) / RADIO_HALF_LIFE_I131
13615 };
13616 const double *inventory[4] = {
13617 depo->Apb210, depo->Abe7, depo->Acs137, depo->Ai131
13618 };
13619 for (int iq = 0; iq < 4; iq++) {
13620 const double decay = ctl->radio_decay
13621 ? exp(-lambda[iq] * (t - ctl->t_start)) : 1.0;
13622 for (int ix = 0; ix < ctl->grid_nx; ix++)
13623 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13624 const int idx = ARRAY_2D(ix, iy, ctl->grid_ny);
13625 data[iq * nxy + idx] = inventory[iq][idx] * decay / area[iy];
13626 }
13627 }
13628
13629 /* Write output... */
13630 if (ctl->depo_type == 0)
13631 write_depo_asc(filename, ctl, data, t, lon, lat, area);
13632 else if (ctl->depo_type == 1)
13633 write_depo_nc(filename, ctl, data, t, lon, lat, area);
13634 else
13635 ERRMSG("Radioactive deposition output type unknown!");
13636
13637 /* Free... */
13638 free(area);
13639 free(data);
13640 free(lat);
13641 free(lon);
13642}
13643
13644/*****************************************************************************/
13645
13647 const char *filename,
13648 const ctl_t *ctl,
13649 const double *data,
13650 const double t,
13651 const double *lon,
13652 const double *lat,
13653 const double *area) {
13654
13655 FILE *out;
13656 if (!(out = fopen(filename, "w")))
13657 ERRMSG("Cannot create file!");
13658
13659 fprintf(out,
13660 "# $1 = time [s]\n"
13661 "# $2 = longitude [deg]\n"
13662 "# $3 = latitude [deg]\n"
13663 "# $4 = area [m^2]\n"
13664 "# $5 = deposited Pb-210 activity [Bq/m^2]\n"
13665 "# $6 = deposited Be-7 activity [Bq/m^2]\n"
13666 "# $7 = deposited Cs-137 activity [Bq/m^2]\n"
13667 "# $8 = deposited I-131 activity [Bq/m^2]\n\n");
13668
13669 const int nxy = ctl->grid_nx * ctl->grid_ny;
13670 for (int ix = 0; ix < ctl->grid_nx; ix++) {
13671 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13672 const int idx = ARRAY_2D(ix, iy, ctl->grid_ny);
13673 fprintf(out, "%.2f %g %g %g %g %g %g %g\n",
13674 t, lon[ix], lat[iy], area[iy],
13675 data[idx], data[nxy + idx],
13676 data[2 * nxy + idx], data[3 * nxy + idx]);
13677 }
13678 fprintf(out, "\n");
13679 }
13680
13681 fclose(out);
13682}
13683
13684/*****************************************************************************/
13685
13687 const char *filename,
13688 const ctl_t *ctl,
13689 const double *data,
13690 const double t,
13691 const double *lon,
13692 const double *lat,
13693 const double *area) {
13694
13695 double *help;
13696 int ncid, dimid[3], varid;
13697 size_t start[2], count[2];
13698
13699 const int nxy = ctl->grid_nx * ctl->grid_ny;
13700 ALLOC(help, double,
13701 nxy);
13702
13703 /* Create file and dimensions... */
13704 NC(nc_create(filename, NC_NETCDF4, &ncid));
13705 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
13706 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[1]));
13707 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[2]));
13708
13709 /* Define variables... */
13710 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
13711 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
13712 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[1], "latitude",
13713 "degrees_north", 0, 0);
13714 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[2], "longitude",
13715 "degrees_east", 0, 0);
13716 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[1], "surface area", "m**2", 0, 0);
13717 NC_DEF_VAR("depo_pb210", NC_DOUBLE, 3, dimid,
13718 "ground inventory of Pb-210", "Bq m**-2", ctl->grid_nc_level, 0);
13719 NC_DEF_VAR("depo_be7", NC_DOUBLE, 3, dimid,
13720 "ground inventory of Be-7", "Bq m**-2", ctl->grid_nc_level, 0);
13721 NC_DEF_VAR("depo_cs137", NC_DOUBLE, 3, dimid,
13722 "ground inventory of Cs-137", "Bq m**-2", ctl->grid_nc_level, 0);
13723 NC_DEF_VAR("depo_i131", NC_DOUBLE, 3, dimid,
13724 "ground inventory of aerosol-bound I-131", "Bq m**-2",
13725 ctl->grid_nc_level, 0);
13726 NC(nc_enddef(ncid));
13727
13728 /* Write coordinates... */
13729 NC_PUT_DOUBLE("time", &t, 0);
13730 NC_PUT_DOUBLE("lon", lon, 0);
13731 NC_PUT_DOUBLE("lat", lat, 0);
13732 NC_PUT_DOUBLE("area", area, 0);
13733
13734 /* Write fields in netCDF dimension order... */
13735 const char *varname[4] = {
13736 "depo_pb210", "depo_be7", "depo_cs137", "depo_i131"
13737 };
13738 for (int iq = 0; iq < 4; iq++) {
13739 for (int ix = 0; ix < ctl->grid_nx; ix++)
13740 for (int iy = 0; iy < ctl->grid_ny; iy++)
13741 help[ARRAY_2D(iy, ix, ctl->grid_nx)] =
13742 data[iq * nxy + ARRAY_2D(ix, iy, ctl->grid_ny)];
13743 NC_PUT_DOUBLE(varname[iq], help, 0);
13744 }
13745
13746 NC(nc_close(ncid));
13747 free(help);
13748}
13749
13750/*****************************************************************************/
13751
13753 const char *filename,
13754 const ctl_t *ctl,
13755 met_t *met0,
13756 met_t *met1,
13757 const atm_t *atm,
13758 const double t) {
13759
13760 if (ctl->met_coord_type != 0)
13761 ERRMSG("Only lat/lon grid supported");
13762
13763 static double kz[EP], kw[EP];
13764
13765 static int nk;
13766
13767 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
13768
13769 int *ixs, *iys, *izs, *np;
13770
13771 /* Set timer... */
13772 SELECT_TIMER("WRITE_GRID", "OUTPUT");
13773
13774 /* Write info... */
13775 LOG(1, "Write grid data: %s", filename);
13776
13777 /* Init... */
13778 if (t == ctl->t_start) {
13779
13780 /* Read kernel data... */
13781 if (ctl->grid_kernel[0] != '-')
13782 read_kernel(ctl->grid_kernel, kz, kw, &nk);
13783 }
13784
13785 /* Allocate... */
13786 ALLOC(cd, double,
13787 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13788 for (int iq = 0; iq < ctl->nq; iq++) {
13789 ALLOC(mean[iq], double,
13790 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13791 ALLOC(sigma[iq], double,
13792 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13793 }
13794 ALLOC(vmr_impl, double,
13795 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13796 ALLOC(z, double,
13797 ctl->grid_nz);
13798 ALLOC(lon, double,
13799 ctl->grid_nx);
13800 ALLOC(lat, double,
13801 ctl->grid_ny);
13802 ALLOC(area, double,
13803 ctl->grid_ny);
13804 ALLOC(press, double,
13805 ctl->grid_nz);
13806 ALLOC(np, int,
13807 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13808 ALLOC(ixs, int,
13809 atm->np);
13810 ALLOC(iys, int,
13811 atm->np);
13812 ALLOC(izs, int,
13813 atm->np);
13814
13815 /* Set grid box size... */
13816 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
13817 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
13818 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
13819
13820 /* Set vertical coordinates... */
13821#pragma omp parallel for default(shared)
13822 for (int iz = 0; iz < ctl->grid_nz; iz++) {
13823 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
13824 press[iz] = P(z[iz]);
13825 }
13826
13827 /* Set horizontal coordinates... */
13828 for (int ix = 0; ix < ctl->grid_nx; ix++)
13829 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
13830#pragma omp parallel for default(shared)
13831 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13832 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
13833 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
13834 }
13835
13836 /* Set time interval for output... */
13837 const double t0 = t - 0.5 * ctl->dt_mod;
13838 const double t1 = t + 0.5 * ctl->dt_mod;
13839
13840 /* Get grid box indices... */
13841#pragma omp parallel for default(shared)
13842 for (int ip = 0; ip < atm->np; ip++) {
13843 const double zpart = Z(atm->p[ip]);
13844 if (atm->time[ip] < t0 || atm->time[ip] > t1
13845 || atm->lon[ip] < ctl->grid_lon0
13846 || atm->lon[ip] >= ctl->grid_lon1
13847 || atm->lat[ip] < ctl->grid_lat0
13848 || atm->lat[ip] >= ctl->grid_lat1
13849 || zpart < ctl->grid_z0 || zpart >= ctl->grid_z1) {
13850 izs[ip] = -1;
13851 continue;
13852 }
13853 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
13854 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
13855 izs[ip] = (int) ((zpart - ctl->grid_z0) / dz);
13856 if (ixs[ip] >= ctl->grid_nx || iys[ip] >= ctl->grid_ny
13857 || izs[ip] >= ctl->grid_nz)
13858 izs[ip] = -1;
13859 }
13860
13861 /* Average data... */
13862 for (int ip = 0; ip < atm->np; ip++)
13863 if (izs[ip] >= 0) {
13864 const int idx =
13865 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
13866 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
13867 np[idx]++;
13868 for (int iq = 0; iq < ctl->nq; iq++) {
13869 mean[iq][idx] += kernel * atm->q[iq][ip];
13870 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
13871 }
13872 }
13873
13874 /* Calculate column density and volume mixing ratio... */
13875#pragma omp parallel for default(shared)
13876 for (int ix = 0; ix < ctl->grid_nx; ix++)
13877 for (int iy = 0; iy < ctl->grid_ny; iy++)
13878 for (int iz = 0; iz < ctl->grid_nz; iz++) {
13879
13880 /* Get grid index... */
13881 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
13882
13883 /* Calculate column density... */
13884 cd[idx] = NAN;
13885 if (ctl->qnt_m >= 0)
13886 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
13887
13888 /* Calculate volume mixing ratio (implicit)... */
13889 vmr_impl[idx] = NAN;
13890 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
13891 && met1 != NULL) {
13892 vmr_impl[idx] = 0;
13893 if (mean[ctl->qnt_m][idx] > 0) {
13894
13895 /* Get temperature... */
13896 double temp;
13898 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
13899 lon[ix], lat[iy], &temp, ci, cw, 1);
13900
13901 /* Calculate volume mixing ratio... */
13902 vmr_impl[idx] =
13903 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
13904 }
13905 }
13906
13907 /* Calculate mean... */
13908 if (np[idx] > 0)
13909 for (int iq = 0; iq < ctl->nq; iq++) {
13910 mean[iq][idx] /= np[idx];
13911 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
13912 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
13913 } else
13914 for (int iq = 0; iq < ctl->nq; iq++) {
13915 mean[iq][idx] = NAN;
13916 sigma[iq][idx] = NAN;
13917 }
13918 }
13919
13920 /* Write ASCII data... */
13921 if (ctl->grid_type == 0)
13922 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
13923 t, z, lon, lat, area, dz, np);
13924
13925 /* Write netCDF data... */
13926 else if (ctl->grid_type == 1)
13927 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
13928 t, z, lon, lat, area, dz, np);
13929
13930 /* Error message... */
13931 else
13932 ERRMSG("Grid data format GRID_TYPE unknown!");
13933
13934 /* Free... */
13935 free(cd);
13936 for (int iq = 0; iq < ctl->nq; iq++) {
13937 free(mean[iq]);
13938 free(sigma[iq]);
13939 }
13940 free(vmr_impl);
13941 free(z);
13942 free(lon);
13943 free(lat);
13944 free(area);
13945 free(press);
13946 free(np);
13947 free(ixs);
13948 free(iys);
13949 free(izs);
13950}
13951
13952/*****************************************************************************/
13953
13955 const char *filename,
13956 const ctl_t *ctl,
13957 const double *cd,
13958 double *mean[NQ],
13959 double *sigma[NQ],
13960 const double *vmr_impl,
13961 const double t,
13962 const double *z,
13963 const double *lon,
13964 const double *lat,
13965 const double *area,
13966 const double dz,
13967 const int *np) {
13968
13969 FILE *out;
13970
13971 /* Check if gnuplot output is requested... */
13972 if (ctl->grid_gpfile[0] != '-') {
13973
13974 /* Create gnuplot pipe... */
13975 if (!(out = popen("gnuplot", "w")))
13976 ERRMSG("Cannot create pipe to gnuplot!");
13977
13978 /* Set plot filename... */
13979 fprintf(out, "set out \"%s.png\"\n", filename);
13980
13981 /* Set time string... */
13982 double r;
13983 int year, mon, day, hour, min, sec;
13984 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
13985 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
13986 year, mon, day, hour, min);
13987
13988 /* Dump gnuplot file to pipe... */
13989 FILE *in;
13990 char line[LEN];
13991 if (!(in = fopen(ctl->grid_gpfile, "r")))
13992 ERRMSG("Cannot open file!");
13993 while (fgets(line, LEN, in))
13994 fprintf(out, "%s", line);
13995 fclose(in);
13996 }
13997
13998 else {
13999
14000 /* Create file... */
14001 if (!(out = fopen(filename, "w")))
14002 ERRMSG("Cannot create file!");
14003 }
14004
14005 /* Write header... */
14006 fprintf(out,
14007 "# $1 = time [s]\n"
14008 "# $2 = altitude [km]\n"
14009 "# $3 = longitude [deg]\n"
14010 "# $4 = latitude [deg]\n"
14011 "# $5 = surface area [km^2]\n"
14012 "# $6 = layer depth [km]\n"
14013 "# $7 = column density (implicit) [kg/m^2]\n"
14014 "# $8 = volume mixing ratio (implicit) [ppv]\n"
14015 "# $9 = number of particles [1]\n");
14016 for (int iq = 0; iq < ctl->nq; iq++)
14017 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
14018 ctl->qnt_unit[iq]);
14019 if (ctl->grid_stddev)
14020 for (int iq = 0; iq < ctl->nq; iq++)
14021 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
14022 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
14023 fprintf(out, "\n");
14024
14025 /* Write data... */
14026 for (int ix = 0; ix < ctl->grid_nx; ix++) {
14027 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
14028 fprintf(out, "\n");
14029 for (int iy = 0; iy < ctl->grid_ny; iy++) {
14030 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
14031 fprintf(out, "\n");
14032 for (int iz = 0; iz < ctl->grid_nz; iz++) {
14033 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
14034 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
14035 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
14036 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
14037 for (int iq = 0; iq < ctl->nq; iq++) {
14038 fprintf(out, " ");
14039 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
14040 }
14041 if (ctl->grid_stddev)
14042 for (int iq = 0; iq < ctl->nq; iq++) {
14043 fprintf(out, " ");
14044 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
14045 }
14046 fprintf(out, "\n");
14047 }
14048 }
14049 }
14050 }
14051
14052 /* Close file... */
14053 fclose(out);
14054}
14055
14056/*****************************************************************************/
14057
14059 const char *filename,
14060 const ctl_t *ctl,
14061 const double *cd,
14062 double *mean[NQ],
14063 double *sigma[NQ],
14064 const double *vmr_impl,
14065 const double t,
14066 const double *z,
14067 const double *lon,
14068 const double *lat,
14069 const double *area,
14070 const double dz,
14071 const int *np) {
14072
14073 char longname[2 * LEN], varname[2 * LEN];
14074
14075 double *help;
14076
14077 int *help2, ncid, dimid[10], varid;
14078
14079 size_t start[2], count[2];
14080
14081 /* Allocate... */
14082 ALLOC(help, double,
14083 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
14084 ALLOC(help2, int,
14085 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
14086
14087 /* Create file... */
14088 NC(nc_create(filename, NC_NETCDF4, &ncid));
14089
14090 /* Define dimensions... */
14091 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
14092 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
14093 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
14094 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
14095 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
14096
14097 /* Define variables and their attributes... */
14098 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
14099 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
14100 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
14101 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
14102 0);
14103 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
14104 0);
14105 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
14106 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
14107
14108 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
14109 ctl->grid_nc_level, 0);
14110 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
14111 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
14112 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
14113 for (int iq = 0; iq < ctl->nq; iq++) {
14114 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
14115 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
14116 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
14117 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
14118 if (ctl->grid_stddev) {
14119 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
14120 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
14121 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
14122 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
14123 }
14124 }
14125 /* End definitions... */
14126 NC(nc_enddef(ncid));
14127
14128 /* Write data... */
14129 NC_PUT_DOUBLE("time", &t, 0);
14130 NC_PUT_DOUBLE("lon", lon, 0);
14131 NC_PUT_DOUBLE("lat", lat, 0);
14132 NC_PUT_DOUBLE("z", z, 0);
14133 NC_PUT_DOUBLE("area", area, 0);
14134 NC_PUT_DOUBLE("dz", &dz, 0);
14135
14136 for (int ix = 0; ix < ctl->grid_nx; ix++)
14137 for (int iy = 0; iy < ctl->grid_ny; iy++)
14138 for (int iz = 0; iz < ctl->grid_nz; iz++)
14139 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14140 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14141 NC_PUT_DOUBLE("cd", help, 0);
14142
14143 for (int ix = 0; ix < ctl->grid_nx; ix++)
14144 for (int iy = 0; iy < ctl->grid_ny; iy++)
14145 for (int iz = 0; iz < ctl->grid_nz; iz++)
14146 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14147 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14148 NC_PUT_DOUBLE("vmr_impl", help, 0);
14149
14150 for (int ix = 0; ix < ctl->grid_nx; ix++)
14151 for (int iy = 0; iy < ctl->grid_ny; iy++)
14152 for (int iz = 0; iz < ctl->grid_nz; iz++)
14153 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14154 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14155 NC_PUT_INT("np", help2, 0);
14156
14157 for (int iq = 0; iq < ctl->nq; iq++) {
14158 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
14159 for (int ix = 0; ix < ctl->grid_nx; ix++)
14160 for (int iy = 0; iy < ctl->grid_ny; iy++)
14161 for (int iz = 0; iz < ctl->grid_nz; iz++)
14162 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14163 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14164 NC_PUT_DOUBLE(varname, help, 0);
14165 }
14166
14167 if (ctl->grid_stddev)
14168 for (int iq = 0; iq < ctl->nq; iq++) {
14169 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
14170 for (int ix = 0; ix < ctl->grid_nx; ix++)
14171 for (int iy = 0; iy < ctl->grid_ny; iy++)
14172 for (int iz = 0; iz < ctl->grid_nz; iz++)
14173 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
14174 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
14175 NC_PUT_DOUBLE(varname, help, 0);
14176 }
14177
14178 /* Close file... */
14179 NC(nc_close(ncid));
14180
14181 /* Free... */
14182 free(help);
14183 free(help2);
14184}
14185
14186/*****************************************************************************/
14187
14189 const char *filename,
14190 const ctl_t *ctl,
14191 met_t *met) {
14192
14193 /* Create file... */
14194 FILE *out, *level_log = NULL;
14195 if (!(out = fopen(filename, "w")))
14196 ERRMSG("Cannot create file!");
14197
14198 /* Create diagnostics file... */
14199 if (strcmp(ctl->met_comp_logfile, "-") != 0) {
14200
14201 if (!(level_log = fopen(ctl->met_comp_logfile, "w")))
14202 ERRMSG("Cannot create compression log file!");
14203 LOG(1, "Write compression diagnostics: %s", ctl->met_comp_logfile);
14204
14205 /* Write header... */
14206 fprintf(level_log,
14207 "# $1 = compression codec name [-]\n"
14208 "# $2 = variable name [-]\n"
14209 "# $3 = level index [-]\n"
14210 "# $4 = pressure level [hPa]\n"
14211 "# $5 = compression ratio [-]\n"
14212 "# $6 = bits per value [bit/value]\n"
14213 "# $7 = correlation coefficient [-]\n"
14214 "# $8 = mean compression error [-]\n"
14215 "# $9 = standard deviation of compression error [-]\n"
14216 "# $10 = minimum compression error [-]\n"
14217 "# $11 = maximum compression error [-]\n"
14218 "# $12 = mean value of original field [-]\n"
14219 "# $13 = value range of original field [-]\n"
14220 "# $14 = normalized root mean square error [-]\n"
14221 "# $15 = compression time [s]\n"
14222 "# $16 = compression speed [MiB/s]\n"
14223 "# $17 = decompression time [s]\n"
14224 "# $18 = decompression speed [MiB/s]\n\n");
14225 }
14226
14227 /* Write type of binary data... */
14228 FWRITE(&ctl->met_type, int,
14229 1,
14230 out);
14231
14232 /* Write version of binary data... */
14233 int version = 104;
14234 FWRITE(&version, int,
14235 1,
14236 out);
14237
14238 /* Write grid data... */
14239 FWRITE(&met->time, double,
14240 1,
14241 out);
14242 FWRITE(&met->nx, int,
14243 1,
14244 out);
14245 FWRITE(&met->ny, int,
14246 1,
14247 out);
14248 FWRITE(&met->np, int,
14249 1,
14250 out);
14251 FWRITE(met->lon, double,
14252 (size_t) met->nx,
14253 out);
14254 FWRITE(met->lat, double,
14255 (size_t) met->ny,
14256 out);
14257 FWRITE(met->p, double,
14258 (size_t) met->np,
14259 out);
14260
14261 /* Write surface data... */
14262 write_met_bin_2d(out, met, met->ps, "PS");
14263 write_met_bin_2d(out, met, met->ts, "TS");
14264 write_met_bin_2d(out, met, met->zs, "ZS");
14265 write_met_bin_2d(out, met, met->us, "US");
14266 write_met_bin_2d(out, met, met->vs, "VS");
14267 write_met_bin_2d(out, met, met->ess, "ESS");
14268 write_met_bin_2d(out, met, met->nss, "NSS");
14269 write_met_bin_2d(out, met, met->shf, "SHF");
14270 write_met_bin_2d(out, met, met->lsm, "LSM");
14271 write_met_bin_2d(out, met, met->sst, "SST");
14272 write_met_bin_2d(out, met, met->pbl, "PBL");
14273 write_met_bin_2d(out, met, met->pt, "PT");
14274 write_met_bin_2d(out, met, met->tt, "TT");
14275 write_met_bin_2d(out, met, met->zt, "ZT");
14276 write_met_bin_2d(out, met, met->h2ot, "H2OT");
14277 write_met_bin_2d(out, met, met->pct, "PCT");
14278 write_met_bin_2d(out, met, met->pcb, "PCB");
14279 write_met_bin_2d(out, met, met->cl, "CL");
14280 write_met_bin_2d(out, met, met->plcl, "PLCL");
14281 write_met_bin_2d(out, met, met->plfc, "PLFC");
14282 write_met_bin_2d(out, met, met->pel, "PEL");
14283 write_met_bin_2d(out, met, met->cape, "CAPE");
14284 write_met_bin_2d(out, met, met->cin, "CIN");
14285 write_met_bin_2d(out, met, met->o3c, "O3C");
14286
14287 /* Write level data... */
14288 write_met_bin_3d(out, ctl, met, met->z, "Z", 0, level_log);
14289 write_met_bin_3d(out, ctl, met, met->t, "T", 1, level_log);
14290 write_met_bin_3d(out, ctl, met, met->u, "U", 2, level_log);
14291 write_met_bin_3d(out, ctl, met, met->v, "V", 3, level_log);
14292 write_met_bin_3d(out, ctl, met, met->w, "W", 4, level_log);
14293 write_met_bin_3d(out, ctl, met, met->pv, "PV", 5, level_log);
14294 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", 6, level_log);
14295 write_met_bin_3d(out, ctl, met, met->o3, "O3", 7, level_log);
14296 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", 8, level_log);
14297 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", 9, level_log);
14298 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", 10, level_log);
14299 write_met_bin_3d(out, ctl, met, met->swc, "SWC", 11, level_log);
14300 write_met_bin_3d(out, ctl, met, met->cc, "CC", 12, level_log);
14301 if (METVAR != 13)
14302 ERRMSG("Number of meteo variables doesn't match!");
14303
14304 /* Write final flag... */
14305 int final = 999;
14306 FWRITE(&final, int,
14307 1,
14308 out);
14309
14310 /* Close file... */
14311 if (level_log)
14312 fclose(level_log);
14313 fclose(out);
14314}
14315
14316/*****************************************************************************/
14317
14319 FILE *out,
14320 met_t *met,
14321 float var[EX][EY],
14322 const char *varname) {
14323
14324 float *help;
14325
14326 /* Allocate... */
14327 ALLOC(help, float,
14328 EX * EY);
14329
14330 /* Copy data... */
14331 for (int ix = 0; ix < met->nx; ix++)
14332 for (int iy = 0; iy < met->ny; iy++)
14333 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
14334
14335 /* Write uncompressed data... */
14336 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
14337 FWRITE(help, float,
14338 (size_t) (met->nx * met->ny),
14339 out);
14340
14341 /* Free... */
14342 free(help);
14343}
14344
14345/*****************************************************************************/
14346
14348 FILE *out,
14349 const ctl_t *ctl,
14350 met_t *met,
14351 float var[EX][EY][EP],
14352 const char *varname,
14353 const int metvar,
14354 FILE *level_log) {
14355
14356 float *help;
14357
14358 /* Allocate... */
14359 ALLOC(help, float,
14360 EX * EY * EP);
14361
14362 /* Copy data... */
14363#pragma omp parallel for default(shared) collapse(2)
14364 for (int ix = 0; ix < met->nx; ix++)
14365 for (int iy = 0; iy < met->ny; iy++)
14366 for (int ip = 0; ip < met->np; ip++)
14367 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
14368
14369 /* Write uncompressed data... */
14370 if (ctl->met_type == 1) {
14371 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
14372 FWRITE(help, float,
14373 (size_t) (met->nx * met->ny * met->np),
14374 out);
14375 }
14376
14377 /* Write packed data... */
14378 else if (ctl->met_type == 2)
14379 compress_pck(ctl, met, varname, help, 0, level_log, out);
14380
14381 /* Write ZFP data... */
14382#ifdef ZFP
14383 else if (ctl->met_type == 3) {
14384 FWRITE(&ctl->met_zfp_prec[metvar], int,
14385 1,
14386 out);
14387 FWRITE(&ctl->met_zfp_tol[metvar], double,
14388 1,
14389 out);
14390 compress_zfp(ctl, met, varname, help, 0, level_log, out);
14391 }
14392#endif
14393
14394 /* Write zstd data... */
14395#ifdef ZSTD
14396 else if (ctl->met_type == 4)
14397 compress_zstd(ctl, met, varname, help, 0, level_log, out);
14398#endif
14399
14400 /* Write LZ4 data... */
14401#ifdef LZ4
14402 else if (ctl->met_type == 8)
14403 compress_lz4(ctl, met, varname, help, 0, level_log, out);
14404#endif
14405
14406 /* Write cmultiscale data... */
14407#ifdef CMS
14408 else if (ctl->met_type == 5) {
14409 compress_cms(ctl, met, varname, help, 0, level_log, out);
14410 }
14411#endif
14412
14413 /* Write SZ3 data... */
14414#ifdef SZ3
14415 else if (ctl->met_type == 7) {
14416 FWRITE(&ctl->met_sz3_prec[metvar], int,
14417 1,
14418 out);
14419 FWRITE(&ctl->met_sz3_tol[metvar], double,
14420 1,
14421 out);
14422 compress_sz3(ctl, met, varname, help, 0, level_log, out);
14423 }
14424#endif
14425
14426 /* Unknown method... */
14427 else {
14428 ERRMSG("MET_TYPE not supported!");
14429
14430 /* This will never execute, hack to avoid compilation error... */
14431 LOG(3, "%d", metvar);
14432 }
14433
14434 /* Free... */
14435 free(help);
14436}
14437
14438/*****************************************************************************/
14439
14441 const char *filename,
14442 const ctl_t *ctl,
14443 met_t *met) {
14444
14445 /* Create file... */
14446 int ncid, varid;
14447 size_t start[4], count[4];
14448 NC(nc_create(filename, NC_NETCDF4, &ncid));
14449
14450 /* Define dimensions... */
14451 int tid, lonid, latid, levid;
14452 NC(nc_def_dim(ncid, "time", 1, &tid));
14453
14454 if (met->coord_type == 0) {
14455 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
14456 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
14457 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0,
14458 0);
14459 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0,
14460 0);
14461 } else {
14462 NC(nc_def_dim(ncid, "x", (size_t) met->nx, &lonid));
14463 NC(nc_def_dim(ncid, "y", (size_t) met->ny, &latid));
14464 NC_DEF_VAR("x", NC_DOUBLE, 1, &lonid, "x", "easting", 0, 0);
14465 NC_DEF_VAR("y", NC_DOUBLE, 1, &latid, "y", "northing", 0, 0);
14466 }
14467
14468 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
14469
14470 /* Define grid... */
14471 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
14472 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
14473 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
14474
14475 /* Define surface variables... */
14476 int dimid2[3] = { tid, latid, lonid };
14477 NC_DEF_VAR("sp", NC_FLOAT, 3, dimid2, "Surface pressure", "Pa",
14478 ctl->met_nc_level, 0);
14479 NC_DEF_VAR("z", NC_FLOAT, 3, dimid2, "Geopotential", "m**2 s**-2",
14480 ctl->met_nc_level, 0);
14481 NC_DEF_VAR("t2m", NC_FLOAT, 3, dimid2, "2 metre temperature", "K",
14482 ctl->met_nc_level, 0);
14483 NC_DEF_VAR("u10m", NC_FLOAT, 3, dimid2, "10 metre U wind component",
14484 "m s**-1", ctl->met_nc_level, 0);
14485 NC_DEF_VAR("v10m", NC_FLOAT, 3, dimid2, "10 metre V wind component",
14486 "m s**-1", ctl->met_nc_level, 0);
14487 NC_DEF_VAR("iews", NC_FLOAT, 3, dimid2,
14488 "Instantaneous eastward turbulent surface stress", "N m**-2",
14489 ctl->met_nc_level, 0);
14490 NC_DEF_VAR("inss", NC_FLOAT, 3, dimid2,
14491 "Instantaneous northward turbulent surface stress", "N m**-2",
14492 ctl->met_nc_level, 0);
14493 NC_DEF_VAR("ishf", NC_FLOAT, 3, dimid2,
14494 "Instantaneous surface sensible heat flux", "W m**-2",
14495 ctl->met_nc_level, 0);
14496 NC_DEF_VAR("lsm", NC_FLOAT, 3, dimid2, "Land/sea mask", "-",
14497 ctl->met_nc_level, 0);
14498 NC_DEF_VAR("sstk", NC_FLOAT, 3, dimid2, "Sea surface temperature", "K",
14499 ctl->met_nc_level, 0);
14500 NC_DEF_VAR("blp", NC_FLOAT, 3, dimid2, "Boundary layer pressure", "Pa",
14501 ctl->met_nc_level, 0);
14502 NC_DEF_VAR("pt", NC_FLOAT, 3, dimid2, "Tropopause pressure", "Pa",
14503 ctl->met_nc_level, 0);
14504 NC_DEF_VAR("tt", NC_FLOAT, 3, dimid2, "Tropopause temperature", "K",
14505 ctl->met_nc_level, 0);
14506 NC_DEF_VAR("zt", NC_FLOAT, 3, dimid2, "Tropopause height", "m",
14507 ctl->met_nc_level, 0);
14508 NC_DEF_VAR("h2ot", NC_FLOAT, 3, dimid2, "Tropopause water vapor", "ppv",
14509 ctl->met_nc_level, 0);
14510 NC_DEF_VAR("pct", NC_FLOAT, 3, dimid2, "Cloud top pressure", "Pa",
14511 ctl->met_nc_level, 0);
14512 NC_DEF_VAR("pcb", NC_FLOAT, 3, dimid2, "Cloud bottom pressure", "Pa",
14513 ctl->met_nc_level, 0);
14514 NC_DEF_VAR("cl", NC_FLOAT, 3, dimid2, "Total column cloud water",
14515 "kg m**2", ctl->met_nc_level, 0);
14516 NC_DEF_VAR("plcl", NC_FLOAT, 3, dimid2,
14517 "Pressure at lifted condensation level (LCL)", "Pa",
14518 ctl->met_nc_level, 0);
14519 NC_DEF_VAR("plfc", NC_FLOAT, 3, dimid2,
14520 "Pressure at level of free convection (LFC)", "Pa",
14521 ctl->met_nc_level, 0);
14522 NC_DEF_VAR("pel", NC_FLOAT, 3, dimid2,
14523 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
14524 0);
14525 NC_DEF_VAR("cape", NC_FLOAT, 3, dimid2,
14526 "Convective available potential energy", "J kg**-1",
14527 ctl->met_nc_level, 0);
14528 NC_DEF_VAR("cin", NC_FLOAT, 3, dimid2, "Convective inhibition",
14529 "J kg**-1", ctl->met_nc_level, 0);
14530 NC_DEF_VAR("o3c", NC_FLOAT, 3, dimid2, "Total column ozone", "DU",
14531 ctl->met_nc_level, 0);
14532
14533 /* Define level data... */
14534 int dimid3[4] = { tid, levid, latid, lonid };
14535 NC_DEF_VAR("t", NC_FLOAT, 4, dimid3, "Temperature", "K",
14536 ctl->met_nc_level, ctl->met_nc_quant);
14537 NC_DEF_VAR("u", NC_FLOAT, 4, dimid3, "U velocity", "m s**-1",
14538 ctl->met_nc_level, ctl->met_nc_quant);
14539 NC_DEF_VAR("v", NC_FLOAT, 4, dimid3, "V velocity", "m s**-1",
14540 ctl->met_nc_level, ctl->met_nc_quant);
14541 NC_DEF_VAR("w", NC_FLOAT, 4, dimid3, "Vertical velocity", "Pa s**-1",
14542 ctl->met_nc_level, ctl->met_nc_quant);
14543 NC_DEF_VAR("q", NC_FLOAT, 4, dimid3, "Specific humidity", "kg kg**-1",
14544 ctl->met_nc_level, ctl->met_nc_quant);
14545 NC_DEF_VAR("o3", NC_FLOAT, 4, dimid3, "Ozone mass mixing ratio",
14546 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14547 NC_DEF_VAR("clwc", NC_FLOAT, 4, dimid3, "Cloud liquid water content",
14548 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14549 NC_DEF_VAR("crwc", NC_FLOAT, 4, dimid3, "Cloud rain water content",
14550 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14551 NC_DEF_VAR("ciwc", NC_FLOAT, 4, dimid3, "Cloud ice water content",
14552 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14553 NC_DEF_VAR("cswc", NC_FLOAT, 4, dimid3, "Cloud snow water content",
14554 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
14555 NC_DEF_VAR("cc", NC_FLOAT, 4, dimid3, "Cloud cover", "-",
14556 ctl->met_nc_level, ctl->met_nc_quant);
14557
14558 /* End definitions... */
14559 NC(nc_enddef(ncid));
14560
14561 /* Write grid data... */
14562 NC_PUT_DOUBLE("time", &met->time, 0);
14563
14564 if (met->coord_type == 0) {
14565 NC_PUT_DOUBLE("lon", met->lon, 0);
14566 NC_PUT_DOUBLE("lat", met->lat, 0);
14567 } else {
14568 NC_PUT_DOUBLE("x", met->lon, 0);
14569 NC_PUT_DOUBLE("y", met->lat, 0);
14570 }
14571
14572 double phelp[EP];
14573 for (int ip = 0; ip < met->np; ip++)
14574 phelp[ip] = 100. * met->p[ip];
14575 NC_PUT_DOUBLE("lev", phelp, 0);
14576
14577 /* Write surface data... */
14578 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
14579 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
14580 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
14581 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
14582 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
14583 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
14584 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
14585 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
14586 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
14587 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
14588 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
14589 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
14590 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
14591 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
14592 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
14593 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
14594 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
14595 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
14596 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
14597 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
14598 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
14599 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
14600 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
14601 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
14602
14603 /* Write level data... */
14604 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
14605 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
14606 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
14607 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
14608 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
14609 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
14610 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
14611 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
14612 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
14613 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
14614 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
14615
14616 /* Close file... */
14617 NC(nc_close(ncid));
14618}
14619
14620/*****************************************************************************/
14621
14623 const int ncid,
14624 const char *varname,
14625 met_t *met,
14626 float var[EX][EY],
14627 const float scl) {
14628
14629 int varid;
14630 size_t start[4], count[4];
14631
14632 /* Allocate... */
14633 float *help;
14634 ALLOC(help, float,
14635 EX * EY);
14636
14637 /* Copy data... */
14638 for (int ix = 0; ix < met->nx; ix++)
14639 for (int iy = 0; iy < met->ny; iy++)
14640 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
14641
14642 /* Write data... */
14643 LOG(2, "Write 2-D variable: %s (netCDF)", varname);
14644 NC_PUT_FLOAT(varname, help, 0);
14645
14646 /* Free... */
14647 free(help);
14648}
14649
14650/*****************************************************************************/
14651
14653 const int ncid,
14654 const char *varname,
14655 met_t *met,
14656 float var[EX][EY][EP],
14657 const float scl) {
14658
14659 int varid;
14660 size_t start[4], count[4];
14661
14662 /* Allocate... */
14663 float *help;
14664 ALLOC(help, float,
14665 EX * EY * EP);
14666
14667 /* Copy data... */
14668 for (int ix = 0; ix < met->nx; ix++)
14669 for (int iy = 0; iy < met->ny; iy++)
14670 for (int ip = 0; ip < met->np; ip++)
14671 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
14672
14673 /* Write data... */
14674 LOG(2, "Write 3-D variable: %s (netCDF)", varname);
14675 NC_PUT_FLOAT(varname, help, 0);
14676
14677 /* Free... */
14678 free(help);
14679}
14680
14681/*****************************************************************************/
14682
14684 const char *filename,
14685 const ctl_t *ctl,
14686 met_t *met0,
14687 met_t *met1,
14688 const atm_t *atm,
14689 const double t) {
14690
14691 if (ctl->met_coord_type != 0)
14692 ERRMSG("Only lat/lon grid supported");
14693
14694 static FILE *out;
14695
14696 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
14697 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
14698
14699 static int nobs, *obscount, ip, okay;
14700
14701 /* Set timer... */
14702 SELECT_TIMER("WRITE_PROF", "OUTPUT");
14703
14704 /* Init... */
14705 if (t == ctl->t_start) {
14706
14707 /* Check quantity index for mass... */
14708 if (ctl->qnt_m < 0)
14709 ERRMSG("Need quantity mass!");
14710
14711 /* Check molar mass... */
14712 if (ctl->molmass <= 0)
14713 ERRMSG("Specify molar mass!");
14714
14715 /* Allocate... */
14716 ALLOC(lon, double,
14717 ctl->prof_nx);
14718 ALLOC(lat, double,
14719 ctl->prof_ny);
14720 ALLOC(area, double,
14721 ctl->prof_ny);
14722 ALLOC(z, double,
14723 ctl->prof_nz);
14724 ALLOC(press, double,
14725 ctl->prof_nz);
14726 ALLOC(rt, double,
14727 NOBS);
14728 ALLOC(rz, double,
14729 NOBS);
14730 ALLOC(rlon, double,
14731 NOBS);
14732 ALLOC(rlat, double,
14733 NOBS);
14734 ALLOC(robs, double,
14735 NOBS);
14736
14737 /* Read observation data... */
14738 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
14739
14740 /* Create new output file... */
14741 LOG(1, "Write profile data: %s", filename);
14742 if (!(out = fopen(filename, "w")))
14743 ERRMSG("Cannot create file!");
14744
14745 /* Write header... */
14746 fprintf(out,
14747 "# $1 = time [s]\n"
14748 "# $2 = altitude [km]\n"
14749 "# $3 = longitude [deg]\n"
14750 "# $4 = latitude [deg]\n"
14751 "# $5 = pressure [hPa]\n"
14752 "# $6 = temperature [K]\n"
14753 "# $7 = volume mixing ratio [ppv]\n"
14754 "# $8 = H2O volume mixing ratio [ppv]\n"
14755 "# $9 = O3 volume mixing ratio [ppv]\n"
14756 "# $10 = observed BT index [K]\n"
14757 "# $11 = number of observations\n");
14758
14759 /* Set grid box size... */
14760 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
14761 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
14762 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
14763
14764 /* Set vertical coordinates... */
14765 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14766 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
14767 press[iz] = P(z[iz]);
14768 }
14769
14770 /* Set horizontal coordinates... */
14771 for (int ix = 0; ix < ctl->prof_nx; ix++)
14772 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
14773 for (int iy = 0; iy < ctl->prof_ny; iy++) {
14774 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
14775 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
14776 }
14777 }
14778
14779 /* Set time interval... */
14780 const double t0 = t - 0.5 * ctl->dt_mod;
14781 const double t1 = t + 0.5 * ctl->dt_mod;
14782
14783 /* Allocate... */
14784 ALLOC(mass, double,
14785 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
14786 ALLOC(obsmean, double,
14787 ctl->prof_nx * ctl->prof_ny);
14788 ALLOC(obscount, int,
14789 ctl->prof_nx * ctl->prof_ny);
14790
14791 /* Loop over observations... */
14792 for (int i = 0; i < nobs; i++) {
14793
14794 /* Check time... */
14795 if (rt[i] < t0)
14796 continue;
14797 else if (rt[i] >= t1)
14798 break;
14799
14800 /* Check observation data... */
14801 if (!isfinite(robs[i]))
14802 continue;
14803
14804 /* Check grid boundaries and calculate indices... */
14805 if (rlon[i] < ctl->prof_lon0 || rlon[i] >= ctl->prof_lon1
14806 || rlat[i] < ctl->prof_lat0 || rlat[i] >= ctl->prof_lat1)
14807 continue;
14808 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
14809 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
14810 if (ix >= ctl->prof_nx || iy >= ctl->prof_ny)
14811 continue;
14812
14813 /* Get mean observation index... */
14814 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
14815 obsmean[idx] += robs[i];
14816 obscount[idx]++;
14817 }
14818
14819 /* Analyze model data... */
14820 for (ip = 0; ip < atm->np; ip++) {
14821
14822 /* Check time... */
14823 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14824 continue;
14825
14826 /* Check grid boundaries and get indices... */
14827 const double zpart = Z(atm->p[ip]);
14828 if (atm->lon[ip] < ctl->prof_lon0
14829 || atm->lon[ip] >= ctl->prof_lon1
14830 || atm->lat[ip] < ctl->prof_lat0
14831 || atm->lat[ip] >= ctl->prof_lat1
14832 || zpart < ctl->prof_z0 || zpart >= ctl->prof_z1)
14833 continue;
14834 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
14835 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
14836 const int iz = (int) ((zpart - ctl->prof_z0) / dz);
14837 if (ix >= ctl->prof_nx || iy >= ctl->prof_ny || iz >= ctl->prof_nz)
14838 continue;
14839
14840 /* Get total mass in grid cell... */
14841 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14842 mass[idx] += atm->q[ctl->qnt_m][ip];
14843 }
14844
14845 /* Extract profiles... */
14846 for (int ix = 0; ix < ctl->prof_nx; ix++)
14847 for (int iy = 0; iy < ctl->prof_ny; iy++) {
14848 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
14849 if (obscount[idx2] > 0) {
14850
14851 /* Check profile... */
14852 okay = 0;
14853 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14854 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14855 if (mass[idx3] > 0) {
14856 okay = 1;
14857 break;
14858 }
14859 }
14860 if (!okay)
14861 continue;
14862
14863 /* Write output... */
14864 fprintf(out, "\n");
14865
14866 /* Loop over altitudes... */
14867 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14868
14869 /* Get temperature, water vapor, and ozone... */
14871 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
14872 lon[ix], lat[iy], &temp, ci, cw, 1);
14873 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
14874 lon[ix], lat[iy], &h2o, ci, cw, 0);
14875 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
14876 lon[ix], lat[iy], &o3, ci, cw, 0);
14877
14878 /* Calculate volume mixing ratio... */
14879 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14880 vmr = MA / ctl->molmass * mass[idx3]
14881 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
14882
14883 /* Write output... */
14884 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
14885 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
14886 obsmean[idx2] / obscount[idx2], obscount[idx2]);
14887 }
14888 }
14889 }
14890
14891 /* Free... */
14892 free(mass);
14893 free(obsmean);
14894 free(obscount);
14895
14896 /* Finalize... */
14897 if (t == ctl->t_stop) {
14898
14899 /* Close output file... */
14900 fclose(out);
14901
14902 /* Free... */
14903 free(lon);
14904 free(lat);
14905 free(area);
14906 free(z);
14907 free(press);
14908 free(rt);
14909 free(rz);
14910 free(rlon);
14911 free(rlat);
14912 free(robs);
14913 }
14914}
14915
14916/*****************************************************************************/
14917
14919 const char *filename,
14920 const ctl_t *ctl,
14921 met_t *met0,
14922 met_t *met1,
14923 const atm_t *atm,
14924 const double t) {
14925
14926 if (ctl->met_coord_type != 0)
14927 ERRMSG("Only lat/lon grid supported");
14928
14929 static FILE *out;
14930
14931 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
14932 kw[EP];
14933
14934 static int nobs, nk;
14935
14936 /* Set timer... */
14937 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT");
14938
14939 /* Init... */
14940 if (t == ctl->t_start) {
14941
14942 /* Allocate... */
14943 ALLOC(rt, double,
14944 NOBS);
14945 ALLOC(rz, double,
14946 NOBS);
14947 ALLOC(rlon, double,
14948 NOBS);
14949 ALLOC(rlat, double,
14950 NOBS);
14951 ALLOC(robs, double,
14952 NOBS);
14953
14954 /* Read observation data... */
14955 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
14956
14957 /* Read kernel data... */
14958 if (ctl->sample_kernel[0] != '-')
14959 read_kernel(ctl->sample_kernel, kz, kw, &nk);
14960
14961 /* Create output file... */
14962 LOG(1, "Write sample data: %s", filename);
14963 if (!(out = fopen(filename, "w")))
14964 ERRMSG("Cannot create file!");
14965
14966 /* Write header... */
14967 fprintf(out,
14968 "# $1 = time [s]\n"
14969 "# $2 = altitude [km]\n"
14970 "# $3 = longitude [deg]\n"
14971 "# $4 = latitude [deg]\n"
14972 "# $5 = surface area [km^2]\n"
14973 "# $6 = layer depth [km]\n"
14974 "# $7 = number of particles [1]\n"
14975 "# $8 = column density [kg/m^2]\n"
14976 "# $9 = volume mixing ratio [ppv]\n"
14977 "# $10 = observed BT index [K]\n\n");
14978
14979 /* Set latitude range, squared radius, and area... */
14980 dlat = DY2DEG(ctl->sample_dx);
14981 rmax2 = SQR(ctl->sample_dx);
14982 area = M_PI * rmax2;
14983 }
14984
14985 /* Set time interval for output... */
14986 const double t0 = t - 0.5 * ctl->dt_mod;
14987 const double t1 = t + 0.5 * ctl->dt_mod;
14988
14989 /* Loop over observations... */
14990 for (int i = 0; i < nobs; i++) {
14991
14992 /* Check time... */
14993 if (rt[i] < t0)
14994 continue;
14995 else if (rt[i] >= t1)
14996 break;
14997
14998 /* Calculate Cartesian coordinates... */
14999 double x0[3];
15000 geo2cart(0, rlon[i], rlat[i], x0);
15001
15002 /* Set pressure range... */
15003 const double rp = P(rz[i]);
15004 const double ptop = P(rz[i] + ctl->sample_dz);
15005 const double pbot = P(rz[i] - ctl->sample_dz);
15006
15007 /* Init... */
15008 double mass = 0;
15009 int np = 0;
15010
15011 /* Loop over air parcels... */
15012 //#pragma omp parallel for default(shared) reduction(+:mass,np)
15013 for (int ip = 0; ip < atm->np; ip++) {
15014
15015 /* Check time... */
15016 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15017 continue;
15018
15019 /* Check latitude... */
15020 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
15021 continue;
15022
15023 /* Check horizontal distance... */
15024 double x1[3];
15025 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
15026 if (DIST2(x0, x1) > rmax2)
15027 continue;
15028
15029 /* Check pressure... */
15030 if (ctl->sample_dz > 0)
15031 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
15032 continue;
15033
15034 /* Add mass... */
15035 if (ctl->qnt_m >= 0)
15036 mass +=
15037 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
15038 np++;
15039 }
15040
15041 /* Calculate column density... */
15042 const double cd = mass / (1e6 * area);
15043
15044 /* Calculate volume mixing ratio... */
15045 double vmr = 0;
15046 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
15047 if (mass > 0) {
15048
15049 /* Get temperature... */
15050 double temp;
15052 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
15053 rlon[i], rlat[i], &temp, ci, cw, 1);
15054
15055 /* Calculate volume mixing ratio... */
15056 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
15057 }
15058 } else
15059 vmr = NAN;
15060
15061 /* Write output... */
15062 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
15063 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
15064 }
15065
15066 /* Finalize...... */
15067 if (t == ctl->t_stop) {
15068
15069 /* Close output file... */
15070 fclose(out);
15071
15072 /* Free... */
15073 free(rt);
15074 free(rz);
15075 free(rlon);
15076 free(rlat);
15077 free(robs);
15078 }
15079}
15080
15081/*****************************************************************************/
15082
15084 const char *filename,
15085 const ctl_t *ctl,
15086 atm_t *atm,
15087 const double t) {
15088
15089 if (ctl->met_coord_type != 0)
15090 ERRMSG("Only lat/lon grid supported");
15091
15092 static FILE *out;
15093
15094 static double rmax2, x0[3], x1[3];
15095
15096 /* Set timer... */
15097 SELECT_TIMER("WRITE_STATION", "OUTPUT");
15098
15099 /* Init... */
15100 if (t == ctl->t_start) {
15101
15102 /* Write info... */
15103 LOG(1, "Write station data: %s", filename);
15104
15105 /* Create new file... */
15106 if (!(out = fopen(filename, "w")))
15107 ERRMSG("Cannot create file!");
15108
15109 /* Write header... */
15110 fprintf(out,
15111 "# $1 = time [s]\n"
15112 "# $2 = altitude [km]\n"
15113 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
15114 for (int iq = 0; iq < ctl->nq; iq++)
15115 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
15116 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
15117 fprintf(out, "\n");
15118
15119 /* Set geolocation and search radius... */
15120 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
15121 rmax2 = SQR(ctl->stat_r);
15122 }
15123
15124 /* Set time interval for output... */
15125 const double t0 = t - 0.5 * ctl->dt_mod;
15126 const double t1 = t + 0.5 * ctl->dt_mod;
15127
15128 /* Loop over air parcels... */
15129 for (int ip = 0; ip < atm->np; ip++) {
15130
15131 /* Check time... */
15132 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15133 continue;
15134
15135 /* Check time range for station output... */
15136 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
15137 continue;
15138
15139 /* Check station flag... */
15140 if (ctl->qnt_stat >= 0)
15141 if ((int) atm->q[ctl->qnt_stat][ip])
15142 continue;
15143
15144 /* Get Cartesian coordinates... */
15145 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
15146
15147 /* Check horizontal distance... */
15148 if (DIST2(x0, x1) > rmax2)
15149 continue;
15150
15151 /* Set station flag... */
15152 if (ctl->qnt_stat >= 0)
15153 atm->q[ctl->qnt_stat][ip] = 1;
15154
15155 /* Write data... */
15156 fprintf(out, "%.2f %g %g %g",
15157 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
15158 for (int iq = 0; iq < ctl->nq; iq++) {
15159 fprintf(out, " ");
15160 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
15161 }
15162 fprintf(out, "\n");
15163 }
15164
15165 /* Close file... */
15166 if (t == ctl->t_stop)
15167 fclose(out);
15168}
15169
15170/*****************************************************************************/
15171
15173 const char *filename,
15174 const ctl_t *ctl,
15175 const atm_t *atm,
15176 const double t) {
15177
15178 if (ctl->met_coord_type != 0)
15179 ERRMSG("Only lat/lon grid supported");
15180
15181 FILE *out;
15182
15183 /* Set timer... */
15184 SELECT_TIMER("WRITE_VTK", "OUTPUT");
15185
15186 /* Write info... */
15187 LOG(1, "Write VTK data: %s", filename);
15188
15189 /* Set time interval for output... */
15190 const double t0 = t - 0.5 * ctl->dt_mod;
15191 const double t1 = t + 0.5 * ctl->dt_mod;
15192
15193 /* Create file... */
15194 if (!(out = fopen(filename, "w")))
15195 ERRMSG("Cannot create file!");
15196
15197 /* Count data points... */
15198 int np = 0;
15199 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15200 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15201 continue;
15202 np++;
15203 }
15204
15205 /* Write header... */
15206 fprintf(out,
15207 "# vtk DataFile Version 3.0\n"
15208 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
15209
15210 /* Write point coordinates... */
15211 fprintf(out, "POINTS %d float\n", np);
15212 if (ctl->vtk_sphere) {
15213 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15214 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15215 continue;
15216 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
15217 + ctl->vtk_offset) / RE;
15218 const double coslat = cos(DEG2RAD(atm->lat[ip]));
15219 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
15220 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
15221 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
15222 fprintf(out, "%g %g %g\n", x, y, z);
15223 }
15224 } else
15225 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15226 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15227 continue;
15228 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
15229 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
15230 }
15231
15232 /* Write point data... */
15233 fprintf(out, "POINT_DATA %d\n", np);
15234 for (int iq = 0; iq < ctl->nq; iq++) {
15235 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
15236 ctl->qnt_name[iq]);
15237 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
15238 if (atm->time[ip] < t0 || atm->time[ip] > t1)
15239 continue;
15240 fprintf(out, "%g\n", atm->q[iq][ip]);
15241 }
15242 }
15243
15244 /* Close file... */
15245 fclose(out);
15246}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:9510
void write_depo(const char *filename, const ctl_t *ctl, const depo_t *depo, const double t)
Convert cumulative ground inventories to Bq m^-2 and write them.
Definition: mptrac.c:13575
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:8117
void day2doy(const int year, const int mon, const int day, int *doy)
Get day of year from date.
Definition: mptrac.c:1898
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:9470
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:12978
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:10160
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:14622
void dd_read_met_nc_grid(dd_t *dd, const ctl_t *ctl, met_t *met, const int ncid)
Read meteorological grid information and construct the domain-decomposed grid with halo regions.
Definition: mptrac.c:11401
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:11986
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:12333
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:3598
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:5999
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:5062
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:8574
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:9306
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:4227
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:12506
double cos_sza(const double sec, const double lon, const double lat)
Calculates the cosine of the solar zenith angle.
Definition: mptrac.c:1857
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:3048
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:10482
void compress_log_levels_3d(FILE *out, const char *codec, const char *varname, const met_t *met, const float *org_all, const float *cmp_all, const size_t nxy, const size_t nz, const double ratio, const double bpv, const double t_comp, const double t_decomp, const size_t nbytes)
Write per-level compression diagnostics for a full 3-D field.
Definition: mptrac.c:765
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:8541
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:11577
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:9363
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:12159
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:12377
void write_depo_asc(const char *filename, const ctl_t *ctl, const double *data, const double t, const double *lon, const double *lat, const double *area)
Write radioactive deposition densities as a gnuplot-compatible table.
Definition: mptrac.c:13646
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:4058
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:3559
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:9963
void compress_pck(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3‑D float array using the PCK format.
Definition: mptrac.c:986
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:11273
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:8693
void intpol_check_cartesian(const double *lons, const int nlon, const double *lats, const int nlat, const double lon, const double lat, double *lon2, double *lat2)
Clamps UTM coordinates to the valid bounds.
Definition: mptrac.c:2782
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:11714
int compress_metvar_index(const char *varname)
Maps a meteorological variable name to its internal MPTRAC variable index.
Definition: mptrac.c:969
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:6046
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:13475
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:5169
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:414
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:5249
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:8665
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:11231
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:213
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:12405
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:9047
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:3495
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:4886
void mptrac_free(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, depo_t *depo, dd_t *dd)
Frees memory resources allocated for MPTRAC.
Definition: mptrac.c:6377
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:3342
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:13954
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:8005
void mptrac_write_output(const char *dirname, const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, depo_t *depo, const double t)
Writes various types of output data to files in a specified directory.
Definition: mptrac.c:8230
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:12607
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:3112
void get_met_filename(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:2619
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:2562
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:6155
int compress_read_lossy_scale(FILE *in, const size_t nz, double **off, double **scl)
Read optional lossyscaling metadata for a 3-D field.
Definition: mptrac.c:874
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:8334
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:12539
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:3885
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:156
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:8747
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:5859
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:11358
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:12638
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:12774
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:2985
void module_sort(const ctl_t *ctl, const met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:5887
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:4102
void compress_scale_to_unit(float *array, const size_t nxy, const size_t nz, double *off, double *scl)
Scales each vertical level of a 3-D field independently to the interval [0,1].
Definition: mptrac.c:811
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:8846
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:3789
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:12434
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:3762
void module_radio_decay(const ctl_t *ctl, const cache_t *cache, atm_t *atm)
Apply radioactive decay to atmospheric tracer species.
Definition: mptrac.c:5493
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:6438
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:5961
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:12586
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:3174
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:9076
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:3525
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:14683
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:6663
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:14440
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:5723
void mptrac_init(ctl_t *ctl, cache_t *cache, clim_t *clim, atm_t *atm, depo_t *depo, const int ntask)
Initializes the MPTRAC model and its associated components.
Definition: mptrac.c:6563
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:6588
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:8061
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 write_met_bin_3d(FILE *out, const ctl_t *ctl, met_t *met, float var[EX][EY][EP], const char *varname, const int metvar, FILE *level_log)
Writes a 3-dimensional meteorological variable to a binary file.
Definition: mptrac.c:14347
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:11957
void mptrac_alloc(ctl_t **ctl, cache_t **cache, clim_t **clim, met_t **met0, met_t **met1, atm_t **atm, depo_t **depo, dd_t **dd)
Allocates and initializes memory resources for MPTRAC.
Definition: mptrac.c:6294
void compress_write_lossy_scale(FILE *out, const int enabled, float *array, const size_t nxy, const size_t nz, double **off, double **scl)
Write optional lossyscaling metadata for a 3-D field.
Definition: mptrac.c:909
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:9825
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:241
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:5754
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:15083
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
double time_from_filename(const char *filename, const int offset, const int with_seconds)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:12706
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:2532
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:2808
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:3141
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:5435
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:124
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:3578
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:14318
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:11837
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:8422
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:4266
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:396
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:3265
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:8887
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:12922
void get_met_replace(char *orig, const char *search, const char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:2688
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:4588
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:8478
void write_depo_nc(const char *filename, const ctl_t *ctl, const double *data, const double t, const double *lon, const double *lat, const double *area)
Write radioactive deposition densities as a CF-style netCDF file.
Definition: mptrac.c:13686
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:7742
void mptrac_run_timestep(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t **met0, met_t **met1, atm_t *atm, depo_t *depo, double t, dd_t *dd)
Executes a single timestep of the MPTRAC model simulation.
Definition: mptrac.c:7851
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:15172
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:6077
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:6723
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:11775
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:4801
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:14058
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:8358
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:4343
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:14652
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:4956
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:5351
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:2601
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:9638
void get_tropo(const int met_tropo, ctl_t *ctl, const 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:2712
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:3298
void compress_log_level(FILE *out, const char *codec, const char *varname, const size_t lev, const double plev, const double ratio, const double bpv, const double t_comp, const double t_decomp, const size_t n, const size_t nbytes, const float *org, const float *cmp)
Write one row of per-level compression diagnostics.
Definition: mptrac.c:666
void compress_unscale_from_unit(float *array, const size_t nxy, const size_t nz, const double *off, const double *scl)
Restores a levelwise [0,1]-scaled 3-D field to physical units.
Definition: mptrac.c:854
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:8380
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:2755
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:14918
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:13752
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:4738
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:14188
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:12872
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:9186
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:8181
double tropo_weight(const ctl_t *ctl, const clim_t *clim, const atm_t *atm, const int ip)
Computes a weighting factor based on tropopause pressure.
Definition: mptrac.c:12748
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:3324
void module_radio_depo(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm, depo_t *depo)
Deposit supported radionuclides from air parcels onto the ground grid.
Definition: mptrac.c:5551
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:13188
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:13139
MPTRAC library declarations.
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1727
void dd_init(const ctl_t *ctl, dd_t *dd, atm_t *atm)
Initialize the domain decomposition infrastructure.
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:559
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:315
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:2199
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:709
#define SO2_DISS_K2_TEMP
Temperature dependence of the second SO2 dissociation constant [K].
Definition: mptrac.h:445
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1754
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:290
#define RADIO_HALF_LIFE_CS137
Half-life of Cs-137 [s].
Definition: mptrac.h:480
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:250
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:285
#define SO2_CORR_B
Exponent of the high-SO2 correction [1].
Definition: mptrac.h:385
#define COMPRESS_BPV(n, stored_size)
Calculate bits per value from stored size and element count.
Definition: mptrac.h:795
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:295
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:564
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:584
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:1159
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1859
#define H0
Scale height [km].
Definition: mptrac.h:270
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1707
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1494
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:1332
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1508
#define RADIO_DRY_VDEP_I131
Dry deposition velocity of aerosol-bound I-131 [m/s].
Definition: mptrac.h:510
#define SELECT_TIMER(id, group)
Select and start a timer with specific attributes.
Definition: mptrac.h:2480
#define RADIO_DRY_VDEP_CS137
Dry deposition velocity of Cs-137 [m/s].
Definition: mptrac.h:505
#define SO2_DISS_K1_REF
First SO2 dissociation constant at CHEM_REF_TEMP [mol/L].
Definition: mptrac.h:430
#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:1094
void compress_zfp(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3D array of floats using the ZFP library.
#define SO2_DISS_K1_TEMP
Temperature dependence of the first SO2 dissociation constant [K].
Definition: mptrac.h:435
#define DOTP(a, b)
Calculate the dot product of two vectors.
Definition: mptrac.h:1036
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:310
int dd_calc_subdomain_from_coords(const ctl_t *ctl, const dd_t *dd, const double lon, const double lat)
Determine MPI subdomain from particle coordinates.
#define DD_EY_GLOB
Maximum number of latitudes of global meteo data.
Definition: mptrac.h:634
#define KARMAN
Karman's constant.
Definition: mptrac.h:280
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:1174
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:1479
#define O1D_RATE_CFC12_B
O(1D) reaction temperature parameter for CFC-12 [K].
Definition: mptrac.h:415
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2406
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1668
#define O1D_RATE_N2O_A
O(1D) reaction pre-factor for N2O [cm^3/s].
Definition: mptrac.h:420
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:554
#define RADIO_DRY_VDEP_PB210
Dry deposition velocity of Pb-210 [m/s].
Definition: mptrac.h:495
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:2024
void compress_sz3(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3-D float array using the SZ3 library.
#define H2O2_HENRY_TEMP
Temperature dependence of the H2O2 Henry constant [K].
Definition: mptrac.h:375
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:1205
#define CLAMP(v, lo, hi)
Clamp a value to a specified range.
Definition: mptrac.h:756
#define M_AIR_MOLECULE
Mean mass of an air molecule [kg].
Definition: mptrac.h:340
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:589
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:594
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:690
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:2243
#define codes_handle
Placeholder when ECCODES is not available.
Definition: mptrac.h:241
void compress_zstd(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a float array using ZSTD.
#define SO2_CORR_A
Scale factor of the high-SO2 correction [1].
Definition: mptrac.h:380
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1784
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:275
#define RADIO_HALF_LIFE_I131
Half-life of I-131 [s].
Definition: mptrac.h:485
#define RADIO_HALF_LIFE_BE7
Half-life of Be-7 [s].
Definition: mptrac.h:475
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:265
void compress_cms(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a 3-D meteorological field using cmultiscale.
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:609
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:574
void dd_assign_subdomains(const ctl_t *ctl, const dd_t *dd, atm_t *atm, const int init)
Assign or update particle subdomain ownership.
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:1139
#define H2O2_SO2_RATE_REF
Reference rate for aqueous H2O2-SO2 chemistry [L^2/(mol^2 s)].
Definition: mptrac.h:350
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:904
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:840
#define O1D_RATE_CFC12_A
O(1D) reaction pre-factor for CFC-12 [cm^3/s].
Definition: mptrac.h:410
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:549
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:260
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1832
#define O1D_RATE_N2O_B
O(1D) reaction temperature parameter for N2O [K].
Definition: mptrac.h:425
#define DX2COORD(met, dx, lat)
Convert a distance in meters to a coordinate value based on grid type.
Definition: mptrac.h:966
#define O1D_RATE_CCL4_B
O(1D) reaction temperature parameter for CCl4 [K].
Definition: mptrac.h:395
#define COMPRESS_RATIO(raw_size, stored_size)
Calculate the compression ratio from raw and stored byte counts.
Definition: mptrac.h:783
#define WET_DEPO_T_ICE
Lower temperature of the ice-cloud retention transition [K].
Definition: mptrac.h:455
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:2124
void dd_normalize_lon_lat(const dd_t *dd, double *lon, double *lat)
Normalize geographic coordinates to the global grid convention.
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:320
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 RADIO_WET_COEFF_BE7
Wet deposition coefficient of Be-7 [s^-1].
Definition: mptrac.h:520
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:2003
void dd_sort(const ctl_t *ctl, const met_t *met0, atm_t *atm, dd_t *dd, int *npart)
Sort local atmospheric particles and determine export counts for domain decomposition.
void dd_particles2atm(const ctl_t *ctl, cache_t *cache, const particle_t *particles, const int npart, atm_t *atm)
Copy received particles from the communication buffer into the atmospheric state.
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:2100
void compress_lz4(const ctl_t *ctl, const met_t *met, const char *varname, float *array, const int decompress, FILE *level_log, FILE *inout)
Compresses or decompresses a float array using LZ4.
#define O1D_RATE_CFC11_A
O(1D) reaction pre-factor for CFC-11 [cm^3/s].
Definition: mptrac.h:400
#define RADIO_WET_COEFF_CS137
Wet deposition coefficient of Cs-137 [s^-1].
Definition: mptrac.h:525
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:2174
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:2274
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:2153
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:941
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:2373
#define H2O2_SO2_RATE_TEMP
Temperature parameter for the aqueous H2O2-SO2 rate [K].
Definition: mptrac.h:355
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:2293
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1936
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:1278
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:667
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:1980
#define O1D_RATE_CCL4_A
O(1D) reaction pre-factor for CCl4 [cm^3/s].
Definition: mptrac.h:390
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:624
#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:1069
#define OMEGA_EARTH
Angular velocity of Earth [s^-1].
Definition: mptrac.h:330
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:857
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:300
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:2037
#define RADIO_WET_COEFF_I131
Wet deposition coefficient of aerosol-bound I-131 [s^-1].
Definition: mptrac.h:530
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1876
#define RADIO_DRY_VDEP_BE7
Dry deposition velocity of Be-7 [m/s].
Definition: mptrac.h:500
void dd_atm2particles(const ctl_t *ctl, cache_t *cache, atm_t *atm, particle_t *particles, const int npart)
Copy migratable atmospheric particles from the ATM state into a particle buffer.
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:569
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2450
#define COMPRESS_SPEED(nbytes, dt)
Calculate compression throughput in MiB/s.
Definition: mptrac.h:771
void dd_communicate_particles(const ctl_t *ctl, const dd_t *dd, particle_t **particles, int *npart, int *capacity)
Exchange particles between MPI ranks according to their destination rank.
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:1188
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1906
#define H2O2_HENRY_REF
Henry constant of H2O2 at CHEM_REF_TEMP [mol/(L atm)].
Definition: mptrac.h:370
#define CHEM_REF_TEMP
Reference temperature for chemical equilibrium constants [K].
Definition: mptrac.h:345
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1645
#define DD_EX_GLOB
Maximum number of longitudes of global meteo data.
Definition: mptrac.h:629
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:599
void dd_sort_help(double *a, dd_t *dd, const int np)
Apply the sorting permutation to a particle data array.
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:2336
#define RADIO_HALF_LIFE_RN222
Half-life of Rn-222 [s].
Definition: mptrac.h:465
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1537
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:2075
#define KAPPA
Exponent used for potential-temperature calculations [1].
Definition: mptrac.h:325
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:734
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:579
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1567
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:544
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1808
#define SO2_DISS_K2_REF
Second SO2 dissociation constant at CHEM_REF_TEMP [mol/L].
Definition: mptrac.h:440
#define SO2_HENRY_REF
Henry constant of SO2 at CHEM_REF_TEMP [mol/(L atm)].
Definition: mptrac.h:360
#define SO2_HENRY_TEMP
Temperature dependence of the SO2 Henry constant [K].
Definition: mptrac.h:365
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1961
#define RADIO_HALF_LIFE_PB210
Half-life of Pb-210 [s].
Definition: mptrac.h:470
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:604
void read_met_grib_grid(codes_handle **handles, int count_handles, met_t *met)
Reads global meteorological information from a grib file.
void module_dd(double t, const ctl_t *ctl, cache_t *cache, dd_t *dd, atm_t *atm, met_t **met)
Perform domain decomposition and exchange particles between MPI ranks.
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1621
#define ECC(cmd)
Execute an ECCODES command and check for errors.
Definition: mptrac.h:1050
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:1351
#define WET_DEPO_T_LIQUID
Upper temperature of the ice-cloud retention transition [K].
Definition: mptrac.h:450
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:1020
#define NC_INQ_DIM(dimname, ptr, min, max, check)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1597
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:819
#define DY2COORD(met, dy)
Convert a distance to coordinate value based on grid type.
Definition: mptrac.h:989
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:255
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:614
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:922
#define O1D_RATE_CFC11_B
O(1D) reaction temperature parameter for CFC-11 [K].
Definition: mptrac.h:405
void dd_push(const ctl_t *ctl, atm_t *atm, cache_t *cache, int *npart)
Compact and stage non-local particles for domain decomposition transfer.
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1378
#define WET_DEPO_T_LIQUID_BC
Temperature threshold for below-cloud retention [K].
Definition: mptrac.h:460
#define RADIO_HALF_LIFE_XE133
Half-life of Xe-133 [s].
Definition: mptrac.h:490
#define RADIO_WET_COEFF_PB210
Wet deposition coefficient of Pb-210 [s^-1].
Definition: mptrac.h:515
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:1121
#define DOBSON_UNIT
Ozone column mass corresponding to one Dobson unit [kg/m^2].
Definition: mptrac.h:335
Air parcel data.
Definition: mptrac.h:3563
double time[NP]
Time [s].
Definition: mptrac.h:3569
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3578
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3575
int np
Number of air parcels.
Definition: mptrac.h:3566
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3581
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3572
Cache data structure.
Definition: mptrac.h:3618
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3639
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3627
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3630
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3624
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3636
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3633
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3621
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3677
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3683
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3692
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3713
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3689
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3707
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3710
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3704
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3698
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3719
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3722
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3701
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3716
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3695
int np
Number of pressure levels.
Definition: mptrac.h:3680
int no3c
Number of total ozone columns.
Definition: mptrac.h:3686
Climatological data.
Definition: mptrac.h:3785
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3827
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3803
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3815
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3806
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3788
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3833
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3821
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3824
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3818
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3797
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3812
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3791
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3809
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3800
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3794
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3830
Climatological data in the form of time series.
Definition: mptrac.h:3733
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3742
double time[CTS]
Time [s].
Definition: mptrac.h:3739
int ntime
Number of timesteps.
Definition: mptrac.h:3736
Climatological data in the form of zonal means.
Definition: mptrac.h:3753
double time[CT]
Time [s].
Definition: mptrac.h:3765
int np
Number of pressure levels.
Definition: mptrac.h:3762
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3771
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3774
int ntime
Number of timesteps.
Definition: mptrac.h:3756
int nlat
Number of latitudes.
Definition: mptrac.h:3759
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3768
Control parameters.
Definition: mptrac.h:2494
double met_utm_ref_lon
Reference longitude [deg] for UTM grid.
Definition: mptrac.h:2853
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3424
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2606
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3385
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3352
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2762
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:3264
int qnt_target_subdomain
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2819
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2870
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2639
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3361
double molmass
Molar mass [g/mol].
Definition: mptrac.h:3120
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2585
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2786
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3548
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:3313
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:3183
int met_zstd_nworkers
ZSTD number of worker threads (0=single-threaded, default=4).
Definition: mptrac.h:2882
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:3207
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2513
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2525
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2795
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2534
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2618
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3355
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2627
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:3159
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:3108
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3376
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2594
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3502
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:3168
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:3013
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:3180
double stat_r
Search radius around station [km].
Definition: mptrac.h:3508
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:3258
int met_zstd_level
ZSTD compression level (from -5 to 22, default=-3).
Definition: mptrac.h:2879
double met_utm_ref_lat
Reference latitude [deg] for UTM grid.
Definition: mptrac.h:2850
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3379
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3532
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:3204
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2981
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2615
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:3222
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:3072
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2774
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2693
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3451
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3427
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2822
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:3020
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2780
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2933
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:3000
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2657
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2729
char species[LEN]
Species.
Definition: mptrac.h:3117
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3370
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3382
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:3051
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2978
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2609
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:3060
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3412
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3430
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3326
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:3081
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3442
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2540
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2684
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2636
int qnt_Acs137
Quantity array index for radioactive activity of Cs-137.
Definition: mptrac.h:2807
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3433
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2663
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2997
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3487
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2723
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2841
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:3141
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:3225
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2969
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3403
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:3045
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2528
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2561
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2705
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:3096
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3514
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3346
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:3042
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3448
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3373
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2567
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:3231
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3418
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2690
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:3213
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:3114
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2675
int radio_decay
RADIO_DECAY switch for airborne and deposited activity (0=off, 1=on, default: 0).
Definition: mptrac.h:3249
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2966
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2939
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2537
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:3030
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3454
int met_pck_zstd
Apply an additional ZSTD compression step to PCK payloads (0=off, 1=on).
Definition: mptrac.h:2888
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:3017
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:3102
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2543
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3457
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3349
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2975
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3358
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2936
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:3216
double depo_dt_out
DEPO_DT_OUT time interval for radioactive deposition output [s] (default: 86400).
Definition: mptrac.h:3304
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:3057
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3400
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3460
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2600
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:3087
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2991
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3466
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2522
double dd_sort_dt
Sorting time interval for the compactification.
Definition: mptrac.h:3551
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2988
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2531
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:3006
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:3171
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2732
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2660
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3367
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3511
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:3234
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3539
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:3144
int qnt_eta
Quantity array index for eta vertical coordinate.
Definition: mptrac.h:2717
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:3129
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:3276
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:3177
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2681
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3331
int met_cms_nd0x
cmultiscale number of cells of coarsest grid in x-direction.
Definition: mptrac.h:2915
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2957
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:3243
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3343
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:3285
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2558
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2549
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2759
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3520
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2828
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:3078
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3490
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2651
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3397
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2867
char met_comp_logfile[LEN]
Filename for per-level compression diagnostics ("-" disables output).
Definition: mptrac.h:2906
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2579
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2699
int met_gp2z
Convert surface geopotential to geopotential height (0=no, 1=yes).
Definition: mptrac.h:2860
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:3093
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2984
int met_dx
Stride for longitudes.
Definition: mptrac.h:2927
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:3192
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2844
char depo_basename[LEN]
DEPO_BASENAME for radioactive deposition files (default: disabled with "-").
Definition: mptrac.h:3301
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2711
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:3138
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:3246
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2831
int diffusion
Diffusion switch (0=off, 1=on).
Definition: mptrac.h:3033
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2747
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2720
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2741
int turb_pbl_scheme
PBL turbulence scheme (0=none, 1=closure).
Definition: mptrac.h:3036
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2582
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3529
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2597
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2678
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:3090
double met_zfp_tol[METVAR]
ZFP compression tolerance.
Definition: mptrac.h:2894
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:3003
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2654
int met_sz3_prec[METVAR]
SZ3 compression precision.
Definition: mptrac.h:2897
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2510
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2765
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2954
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:3228
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2603
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3475
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2702
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2591
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3496
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:3126
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3340
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3415
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2546
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3436
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2789
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2783
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2504
int depo_type
DEPO_TYPE of deposition files (0=ASCII, 1=netCDF, default: 0).
Definition: mptrac.h:3307
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:3310
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:3195
int nens
Number of ensembles.
Definition: mptrac.h:3388
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2570
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2630
int advect
Advection scheme (1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:3023
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3463
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2960
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2588
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3319
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:3240
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2708
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL pressure thickness).
Definition: mptrac.h:3069
int met_lz4_accel
LZ4 acceleration factor (>=1, default=8).
Definition: mptrac.h:2885
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3391
int qnt_Ai131
Quantity array index for radioactive activity of I-131.
Definition: mptrac.h:2810
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:3255
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:2857
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3364
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2726
int qnt_Apb210
Quantity array index for radioactive activity of Pb-210.
Definition: mptrac.h:2801
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3505
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2768
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3273
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3439
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2792
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2753
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2945
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:3066
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2838
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:3105
double met_cms_eps[METVAR]
cmultiscale compression epsilon.
Definition: mptrac.h:2924
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:3201
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2642
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2714
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:3084
int met_cms_nd0y
cmultiscale number of cells of coarsest grid in y-direction.
Definition: mptrac.h:2918
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:3174
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2648
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:3099
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:3186
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:3150
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2756
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2744
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3421
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:3135
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2555
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3394
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3484
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3322
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2972
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:3198
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:3316
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:3162
int met_lossy_scale[METVAR]
Apply levelwise [0,1] scaling before lossy compression (0=off, 1=on).
Definition: mptrac.h:2903
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3481
int qnt_current_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2816
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2909
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:3291
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2942
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3469
int qnt_Axe133
Quantity array index for radioactive activity of Xe-133.
Definition: mptrac.h:2813
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:3210
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2624
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2672
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2687
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2963
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3478
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2645
double turb_pbl_trans
Depth of turbulent PBL transition layer (fraction of PBL pressure thickness).
Definition: mptrac.h:3063
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:3294
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3472
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2876
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:3237
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2777
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3337
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:3282
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:3219
int qnt_Abe7
Quantity array index for radioactive activity of Be-7.
Definition: mptrac.h:2804
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:3153
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2912
int met_cms_maxlev
cmultiscale maximum refinement level.
Definition: mptrac.h:2921
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3409
double met_sz3_tol[METVAR]
SZ3 compression tolerance.
Definition: mptrac.h:2900
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3517
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:3288
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2573
int met_np
Number of target pressure levels.
Definition: mptrac.h:2948
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2519
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2873
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:3165
int qnt_Arn222
Quantity array index for radioactive activity of Rn-222.
Definition: mptrac.h:2798
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2669
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3526
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:3156
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3270
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:3039
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:3075
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2735
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev,...
Definition: mptrac.h:3027
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2666
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2771
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2564
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:3189
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3334
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:3132
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:3279
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2696
int met_coord_type
Type of coordinates for meteo data (-1=detect, 0=lat/lon [deg], 1=UTM [m]).
Definition: mptrac.h:2847
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2552
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:3267
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:3261
int met_dy
Stride for latitudes.
Definition: mptrac.h:2930
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2750
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:3054
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:3111
int radio_depo
RADIO_DEPO switch for radionuclide deposition (0=off, 1=on, default: 0).
Definition: mptrac.h:3252
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3542
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2516
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2994
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2612
double t_start
Start time of simulation [s].
Definition: mptrac.h:2825
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2507
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2951
int nq
Number of quantities.
Definition: mptrac.h:2501
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:3123
int met_zfp_prec[METVAR]
ZFP compression precision.
Definition: mptrac.h:2891
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3493
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3523
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3499
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:3048
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3445
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3545
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2576
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:2864
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2621
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2633
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3406
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2738
Domain decomposition data structure.
Definition: mptrac.h:4021
size_t halo_bnd_count[4]
Extent of the periodic boundary halo hyperslab.
Definition: mptrac.h:4053
int halo_offset_end
Offset of the periodic halo block at the end of the local x-array.
Definition: mptrac.h:4059
int nx_glob
Number of global longitudes.
Definition: mptrac.h:4028
size_t halo_bnd_start[4]
Start indices of the periodic boundary halo hyperslab.
Definition: mptrac.h:4050
double lon_glob[DD_EX_GLOB]
Longitudes of the global grid [deg].
Definition: mptrac.h:4034
double lat_glob[DD_EY_GLOB]
Latitudes of the global grid [deg].
Definition: mptrac.h:4037
int halo_offset_start
Offset of the periodic halo block at the beginning of the local x-array.
Definition: mptrac.h:4056
size_t subdomain_count[4]
Extent of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:4047
int ny_glob
Number of global latitudes.
Definition: mptrac.h:4031
size_t subdomain_start[4]
Start indices of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:4044
Ground inventories of deposited radionuclides.
Definition: mptrac.h:3654
double Ai131[EX *EY]
Deposited I-131 activity [Bq].
Definition: mptrac.h:3666
double Abe7[EX *EY]
Deposited Be-7 activity [Bq].
Definition: mptrac.h:3660
double Acs137[EX *EY]
Deposited Cs-137 activity [Bq].
Definition: mptrac.h:3663
double Apb210[EX *EY]
Deposited Pb-210 activity [Bq].
Definition: mptrac.h:3657
Meteo data structure.
Definition: mptrac.h:3844
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3925
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3913
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3985
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3955
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:4012
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3976
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3949
int coord_type
Definition: mptrac.h:3850
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3970
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3931
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3874
int nx
Number of longitudes.
Definition: mptrac.h:3853
int ny
Number of latitudes.
Definition: mptrac.h:3856
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3907
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3886
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3982
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3895
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:4006
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:4003
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3892
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3979
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3994
int np
Number of pressure levels.
Definition: mptrac.h:3859
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3961
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3889
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3964
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3901
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:4000
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3934
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3946
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3952
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3940
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3865
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3919
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3922
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3916
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3898
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3958
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3967
int npl
Number of model levels.
Definition: mptrac.h:3862
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3910
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3988
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3928
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3973
double eta[EP]
Model level eta values.
Definition: mptrac.h:3883
double time
Time [s].
Definition: mptrac.h:3847
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3937
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3904
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3997
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3943
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3877
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3868
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3991
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3880
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:4009
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3871
Particle data.
Definition: mptrac.h:3592
double p
Pressure [hPa].
Definition: mptrac.h:3598
double lat
Latitude [deg].
Definition: mptrac.h:3604
double time
Time [s].
Definition: mptrac.h:3595
double lon
Longitude [deg].
Definition: mptrac.h:3601
double q[NQ]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3607