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
481 /* Get meteo variable... */
482 const int metvar = compress_metvar_index(varname);
483
484 /* Set lon-lat grid... */
485 const size_t nxy = nx * ny;
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 rho[EP], mean_err[EP], stddev_err[EP], min_err[EP], max_err[EP];
554 double mean_org[EP], range_org[EP], nrmse[EP];
555 double ratio[EP], bpv[EP];
556
557 /* Loop over batches... */
558 const size_t dip = (ctl->met_cms_batch <= 0
559 ? (size_t) omp_get_max_threads()
560 : (size_t) ctl->met_cms_batch);
561 for (size_t ip0 = 0; ip0 < np; ip0 += dip) {
562
563 /* Measure time... */
564 double t0 = omp_get_wtime();
565
566 /* Loop over levels... */
567#pragma omp parallel for default(shared)
568 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
569
570 /* Allocate... */
571 float *tmp_arr;
572 ALLOC(tmp_arr, float,
573 nxy);
574
575 /* Copy level data... */
576 for (size_t ix = 0; ix < nx; ++ix)
577 for (size_t iy = 0; iy < ny; ++iy)
578 tmp_arr[ARRAY_2D(ix, iy, ny)] =
579 array[ARRAY_3D(ix, iy, ny, ip, np)];
580
581 /* Initialize current level... */
582 cms_ptr[ip] = cms_init(cms_param);
583
584 /* Coarsening... */
585 cms_sol[ip] =
586 cms_read_arr_new(cms_ptr[ip], tmp_arr, lon, lat,
587 nx, ny, ctl->met_cms_eps[metvar]);
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 += (omp_get_wtime() - t0);
623
624 /* Write per-level diagnostics... */
625 if (level_log) {
626 ratio[ip] = cms_compression_rate(cms_ptr[ip], cms_sol[ip]);
627 bpv[ip] = 32. / ratio[ip];
628 compress_error_stats(tmp_org, tmp_cms, nxy, &mean_err[ip],
629 &stddev_err[ip], &min_err[ip], &max_err[ip],
630 &nrmse[ip], &mean_org[ip], &range_org[ip]);
631 rho[ip] = gsl_stats_float_correlation(tmp_org, 1, tmp_cms, 1, nxy);
632 }
633
634 /* Calculate harmonic mean of compression rates... */
635 cr += 1.0 / cms_compression_rate(cms_ptr[ip], cms_sol[ip]);
636
637 /* Save binary data... */
638 if (ctl->met_cms_zstd == 1)
639 cms_save_zstd_sol(cms_sol[ip], inout, 3);
640 else
641 cms_save_sol(cms_sol[ip], inout);
642
643 /* Free... */
644 cms_delete_sol(cms_sol[ip]);
645 cms_delete_module(cms_ptr[ip]);
646 free(tmp_cms);
647 free(tmp_org);
648 }
649 }
650
651 /* Write per-level diagnostics... */
652 if (level_log) {
653 const size_t nbytes = nx * ny * np * sizeof(float);
654 for (size_t ip = 0; ip < np; ip++)
655 fprintf(level_log,
656 "%s %s %lu %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n",
657 "CMS", varname, (unsigned long) ip, met->p[ip], ratio[ip],
658 bpv[ip], rho[ip], mean_err[ip], stddev_err[ip], min_err[ip],
659 max_err[ip], mean_org[ip], range_org[ip], nrmse[ip], t_coars,
660 COMPRESS_SPEED(nbytes, t_coars), t_eval,
661 COMPRESS_SPEED(nbytes, t_eval));
662 }
663
664 /* Write info... */
665 LOG(2, "Write 3-D variable: %s"
666 " (CMS, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
667 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
668 varname, (double) np / cr, 32. * cr / (double) np, t_coars,
669 COMPRESS_SPEED(nx * ny * np * sizeof(float), t_coars), t_eval,
670 COMPRESS_SPEED(nx * ny * np * sizeof(float), t_eval));
671 }
672
673 /* Free... */
674 cms_delete_param(cms_param);
675}
676#endif
677
678/*****************************************************************************/
679
681 const float *org,
682 const float *cmp,
683 const size_t n,
684 double *mean,
685 double *stddev,
686 double *min,
687 double *max,
688 double *nrmse,
689 double *org_mean,
690 double *range) {
691
692 double avg = 0, m2 = 0, err_min = 0, err_max = 0, rmse = 0;
693 double org_min = 0, org_max = 0;
694
695 /* Calculate error statistics... */
696 for (size_t i = 0; i < n; i++) {
697 const double err = (double) cmp[i] - (double) org[i];
698 const double val = (double) org[i];
699 const double delta = err - avg;
700
701 avg += delta / ((double) i + 1.);
702 m2 += delta * (err - avg);
703 rmse += err * err;
704
705 if (i == 0 || err < err_min)
706 err_min = err;
707 if (i == 0 || err > err_max)
708 err_max = err;
709 if (i == 0 || val < org_min)
710 org_min = val;
711 if (i == 0 || val > org_max)
712 org_max = val;
713 }
714
715 *mean = avg;
716 *stddev = (n > 1 ? sqrt(m2 / ((double) n - 1.)) : 0);
717 *min = err_min;
718 *max = err_max;
719 *org_mean = 0;
720 for (size_t i = 0; i < n; i++)
721 *org_mean += (double) org[i];
722 *org_mean /= (double) n;
723 *range = org_max - org_min;
724 *nrmse = ((org_max - org_min) > 0
725 ? sqrt(rmse / (double) n) / (org_max - org_min)
726 : NAN);
727}
728
729/*****************************************************************************/
730
732 FILE *out) {
733
734 /* Write file header... */
735 fprintf(out,
736 "# $1 = compression codec name [-]\n"
737 "# $2 = variable name [-]\n"
738 "# $3 = level index [-]\n"
739 "# $4 = pressure level [hPa]\n"
740 "# $5 = compression ratio [-]\n"
741 "# $6 = bits per value [bit/value]\n"
742 "# $7 = correlation coefficient [-]\n"
743 "# $8 = mean compression error [-]\n"
744 "# $9 = standard deviation of compression error [-]\n"
745 "# $10 = minimum compression error [-]\n"
746 "# $11 = maximum compression error [-]\n"
747 "# $12 = mean value of original field [-]\n"
748 "# $13 = value range of original field [-]\n"
749 "# $14 = normalized root mean square error [-]\n"
750 "# $15 = compression time [s]\n"
751 "# $16 = compression speed [MiB/s]\n"
752 "# $17 = decompression time [s]\n"
753 "# $18 = decompression speed [MiB/s]\n\n");
754}
755
756/*****************************************************************************/
757
759 FILE *out,
760 const char *codec,
761 const char *varname,
762 const size_t lev,
763 const double plev,
764 const double ratio,
765 const double bpv,
766 const double rho,
767 const double t_comp,
768 const double t_decomp,
769 const size_t n,
770 const size_t nbytes,
771 const float *org,
772 const float *cmp) {
773 static FILE *last_out = NULL;
774 static char last_var[LEN] = "";
775 double mean_err, stddev_err, min_err, max_err;
776 double nrmse, mean_org, range_org, rho_out = rho;
777
778 /* Calculate error statistics... */
779 compress_error_stats(org, cmp, n, &mean_err, &stddev_err, &min_err,
780 &max_err, &nrmse, &mean_org, &range_org);
781 if (isnan(rho_out))
782 rho_out = gsl_stats_float_correlation(org, 1, cmp, 1, n);
783
784 /* Write output... */
785 if (out != last_out) {
786 last_out = out;
787 last_var[0] = '\0';
788 }
789 if (last_var[0] != '\0' && strcmp(last_var, varname) != 0)
790 fprintf(out, "\n");
791 snprintf(last_var, LEN, "%s", varname);
792 fprintf(out,
793 "%s %s %lu %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n",
794 codec, varname, (unsigned long) lev, plev, ratio, bpv, rho_out,
795 mean_err, stddev_err, min_err, max_err, mean_org, range_org, nrmse,
796 t_comp, COMPRESS_SPEED(nbytes, t_comp), t_decomp,
797 COMPRESS_SPEED(nbytes, t_decomp));
798}
799
800/*****************************************************************************/
801
803 float *array,
804 const size_t nxy,
805 const size_t nz,
806 double *off,
807 double *scl) {
808
809 for (size_t iz = 0; iz < nz; iz++) {
810 off[iz] = array[iz];
811 scl[iz] = array[iz];
812 }
813
814 for (size_t ixy = 1; ixy < nxy; ixy++)
815 for (size_t iz = 0; iz < nz; iz++) {
816 const double value = array[ixy * nz + iz];
817 if (value < off[iz])
818 off[iz] = value;
819 if (value > scl[iz])
820 scl[iz] = value;
821 }
822
823 for (size_t iz = 0; iz < nz; iz++) {
824 const double range = scl[iz] - off[iz];
825 const double ref = fmax(1.0, fmax(fabs(off[iz]), fabs(scl[iz])));
826 scl[iz] = !(range > 1e-12 * ref) ? 0.0 : range;
827 }
828
829#pragma omp parallel for default(shared)
830 for (size_t ixy = 0; ixy < nxy; ixy++)
831 for (size_t iz = 0; iz < nz; iz++)
832 if (scl[iz] > 0.0)
833 array[ixy * nz + iz] =
834 (float) ((array[ixy * nz + iz] - off[iz]) / scl[iz]);
835 else
836 array[ixy * nz + iz] = 0.0f;
837}
838
839/*****************************************************************************/
840
842 float *array,
843 const size_t nxy,
844 const size_t nz,
845 const double *off,
846 const double *scl) {
847
848#pragma omp parallel for default(shared)
849 for (size_t ixy = 0; ixy < nxy; ixy++)
850 for (size_t iz = 0; iz < nz; iz++)
851 if (scl[iz] > 0.0)
852 array[ixy * nz + iz] =
853 (float) (array[ixy * nz + iz] * scl[iz] + off[iz]);
854 else
855 array[ixy * nz + iz] = (float) off[iz];
856}
857
858/*****************************************************************************/
859
861 const char *varname) {
862
863 if (strcasecmp(varname, "Z") == 0)
864 return 0;
865 else if (strcasecmp(varname, "T") == 0)
866 return 1;
867 else if (strcasecmp(varname, "U") == 0)
868 return 2;
869 else if (strcasecmp(varname, "V") == 0)
870 return 3;
871 else if (strcasecmp(varname, "W") == 0)
872 return 4;
873 else if (strcasecmp(varname, "PV") == 0)
874 return 5;
875 else if (strcasecmp(varname, "H2O") == 0)
876 return 6;
877 else if (strcasecmp(varname, "O3") == 0)
878 return 7;
879 else if (strcasecmp(varname, "LWC") == 0)
880 return 8;
881 else if (strcasecmp(varname, "RWC") == 0)
882 return 9;
883 else if (strcasecmp(varname, "IWC") == 0)
884 return 10;
885 else if (strcasecmp(varname, "SWC") == 0)
886 return 11;
887 else if (strcasecmp(varname, "CC") == 0)
888 return 12;
889 else
890 ERRMSG("Unknown meteorological variable name!");
891}
892
893/*****************************************************************************/
894
896 const ctl_t *ctl,
897 const met_t *met,
898 const char *varname,
899 float *array,
900 const int decompress,
901 FILE *level_log,
902 FILE *inout) {
903
904 const size_t nxy = (size_t) met->nx * (size_t) met->ny;
905 const size_t nz = (size_t) met->np;
906
907 double vmin[EP], vmax[EP], off[EP], scl[EP];
908 unsigned short *sarray;
909 const size_t payload_len = 2 * nz * sizeof(double)
910 + nxy * nz * sizeof(unsigned short);
911 size_t stored_len = payload_len;
912
913 /* Allocate... */
914 ALLOC(sarray, unsigned short,
915 nxy * nz);
916
917 /* Read compressed stream and decompress array... */
918 if (decompress) {
919 double t_zstd = 0.0;
920
921 /* Read data... */
922 if (ctl->met_pck_zstd) {
923#ifdef ZSTD
924 uint64_t magic, pck_zstd_magic = UINT64_C(0x50434b5a53544431);
925 unsigned char *compr = NULL, *payload = NULL;
926
927 FREAD(&magic, uint64_t, 1, inout);
928 if (magic != pck_zstd_magic)
929 ERRMSG("PCK+ZSTD magic mismatch! Check MET_PCK_ZSTD and file type.");
930 FREAD(&stored_len, size_t,
931 1,
932 inout);
933 ALLOC(compr, unsigned char,
934 stored_len);
935 FREAD(compr, unsigned char,
936 stored_len,
937 inout);
938 ALLOC(payload, unsigned char,
939 payload_len);
940 const double t0_decomp = omp_get_wtime();
941 const size_t out_len =
942 ZSTD_decompress(payload, payload_len, compr, stored_len);
943 t_zstd = omp_get_wtime() - t0_decomp;
944 if (ZSTD_isError(out_len) || out_len != payload_len)
945 ERRMSG("PCK ZSTD decompression failed or size mismatch!");
946 memcpy(scl, payload, nz * sizeof(double));
947 memcpy(off, payload + nz * sizeof(double), nz * sizeof(double));
948 memcpy(sarray, payload + 2 * nz * sizeof(double),
949 nxy * nz * sizeof(unsigned short));
950 free(payload);
951 free(compr);
952#else
953 ERRMSG("MPTRAC was compiled without ZSTD compression!");
954#endif
955 } else {
956 FREAD(&scl, double,
957 nz,
958 inout);
959 FREAD(&off, double,
960 nz,
961 inout);
962 FREAD(sarray, unsigned short,
963 nxy * nz,
964 inout);
965 }
966
967 /* Measure time... */
968 const double t0 = omp_get_wtime();
969
970 /* Convert to float... */
971#pragma omp parallel for default(shared)
972 for (size_t ixy = 0; ixy < nxy; ixy++)
973 for (size_t iz = 0; iz < nz; iz++)
974 array[ixy * nz + iz]
975 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
976
977 /* Write info... */
978 const double t_decomp = t_zstd + omp_get_wtime() - t0;
979 const double ratio_out =
980 (double) (nxy * nz * sizeof(float)) / (double) stored_len;
981 const double bpv_out = (8. * (double) stored_len) / (double) (nxy * nz);
982 LOG(2, "Read 3-D variable: %s"
983 " (PCK%s, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
984 varname, ctl->met_pck_zstd ? "+ZSTD" : "", ratio_out, bpv_out,
985 t_decomp, COMPRESS_SPEED(nxy * nz * sizeof(float), t_decomp));
986 }
987
988 /* Compress array and output compressed stream... */
989 else {
990 float *tmp_org, *tmp_pck;
991 double t_comp_sum = 0, t_decomp_sum = 0, t_zstd = 0, t_zstd_decomp = 0;
992 double rho[EP], mean[EP], stddev[EP], min[EP], max[EP], nrmse[EP];
993 double org_mean[EP], range[EP];
994
995 /* Allocate... */
996 ALLOC(tmp_org, float,
997 nxy);
998 ALLOC(tmp_pck, float,
999 nxy);
1000
1001 /* Get range... */
1002 for (size_t iz = 0; iz < nz; iz++) {
1003 vmin[iz] = array[iz];
1004 vmax[iz] = array[iz];
1005 }
1006 for (size_t ixy = 1; ixy < nxy; ixy++)
1007 for (size_t iz = 0; iz < nz; iz++) {
1008 if (array[ixy * nz + iz] < vmin[iz])
1009 vmin[iz] = array[ixy * nz + iz];
1010 if (array[ixy * nz + iz] > vmax[iz])
1011 vmax[iz] = array[ixy * nz + iz];
1012 }
1013
1014 /* Get offset and scaling factor... */
1015 for (size_t iz = 0; iz < nz; iz++) {
1016 scl[iz] = (vmax[iz] - vmin[iz]) / 65533.;
1017 off[iz] = vmin[iz];
1018 }
1019
1020 /* Convert to short and evaluate per level... */
1021 for (size_t iz = 0; iz < nz; iz++) {
1022 const double t0 = omp_get_wtime();
1023
1024#pragma omp parallel for default(shared)
1025 for (size_t ixy = 0; ixy < nxy; ixy++)
1026 if (scl[iz] != 0)
1027 sarray[ixy * nz + iz] =
1028 (unsigned short) ((array[ixy * nz + iz] - off[iz]) / scl[iz] +
1029 .5);
1030 else
1031 sarray[ixy * nz + iz] = 0;
1032
1033 const double t_comp = omp_get_wtime() - t0;
1034 t_comp_sum += t_comp;
1035
1036 const double t1 = omp_get_wtime();
1037
1038#pragma omp parallel for default(shared)
1039 for (size_t ixy = 0; ixy < nxy; ixy++) {
1040 tmp_org[ixy] = array[ixy * nz + iz];
1041 tmp_pck[ixy] = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
1042 }
1043
1044 const double t_decomp = omp_get_wtime() - t1;
1045 t_decomp_sum += t_decomp;
1046
1047 if (level_log) {
1048 compress_error_stats(tmp_org, tmp_pck, nxy, &mean[iz], &stddev[iz],
1049 &min[iz], &max[iz], &nrmse[iz], &org_mean[iz],
1050 &range[iz]);
1051 rho[iz] = gsl_stats_float_correlation(tmp_org, 1, tmp_pck, 1, nxy);
1052 }
1053 }
1054
1055 /* Write data... */
1056 if (ctl->met_pck_zstd) {
1057#ifdef ZSTD
1058 uint64_t pck_zstd_magic = UINT64_C(0x50434b5a53544431);
1059 unsigned char *payload = NULL, *payload_chk = NULL;
1060 void *stored_data = NULL;
1061 ALLOC(payload, unsigned char,
1062 payload_len);
1063 memcpy(payload, scl, nz * sizeof(double));
1064 memcpy(payload + nz * sizeof(double), off, nz * sizeof(double));
1065 memcpy(payload + 2 * nz * sizeof(double), sarray,
1066 nxy * nz * sizeof(unsigned short));
1067 const size_t dst_cap = ZSTD_compressBound(payload_len);
1068 ALLOC(stored_data, char,
1069 dst_cap);
1070 ZSTD_CCtx *cctx = ZSTD_createCCtx();
1071 if (!cctx)
1072 ERRMSG("Cannot create ZSTD context!");
1073 if (ZSTD_isError
1074 (ZSTD_CCtx_setParameter
1075 (cctx, ZSTD_c_compressionLevel, ctl->met_zstd_level)))
1076 ERRMSG("Cannot set ZSTD compression level!");
1077 if (ZSTD_isError
1078 (ZSTD_CCtx_setParameter
1079 (cctx, ZSTD_c_nbWorkers, ctl->met_zstd_nworkers)))
1080 ERRMSG("Cannot set ZSTD worker count!");
1081 const double t0_comp = omp_get_wtime();
1082 stored_len =
1083 ZSTD_compress2(cctx, stored_data, dst_cap, payload, payload_len);
1084 t_zstd = omp_get_wtime() - t0_comp;
1085 ZSTD_freeCCtx(cctx);
1086 if (ZSTD_isError(stored_len))
1087 ERRMSG("PCK ZSTD compression failed!");
1088 ALLOC(payload_chk, unsigned char,
1089 payload_len);
1090 const double t0_decomp2 = omp_get_wtime();
1091 const size_t out_len2 =
1092 ZSTD_decompress(payload_chk, payload_len, stored_data, stored_len);
1093 t_zstd_decomp = omp_get_wtime() - t0_decomp2;
1094 if (ZSTD_isError(out_len2) || out_len2 != payload_len)
1095 ERRMSG("PCK ZSTD decompression failed or size mismatch!");
1096 free(payload_chk);
1097 free(payload);
1098 FWRITE(&pck_zstd_magic, uint64_t, 1, inout);
1099 FWRITE(&stored_len, size_t,
1100 1,
1101 inout);
1102 FWRITE(stored_data, unsigned char,
1103 stored_len,
1104 inout);
1105 free(stored_data);
1106#else
1107 ERRMSG("MPTRAC was compiled without ZSTD compression!");
1108#endif
1109 } else {
1110 FWRITE(&scl, double,
1111 nz,
1112 inout);
1113 FWRITE(&off, double,
1114 nz,
1115 inout);
1116 FWRITE(sarray, unsigned short,
1117 nxy * nz,
1118 inout);
1119 }
1120
1121 /* Write info... */
1122 const double ratio_out =
1123 (double) (nxy * nz * sizeof(float)) / (double) stored_len;
1124 const double bpv_out = (8. * (double) stored_len) / (double) (nxy * nz);
1125 const double t_comp = t_comp_sum + t_zstd;
1126 const double t_decomp = t_decomp_sum + t_zstd_decomp;
1127 LOG(2, "Write 3-D variable: %s"
1128 " (PCK%s, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
1129 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1130 varname, ctl->met_pck_zstd ? "+ZSTD" : "", ratio_out, bpv_out, t_comp,
1131 COMPRESS_SPEED(nxy * nz * sizeof(float), t_comp), t_decomp,
1132 COMPRESS_SPEED(nxy * nz * sizeof(float), t_decomp));
1133
1134 /* Write per-level diagnostics... */
1135 if (level_log) {
1136 const double t_comp_level = t_comp / (double) nz;
1137 const double t_decomp_level = t_decomp / (double) nz;
1138 for (size_t iz = 0; iz < nz; iz++)
1139 fprintf(level_log,
1140 "%s %s %lu %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n",
1141 ctl->met_pck_zstd ? "PCKZSTD" : "PCK", varname,
1142 (unsigned long) iz, met->p[iz], ratio_out, bpv_out, rho[iz],
1143 mean[iz], stddev[iz], min[iz], max[iz], org_mean[iz],
1144 range[iz], nrmse[iz], t_comp_level,
1145 COMPRESS_SPEED(nxy * sizeof(float), t_comp_level),
1146 t_decomp_level, COMPRESS_SPEED(nxy * sizeof(float),
1147 t_decomp_level));
1148 }
1149
1150 /* Free... */
1151 free(tmp_org);
1152 free(tmp_pck);
1153 }
1154
1155 /* Free... */
1156 free(sarray);
1157}
1158
1159/*****************************************************************************/
1160
1161#ifdef SZ3
1162void compress_sz3(
1163 const ctl_t *ctl,
1164 const met_t *met,
1165 const char *varname,
1166 float *array,
1167 const int decompress,
1168 FILE *level_log,
1169 FILE *inout) {
1170
1171 /* Get meteo variable... */
1172 const int metvar = compress_metvar_index(varname);
1173
1174 /* Check compression settings... */
1175 if ((ctl->met_sz3_prec[metvar] > 0) == (ctl->met_sz3_tol[metvar] > 0.0))
1176 ERRMSG("Exactly one of precision or tolerance must be set for SZ3!");
1177
1178 size_t r1 = (size_t) met->np, r2 = (size_t) met->ny, r3 = (size_t) met->nx,
1179 outSize = 0, total_elems = r1 * r2 * r3;
1180
1181 unsigned char *bytes = NULL;
1182 double *scale_off = NULL, *scale_scl = NULL;
1183 float *orig_all = NULL;
1184
1185 /* Read compressed stream and decompress array... */
1186 if (decompress) {
1187
1188 int stored_lossy_scale;
1189 FREAD(&stored_lossy_scale, int,
1190 1,
1191 inout);
1192 if (stored_lossy_scale < 0 || stored_lossy_scale > 1)
1193 ERRMSG("Invalid stored MET_LOSSY_SCALE flag!");
1194 if (stored_lossy_scale > 0) {
1195 ALLOC(scale_off, double,
1196 r1);
1197 ALLOC(scale_scl, double,
1198 r1);
1199 FREAD(scale_off, double,
1200 r1,
1201 inout);
1202 FREAD(scale_scl, double,
1203 r1,
1204 inout);
1205 }
1206
1207 size_t sz3size;
1208 FREAD(&sz3size, size_t,
1209 1,
1210 inout);
1211 ALLOC(bytes, char,
1212 sz3size);
1213 FREAD(bytes, unsigned char,
1214 sz3size,
1215 inout);
1216
1217 const double t0 = omp_get_wtime();
1218 void *outData = SZ_decompress(SZ_FLOAT, bytes, sz3size, 0, 0, r3, r2, r1);
1219 if (!outData)
1220 ERRMSG("Decompression failed!");
1221
1222 memcpy(array, outData, total_elems * sizeof(float));
1223 if (stored_lossy_scale > 0)
1224 compress_unscale_from_unit(array, r2 * r3, r1, scale_off, scale_scl);
1225 const double t_decomp = omp_get_wtime() - t0;
1226
1227 free(outData);
1228 free(bytes);
1229
1230 LOG(2, "Read 3-D variable: %s"
1231 " (SZ3, PREC=%d, TOL=%g, SCALE=%d, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1232 varname, ctl->met_sz3_prec[metvar], ctl->met_sz3_tol[metvar],
1233 stored_lossy_scale,
1234 (double) (total_elems * sizeof(float)) / (double) sz3size,
1235 (8. * (double) sz3size) / (double) total_elems, t_decomp,
1236 COMPRESS_SPEED(total_elems * sizeof(float), t_decomp));
1237 }
1238
1239 /* Compress array and output compressed stream... */
1240 else {
1241 const int errBoundMode = (ctl->met_sz3_prec[metvar] > 0) ? REL : ABS;
1242 FWRITE(&ctl->met_lossy_scale[metvar], int,
1243 1,
1244 inout);
1245 if (ctl->met_lossy_scale[metvar] > 0) {
1246 ALLOC(scale_off, double,
1247 r1);
1248 ALLOC(scale_scl, double,
1249 r1);
1250 if (level_log) {
1251 ALLOC(orig_all, float,
1252 total_elems);
1253 memcpy(orig_all, array, total_elems * sizeof(float));
1254 }
1255 compress_scale_to_unit(array, r2 * r3, r1, scale_off, scale_scl);
1256 FWRITE(scale_off, double,
1257 r1,
1258 inout);
1259 FWRITE(scale_scl, double,
1260 r1,
1261 inout);
1262 }
1263 const double absBound =
1264 (errBoundMode == ABS) ? ctl->met_sz3_tol[metvar] : 0.0;
1265 const double relBound = (errBoundMode == REL) ? pow(2.0,
1266 -(double)
1267 ctl->met_sz3_prec
1268 [metvar])
1269 : 0.0;
1270
1271 const double t0 = omp_get_wtime();
1272 bytes = SZ_compress_args(SZ_FLOAT, array, &outSize,
1273 errBoundMode, absBound, relBound, 0.0,
1274 0, 0, r3, r2, r1);
1275 const double t_comp = omp_get_wtime() - t0;
1276 if (!bytes || outSize == 0)
1277 ERRMSG("Compression failed!");
1278
1279 FWRITE(&outSize, size_t,
1280 1,
1281 inout);
1282 FWRITE(bytes, unsigned char,
1283 outSize,
1284 inout);
1285
1286 double t_decomp = NAN;
1287 if (level_log) {
1288 unsigned char *bytes_copy;
1289
1290 /* Reconstruct data for per-level diagnostics... */
1291 ALLOC(bytes_copy, unsigned char,
1292 outSize);
1293 memcpy(bytes_copy, bytes, outSize);
1294
1295 const double t1 = omp_get_wtime();
1296 void *decData = SZ_decompress(SZ_FLOAT, bytes_copy, outSize, 0, 0, r3,
1297 r2, r1);
1298 t_decomp = omp_get_wtime() - t1;
1299 if (!decData)
1300 ERRMSG("Decompression failed!");
1301
1302 float *tmp_all, *tmp_org, *tmp_sz3;
1303 const size_t nxy = r2 * r3;
1304
1305 ALLOC(tmp_all, float,
1306 total_elems);
1307 ALLOC(tmp_org, float,
1308 nxy);
1309 ALLOC(tmp_sz3, float,
1310 nxy);
1311 memcpy(tmp_all, decData, total_elems * sizeof(float));
1312 if (ctl->met_lossy_scale[metvar] > 0)
1313 compress_unscale_from_unit(tmp_all, r2 * r3, r1, scale_off,
1314 scale_scl);
1315
1316 for (size_t lev = 0; lev < r1; lev++) {
1317
1318 /* Extract current level... */
1319#pragma omp parallel for default(shared)
1320 for (size_t ixy = 0; ixy < nxy; ixy++) {
1321 tmp_org[ixy] = (orig_all ? orig_all : array)[ixy * r1 + lev];
1322 tmp_sz3[ixy] = tmp_all[ixy * r1 + lev];
1323 }
1324 compress_log_level(level_log, "SZ3", varname, lev, met->p[lev],
1325 (double) (total_elems * sizeof(float))
1326 / (double) outSize,
1327 (8. * (double) outSize) / (double) total_elems,
1328 NAN, t_comp, t_decomp, nxy,
1329 total_elems * sizeof(float), tmp_org, tmp_sz3);
1330 }
1331
1332 free(tmp_all);
1333 free(tmp_org);
1334 free(tmp_sz3);
1335 free(decData);
1336 free(bytes_copy);
1337
1338 LOG(2, "Write 3-D variable: %s"
1339 " (SZ3, PREC=%d, TOL=%g, SCALE=%d, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
1340 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1341 varname, ctl->met_sz3_prec[metvar], ctl->met_sz3_tol[metvar],
1342 ctl->met_lossy_scale[metvar],
1343 (double) (total_elems * sizeof(float)) / (double) outSize,
1344 (8. * (double) outSize) / (double) total_elems, t_comp,
1345 COMPRESS_SPEED(total_elems * sizeof(float), t_comp), t_decomp,
1346 COMPRESS_SPEED(total_elems * sizeof(float), t_decomp));
1347 } else
1348 LOG(2, "Write 3-D variable: %s"
1349 " (SZ3, PREC=%d, TOL=%g, SCALE=%d, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s)",
1350 varname, ctl->met_sz3_prec[metvar], ctl->met_sz3_tol[metvar],
1351 ctl->met_lossy_scale[metvar],
1352 (double) (total_elems * sizeof(float)) / (double) outSize,
1353 (8. * (double) outSize) / (double) total_elems, t_comp,
1354 COMPRESS_SPEED(total_elems * sizeof(float), t_comp));
1355 free(bytes);
1356 free(orig_all);
1357 }
1358
1359 free(scale_off);
1360 free(scale_scl);
1361}
1362#endif
1363
1364/*****************************************************************************/
1365
1366#ifdef ZFP
1367void compress_zfp(
1368 const ctl_t *ctl,
1369 const met_t *met,
1370 const char *varname,
1371 float *array,
1372 const int decompress,
1373 FILE *level_log,
1374 FILE *inout) {
1375
1376 /* Get meteo variable... */
1377 const int metvar = compress_metvar_index(varname);
1378
1379 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
1380 const size_t snx = (size_t) met->np;
1381 const size_t sny = (size_t) met->ny;
1382 const size_t snz = (size_t) met->nx;
1383 const zfp_type type = zfp_type_float;
1384 zfp_field *field = zfp_field_3d(array, type, snx, sny, snz);
1385
1386 /* Allocate meta data for a compressed stream... */
1387 zfp_stream *zfp = zfp_stream_open(NULL);
1388 if (!field || !zfp)
1389 ERRMSG("Failed to allocate zfp structures!");
1390
1391 /* Set compression mode... */
1392 int actual_prec = 0;
1393 double actual_tol = 0;
1394 if ((ctl->met_zfp_prec[metvar] > 0 && ctl->met_zfp_tol[metvar] > 0)
1395 || (ctl->met_zfp_prec[metvar] <= 0 && ctl->met_zfp_tol[metvar] <= 0)) {
1396 ERRMSG("Exactly one of precision or tolerance must be set for zfp!");
1397 } else if (ctl->met_zfp_prec[metvar] > 0)
1398 actual_prec = (int) zfp_stream_set_precision(zfp, (unsigned int)
1399 ctl->met_zfp_prec[metvar]);
1400 else if (ctl->met_zfp_tol[metvar] > 0)
1401 actual_tol = zfp_stream_set_accuracy(zfp, ctl->met_zfp_tol[metvar]);
1402
1403 /* Allocate buffer for compressed data... */
1404 const size_t bufsize = zfp_stream_maximum_size(zfp, field);
1405 void *buffer;
1406 ALLOC(buffer, char,
1407 bufsize);
1408
1409 /* Associate bit stream with allocated buffer... */
1410 bitstream *stream = stream_open(buffer, bufsize);
1411 zfp_stream_set_bit_stream(zfp, stream);
1412 zfp_stream_rewind(zfp);
1413
1414 /* Read compressed stream and decompress array... */
1415 size_t zfpsize;
1416 double *scale_off = NULL, *scale_scl = NULL;
1417 if (decompress) {
1418 int stored_lossy_scale;
1419 FREAD(&stored_lossy_scale, int,
1420 1,
1421 inout);
1422 if (stored_lossy_scale < 0 || stored_lossy_scale > 1)
1423 ERRMSG("Invalid stored MET_LOSSY_SCALE flag!");
1424 if (stored_lossy_scale > 0) {
1425 ALLOC(scale_off, double,
1426 snx);
1427 ALLOC(scale_scl, double,
1428 snx);
1429 FREAD(scale_off, double,
1430 snx,
1431 inout);
1432 FREAD(scale_scl, double,
1433 snx,
1434 inout);
1435 }
1436 FREAD(&zfpsize, size_t,
1437 1,
1438 inout);
1439 if (zfpsize > bufsize)
1440 ERRMSG("Compressed data size exceeds allocated buffer!");
1441 FREAD(buffer, unsigned char,
1442 zfpsize,
1443 inout);
1444 const double t0 = omp_get_wtime();
1445 if (!zfp_decompress(zfp, field))
1446 ERRMSG("Decompression failed!");
1447 if (stored_lossy_scale > 0)
1448 compress_unscale_from_unit(array, sny * snz, snx, scale_off, scale_scl);
1449 const double t_decomp = omp_get_wtime() - t0;
1450 const double cr =
1451 ((double) (snx * sny * snz * sizeof(float))) / (double) zfpsize;
1452 const double bpv = (8.0 * (double) zfpsize) / (double) (snx * sny * snz);
1453 LOG(2,
1454 "Read 3-D variable: %s"
1455 " (ZFP, PREC=%d, TOL=%g, SCALE=%d, RATIO=%g, BPV=%g, T_DECOMP=%g s,"
1456 " V_DECOMP=%g MiB/s)",
1457 varname, actual_prec, actual_tol, stored_lossy_scale, cr, bpv,
1458 t_decomp, COMPRESS_SPEED(snx * sny * snz * sizeof(float), t_decomp));
1459 }
1460
1461 /* Compress array and output compressed stream... */
1462 else {
1463 float *tmp_all, *tmp_org, *tmp_zfp, *orig_all = NULL;
1464 const size_t nxy = sny * snz;
1465
1466 FWRITE(&ctl->met_lossy_scale[metvar], int,
1467 1,
1468 inout);
1469 if (ctl->met_lossy_scale[metvar] > 0) {
1470 ALLOC(scale_off, double,
1471 snx);
1472 ALLOC(scale_scl, double,
1473 snx);
1474 if (level_log) {
1475 ALLOC(orig_all, float,
1476 snx * sny * snz);
1477 memcpy(orig_all, array, snx * sny * snz * sizeof(float));
1478 }
1479 compress_scale_to_unit(array, nxy, snx, scale_off, scale_scl);
1480 FWRITE(scale_off, double,
1481 snx,
1482 inout);
1483 FWRITE(scale_scl, double,
1484 snx,
1485 inout);
1486 }
1487
1488 ALLOC(tmp_all, float,
1489 snx * sny * snz);
1490 ALLOC(tmp_org, float,
1491 nxy);
1492 ALLOC(tmp_zfp, float,
1493 nxy);
1494
1495 const double t0 = omp_get_wtime();
1496 zfpsize = zfp_compress(zfp, field);
1497 const double t_comp = omp_get_wtime() - t0;
1498 if (!zfpsize) {
1499 ERRMSG("Compression failed!");
1500 } else {
1501 FWRITE(&zfpsize, size_t,
1502 1,
1503 inout);
1504 FWRITE(buffer, unsigned char,
1505 zfpsize,
1506 inout);
1507 }
1508
1509 zfp_field *dec_field = zfp_field_3d(tmp_all, type, snx, sny, snz);
1510 if (!dec_field)
1511 ERRMSG("Failed to allocate zfp structures!");
1512
1513 const double t1 = omp_get_wtime();
1514 zfp_stream_rewind(zfp);
1515 if (!zfp_decompress(zfp, dec_field))
1516 ERRMSG("Decompression failed!");
1517 if (ctl->met_lossy_scale[metvar] > 0)
1518 compress_unscale_from_unit(tmp_all, nxy, snx, scale_off, scale_scl);
1519 const double t_decomp = omp_get_wtime() - t1;
1520
1521 for (size_t lev = 0; lev < snx; lev++) {
1522
1523 /* Extract current level... */
1524#pragma omp parallel for default(shared)
1525 for (size_t ixy = 0; ixy < nxy; ixy++) {
1526 tmp_org[ixy] = (orig_all ? orig_all : array)[ixy * snx + lev];
1527 tmp_zfp[ixy] = tmp_all[ixy * snx + lev];
1528 }
1529 if (level_log)
1530 compress_log_level(level_log, "ZFP", varname, lev, met->p[lev],
1531 ((double) (snx * sny * snz * sizeof(float)))
1532 / (double) zfpsize, (8.0 * (double) zfpsize)
1533 / (double) (snx * sny * snz),
1534 NAN, t_comp, t_decomp, nxy,
1535 snx * sny * snz * sizeof(float), tmp_org, tmp_zfp);
1536 }
1537
1538 const double cr =
1539 ((double) (snx * sny * snz * sizeof(float))) / (double) zfpsize;
1540 const double bpv = (8.0 * (double) zfpsize) / (double) (snx * sny * snz);
1541 LOG(2,
1542 "Write 3-D variable: %s"
1543 " (ZFP, PREC=%d, TOL=%g, SCALE=%d, RATIO=%g, BPV=%g, T_COMP=%g s,"
1544 " V_COMP=%g MiB/s, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1545 varname, actual_prec, actual_tol, ctl->met_lossy_scale[metvar], cr,
1546 bpv, t_comp, COMPRESS_SPEED(snx * sny * snz * sizeof(float), t_comp),
1547 t_decomp, COMPRESS_SPEED(snx * sny * snz * sizeof(float), t_decomp));
1548
1549 free(tmp_all);
1550 free(tmp_org);
1551 free(tmp_zfp);
1552 free(orig_all);
1553 zfp_field_free(dec_field);
1554 }
1555
1556 free(scale_off);
1557 free(scale_scl);
1558
1559 /* Free... */
1560 zfp_field_free(field);
1561 stream_close(stream);
1562 zfp_stream_close(zfp);
1563 free(buffer);
1564}
1565#endif
1566
1567/*****************************************************************************/
1568
1569#ifdef ZSTD
1570void compress_zstd(
1571 const ctl_t *ctl,
1572 const met_t *met,
1573 const char *varname,
1574 float *array,
1575 const int decompress,
1576 FILE *level_log,
1577 FILE *inout) {
1578
1579 /* Get buffer sizes... */
1580 const size_t nxy = (size_t) met->nx * (size_t) met->ny;
1581 const size_t nz = (size_t) met->np;
1582 const size_t n = nxy * nz, uncomprLen = n * sizeof(float);
1583 size_t compsize, comprLen = ZSTD_compressBound(uncomprLen);
1584
1585 /* Allocate... */
1586 char *compr, *uncompr = (char *) array;
1587 ALLOC(compr, char,
1588 comprLen);
1589
1590 /* Read compressed stream and decompress array... */
1591 if (decompress) {
1592 FREAD(&comprLen, size_t,
1593 1,
1594 inout);
1595 FREAD(compr, unsigned char,
1596 comprLen,
1597 inout);
1598 const double t0 = omp_get_wtime();
1599 compsize = ZSTD_decompress(uncompr, uncomprLen, compr, comprLen);
1600 const double t_decomp = omp_get_wtime() - t0;
1601 if (ZSTD_isError(compsize) || compsize != uncomprLen)
1602 ERRMSG("Decompression failed or size mismatch!");
1603 LOG(2, "Read 3-D variable: %s"
1604 " (ZSTD, LEVEL=%d, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1605 varname, ctl->met_zstd_level,
1606 ((double) uncomprLen) / (double) comprLen,
1607 (8. * (double) comprLen) / (double) n, t_decomp,
1608 COMPRESS_SPEED(uncomprLen, t_decomp));
1609 }
1610
1611 /* Compress array and output compressed stream... */
1612 else {
1613 float *tmp_org, *tmp_zstd, *tmp_all;
1614 ZSTD_CCtx *cctx;
1615
1616 ALLOC(tmp_org, float,
1617 nxy);
1618 ALLOC(tmp_zstd, float,
1619 nxy);
1620 ALLOC(tmp_all, float,
1621 n);
1622
1623 cctx = ZSTD_createCCtx();
1624 if (!cctx)
1625 ERRMSG("Cannot create ZSTD context!");
1626
1627 if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel,
1628 ctl->met_zstd_level)))
1629 ERRMSG("Cannot set ZSTD compression level!");
1630
1631 if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers,
1632 ctl->met_zstd_nworkers)))
1633 ERRMSG("Cannot set ZSTD worker count!");
1634
1635 const double t0 = omp_get_wtime();
1636 compsize = ZSTD_compress2(cctx, compr, comprLen, uncompr, uncomprLen);
1637 const double t_comp = omp_get_wtime() - t0;
1638 if (ZSTD_isError(compsize)) {
1639 ZSTD_freeCCtx(cctx);
1640 ERRMSG("Compression failed!");
1641 } else {
1642 FWRITE(&compsize, size_t,
1643 1,
1644 inout);
1645 FWRITE(compr, unsigned char,
1646 compsize,
1647 inout);
1648 }
1649
1650 const double t1 = omp_get_wtime();
1651 const size_t decomp_size = ZSTD_decompress(tmp_all, uncomprLen, compr,
1652 compsize);
1653 const double t_decomp = omp_get_wtime() - t1;
1654 if (ZSTD_isError(decomp_size) || decomp_size != uncomprLen)
1655 ERRMSG("Decompression failed or size mismatch!");
1656
1657 for (size_t lev = 0; lev < nz; lev++) {
1658
1659 /* Extract current level... */
1660#pragma omp parallel for default(shared)
1661 for (size_t ixy = 0; ixy < nxy; ixy++) {
1662 tmp_org[ixy] = array[ixy * nz + lev];
1663 tmp_zstd[ixy] = tmp_all[ixy * nz + lev];
1664 }
1665 if (level_log)
1666 compress_log_level(level_log, "ZSTD", varname, lev, met->p[lev],
1667 ((double) uncomprLen) / (double) compsize,
1668 (8. * (double) compsize) / (double) n,
1669 NAN, t_comp, t_decomp, nxy, uncomprLen, tmp_org,
1670 tmp_zstd);
1671 }
1672
1673 LOG(2, "Write 3-D variable: %s"
1674 " (ZSTD, LEVEL=%d, NWORKERS=%d, RATIO=%g, BPV=%g, T_COMP=%g s,"
1675 " V_COMP=%g MiB/s,"
1676 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1677 varname, ctl->met_zstd_level, ctl->met_zstd_nworkers,
1678 ((double) uncomprLen) / (double) compsize,
1679 (8. * (double) compsize) / (double) n, t_comp,
1680 COMPRESS_SPEED(uncomprLen, t_comp), t_decomp,
1681 COMPRESS_SPEED(uncomprLen, t_decomp));
1682
1683 ZSTD_freeCCtx(cctx);
1684 free(tmp_org);
1685 free(tmp_zstd);
1686 free(tmp_all);
1687 }
1688
1689 /* Free... */
1690 free(compr);
1691}
1692#endif
1693
1694/*****************************************************************************/
1695
1696#ifdef LZ4
1697void compress_lz4(
1698 const ctl_t *ctl,
1699 const met_t *met,
1700 const char *varname,
1701 float *array,
1702 const int decompress,
1703 FILE *level_log,
1704 FILE *inout) {
1705
1706 /* Get buffer sizes... */
1707 const size_t nxy = (size_t) met->nx * (size_t) met->ny;
1708 const size_t nz = (size_t) met->np;
1709 const size_t n = nxy * nz;
1710 const size_t uncomprLen = n * sizeof(float);
1711 if (uncomprLen > (size_t) INT_MAX)
1712 ERRMSG("LZ4 input buffer exceeds INT_MAX!");
1713 const int uncomprLenInt = (int) uncomprLen;
1714 const int accel = ctl->met_lz4_accel > 0 ? ctl->met_lz4_accel : 1;
1715 const int comprCapInt = LZ4_compressBound(uncomprLenInt);
1716 if (comprCapInt <= 0)
1717 ERRMSG("Cannot determine LZ4 compression bound!");
1718 size_t comprLen = (size_t) comprCapInt;
1719
1720 /* Allocate... */
1721 char *compr, *uncompr = (char *) array;
1722 ALLOC(compr, char,
1723 comprLen);
1724
1725 /* Read compressed stream and decompress array... */
1726 if (decompress) {
1727 FREAD(&comprLen, size_t,
1728 1,
1729 inout);
1730 if (comprLen > (size_t) INT_MAX)
1731 ERRMSG("LZ4 compressed buffer exceeds INT_MAX!");
1732 FREAD(compr, unsigned char,
1733 comprLen,
1734 inout);
1735 const double t0 = omp_get_wtime();
1736 const int decomp_size =
1737 LZ4_decompress_safe(compr, uncompr, (int) comprLen, uncomprLenInt);
1738 const double t_decomp = omp_get_wtime() - t0;
1739 if (decomp_size != uncomprLenInt)
1740 ERRMSG("Decompression failed or size mismatch!");
1741 LOG(2, "Read 3-D variable: %s"
1742 " (LZ4, ACCEL=%d, RATIO=%g, BPV=%g, T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1743 varname, accel, ((double) uncomprLen) / (double) comprLen,
1744 (8. * (double) comprLen) / (double) n, t_decomp,
1745 COMPRESS_SPEED(uncomprLen, t_decomp));
1746 }
1747
1748 /* Compress array and output compressed stream... */
1749 else {
1750 float *tmp_org, *tmp_lz4, *tmp_all;
1751
1752 ALLOC(tmp_org, float,
1753 nxy);
1754 ALLOC(tmp_lz4, float,
1755 nxy);
1756 ALLOC(tmp_all, float,
1757 n);
1758
1759 const double t0 = omp_get_wtime();
1760 const int compsizeInt =
1761 LZ4_compress_fast(uncompr, compr, uncomprLenInt, comprCapInt, accel);
1762 const double t_comp = omp_get_wtime() - t0;
1763 if (compsizeInt <= 0)
1764 ERRMSG("Compression failed!");
1765 const size_t compsize = (size_t) compsizeInt;
1766 FWRITE(&compsize, size_t,
1767 1,
1768 inout);
1769 FWRITE(compr, unsigned char,
1770 compsize,
1771 inout);
1772
1773 const double t1 = omp_get_wtime();
1774 const int decomp_size =
1775 LZ4_decompress_safe(compr, (char *) tmp_all, compsizeInt,
1776 uncomprLenInt);
1777 const double t_decomp = omp_get_wtime() - t1;
1778 if (decomp_size != uncomprLenInt)
1779 ERRMSG("Decompression failed or size mismatch!");
1780
1781 for (size_t lev = 0; lev < nz; lev++) {
1782
1783 /* Extract current level... */
1784#pragma omp parallel for default(shared)
1785 for (size_t ixy = 0; ixy < nxy; ixy++) {
1786 tmp_org[ixy] = array[ixy * nz + lev];
1787 tmp_lz4[ixy] = tmp_all[ixy * nz + lev];
1788 }
1789 if (level_log)
1790 compress_log_level(level_log, "LZ4", varname, lev, met->p[lev],
1791 ((double) uncomprLen) / (double) compsize,
1792 (8. * (double) compsize) / (double) n,
1793 NAN, t_comp, t_decomp, nxy, uncomprLen, tmp_org,
1794 tmp_lz4);
1795 }
1796
1797 LOG(2, "Write 3-D variable: %s"
1798 " (LZ4, ACCEL=%d, RATIO=%g, BPV=%g, T_COMP=%g s, V_COMP=%g MiB/s,"
1799 " T_DECOMP=%g s, V_DECOMP=%g MiB/s)",
1800 varname, accel, ((double) uncomprLen) / (double) compsize,
1801 (8. * (double) compsize) / (double) n, t_comp,
1802 COMPRESS_SPEED(uncomprLen, t_comp), t_decomp,
1803 COMPRESS_SPEED(uncomprLen, t_decomp));
1804
1805 free(tmp_org);
1806 free(tmp_lz4);
1807 free(tmp_all);
1808 }
1809
1810 /* Free... */
1811 free(compr);
1812}
1813#endif
1814
1815/*****************************************************************************/
1816
1817double cos_sza(
1818 const double sec,
1819 const double lon,
1820 const double lat) {
1821
1822 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
1823 const double D = sec / 86400 - 0.5;
1824
1825 /* Geocentric apparent ecliptic longitude [rad]... */
1826 const double g = DEG2RAD(357.529 + 0.98560028 * D);
1827 const double q = 280.459 + 0.98564736 * D;
1828 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
1829
1830 /* Mean obliquity of the ecliptic [rad]... */
1831 const double e = DEG2RAD(23.439 - 0.00000036 * D);
1832
1833 /* Declination [rad]... */
1834 const double sindec = sin(e) * sin(L);
1835
1836 /* Right ascension [rad]... */
1837 const double ra = atan2(cos(e) * sin(L), cos(L));
1838
1839 /* Greenwich Mean Sidereal Time [h]... */
1840 const double GMST = 18.697374558 + 24.06570982441908 * D;
1841
1842 /* Local Sidereal Time [h]... */
1843 const double LST = GMST + lon / 15;
1844
1845 /* Hour angle [rad]... */
1846 const double h = LST / 12 * M_PI - ra;
1847
1848 /* Convert latitude... */
1849 const double lat_help = DEG2RAD(lat);
1850
1851 /* Return cosine of solar zenith angle... */
1852 return sin(lat_help) * sindec + cos(lat_help) * sqrt(1 -
1853 SQR(sindec)) * cos(h);
1854}
1855
1856/*****************************************************************************/
1857
1859 const int year,
1860 const int mon,
1861 const int day,
1862 int *doy) {
1863
1864 const int
1865 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1866 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1867
1868 /* Get day of year... */
1869 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
1870 *doy = d0l[mon - 1] + day - 1;
1871 else
1872 *doy = d0[mon - 1] + day - 1;
1873}
1874
1875/*****************************************************************************/
1876
1877#ifdef DD
1879 const ctl_t *ctl,
1880 const dd_t *dd,
1881 atm_t *atm,
1882 const int init) {
1883
1884 /* Set timer... */
1885 SELECT_TIMER("DD_ASSIGN_SUBDOMAINS", "DD");
1886
1887 /* Get MPI rank... */
1888 int rank;
1889 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
1890
1891 /* Determine owned core subdomain in index space... */
1892 const int zonal_rank = rank / ctl->dd_subdomains_meridional;
1893 const int merid_rank = rank % ctl->dd_subdomains_meridional;
1894
1895 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
1896 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
1897
1898 const int ix0 = zonal_rank * nx_block;
1899 const int iy0 = merid_rank * ny_block;
1900
1901 const int ix1 = ix0 + nx_block
1902 + (zonal_rank == ctl->dd_subdomains_zonal - 1 ?
1903 dd->nx_glob - ctl->dd_subdomains_zonal * nx_block : 0);
1904
1905 const int iy1 = iy0 + ny_block
1906 + (merid_rank == ctl->dd_subdomains_meridional - 1 ?
1907 dd->ny_glob - ctl->dd_subdomains_meridional * ny_block : 0);
1908
1909 /* Loop over particles... */
1910#ifdef _OPENACC
1911#pragma acc update device(dd->nx_glob, dd->ny_glob, \
1912 dd->lon_glob[:dd->nx_glob], \
1913 dd->lat_glob[:dd->ny_glob])
1914#pragma acc data present(atm, ctl, dd)
1915#pragma acc parallel loop independent gang vector
1916#endif
1917 for (int ip = 0; ip < atm->np; ip++) {
1918
1919 /* Skip already invalid particles... */
1920 if (!init && (int) atm->q[ctl->qnt_subdomain][ip] == -1)
1921 continue;
1922
1923 /* Normalize coordinates... */
1924 double lon = atm->lon[ip];
1925 double lat = atm->lat[ip];
1926 dd_normalize_lon_lat(dd, &lon, &lat);
1927
1928 /* Check whether particle is inside owned core subdomain... */
1929 const int ix = locate_reg(dd->lon_glob, dd->nx_glob, lon);
1930 const int iy = locate_irr(dd->lat_glob, dd->ny_glob, lat);
1931 const int inside = (ix >= ix0 && ix < ix1 && iy >= iy0 && iy < iy1);
1932
1933 /* Init... */
1934 if (init) {
1935 atm->q[ctl->qnt_subdomain][ip] = inside ? rank : -1;
1936 atm->q[ctl->qnt_destination][ip] = inside ? rank : -1;
1937 }
1938
1939 /* Reassign... */
1940 else {
1941 atm->q[ctl->qnt_destination][ip] =
1942 inside ? rank : dd_calc_subdomain_from_coords(ctl, dd, lon, lat);
1943 }
1944 }
1945}
1946#endif
1947
1948/*****************************************************************************/
1949
1950#ifdef DD
1951void dd_atm2particles(
1952 const ctl_t *ctl,
1953 cache_t *cache,
1954 atm_t *atm,
1955 particle_t *particles,
1956 const int npart) {
1957
1958 /* Set timer... */
1959 SELECT_TIMER("DD_ATM2PARTICLES", "DD");
1960
1961 /* Check if particles are present... */
1962 if (npart == 0)
1963 return;
1964
1965 int rank;
1966 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
1967
1968 /* Select the particles that will be send... */
1969#ifdef _OPENACC
1970#pragma acc enter data create(npart, particles[:npart])
1971#pragma acc update device(npart, particles[:npart])
1972#pragma acc parallel loop present(atm, ctl, particles, cache, npart)
1973#endif
1974 for (int ip = atm->np; ip < atm->np + npart; ip++)
1975 if (((int) (atm->q[ctl->qnt_destination][ip]) != rank)
1976 && ((int) (atm->q[ctl->qnt_destination][ip]) >= 0)
1977 && ((int) atm->q[ctl->qnt_subdomain][ip] >= 0)) {
1978
1979 particles[ip - atm->np].time = atm->time[ip];
1980 particles[ip - atm->np].lon = atm->lon[ip];
1981 particles[ip - atm->np].lat = atm->lat[ip];
1982 particles[ip - atm->np].p = atm->p[ip];
1983 for (int iq = 0; iq < ctl->nq; iq++)
1984 particles[ip - atm->np].q[iq] = atm->q[iq][ip];
1985
1986 atm->q[ctl->qnt_subdomain][ip] = -1;
1987 cache->dt[ip] = 0;
1988 }
1989#ifdef _OPENACC
1990#pragma acc update host( particles[:npart])
1991#pragma acc exit data delete(npart, particles)
1992#endif
1993}
1994#endif
1995
1996/*****************************************************************************/
1997
1998#ifdef DD
2000 const ctl_t *ctl,
2001 const dd_t *dd,
2002 double lon,
2003 double lat) {
2004
2005 /* Normalize coordinates... */
2006 dd_normalize_lon_lat(dd, &lon, &lat);
2007
2008 /* Get grid index... */
2009 const int ix = locate_reg(dd->lon_glob, dd->nx_glob, lon);
2010 const int iy = locate_irr(dd->lat_glob, dd->ny_glob, lat);
2011
2012 /* Get zonal subdomain index... */
2013 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
2014 int zonal_rank = ix / nx_block;
2015 if (zonal_rank >= ctl->dd_subdomains_zonal)
2016 zonal_rank = ctl->dd_subdomains_zonal - 1;
2017
2018 /* Get meridional subdomain index... */
2019 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
2020 int merid_rank = iy / ny_block;
2021 if (merid_rank >= ctl->dd_subdomains_meridional)
2022 merid_rank = ctl->dd_subdomains_meridional - 1;
2023
2024 /* Return rank... */
2025 return zonal_rank * ctl->dd_subdomains_meridional + merid_rank;
2026}
2027#endif
2028
2029/*****************************************************************************/
2030
2031#ifdef DD
2033 const ctl_t *ctl,
2034 const dd_t *dd,
2035 particle_t **particles,
2036 int *npart,
2037 int *capacity) {
2038
2039 /* Set timer... */
2040 SELECT_TIMER("DD_COMMUNICATE_PARTICLES", "DD");
2041
2042 int rank, size;
2043 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
2044 MPI_Comm_size(MPI_COMM_WORLD, &size);
2045
2046 int *send_counts, *recv_counts;
2047 int *send_displs, *recv_displs;
2048 int *offsets;
2049
2050 particle_t *sendbuf = NULL;
2051 particle_t *recvbuf = NULL;
2052
2053 ALLOC(send_counts, int,
2054 size);
2055 ALLOC(recv_counts, int,
2056 size);
2057 ALLOC(send_displs, int,
2058 size);
2059 ALLOC(recv_displs, int,
2060 size);
2061 ALLOC(offsets, int,
2062 size);
2063
2064 /* Count particles per destination rank... */
2065#pragma omp parallel for
2066 for (int ip = 0; ip < *npart; ip++) {
2067 const int dest = (int) (*particles)[ip].q[ctl->qnt_destination];
2068 if (dest == rank)
2069 continue;
2070 if (dest < 0 || dest >= size)
2071 ERRMSG("Invalid destination rank!");
2072#pragma omp atomic
2073 send_counts[dest]++;
2074 }
2075
2076 /* Compute send displacements... */
2077 int nsend = 0;
2078 for (int i = 0; i < size; i++) {
2079 send_displs[i] = nsend;
2080 nsend += send_counts[i];
2081 }
2082
2083 /* Exchange particle counts... */
2084 MPI_Alltoall(send_counts, 1, MPI_INT,
2085 recv_counts, 1, MPI_INT, MPI_COMM_WORLD);
2086
2087 /* Compute receive displacements... */
2088 int nrecv = 0;
2089 for (int i = 0; i < size; i++) {
2090 recv_displs[i] = nrecv;
2091 nrecv += recv_counts[i];
2092 }
2093 if (nsend > 0)
2094 ALLOC(sendbuf, particle_t, nsend);
2095 if (nrecv > 0)
2096 ALLOC(recvbuf, particle_t, nrecv);
2097 for (int i = 0; i < size; i++)
2098 offsets[i] = send_displs[i];
2099
2100 /* Pack particles into send buffer... */
2101 for (int ip = 0; ip < *npart; ip++) {
2102 const int dest = (int) (*particles)[ip].q[ctl->qnt_destination];
2103 if (dest == rank)
2104 continue;
2105 memcpy(&sendbuf[offsets[dest]], &(*particles)[ip], sizeof(particle_t));
2106 offsets[dest]++;
2107 }
2108
2109 /* Exchange particle data... */
2110 MPI_Alltoallv(sendbuf,
2111 send_counts,
2112 send_displs,
2113 dd->MPI_Particle,
2114 recvbuf,
2115 recv_counts, recv_displs, dd->MPI_Particle, MPI_COMM_WORLD);
2116
2117 /* Resize particle buffer if necessary... */
2118 if (nrecv > *capacity) {
2119 const int newcap = nrecv + nrecv / 2 + 1;
2120 particle_t *tmp =
2121 realloc(*particles, (size_t) newcap * sizeof(particle_t));
2122 if (!tmp)
2123 ERRMSG("Out of memory!");
2124 *particles = tmp;
2125 *capacity = newcap;
2126 }
2127
2128 /* Copy received particles... */
2129#pragma omp parallel for
2130 for (int ip = 0; ip < nrecv; ip++) {
2131 (*particles)[ip] = recvbuf[ip];
2132 (*particles)[ip].q[ctl->qnt_destination] = rank;
2133 (*particles)[ip].q[ctl->qnt_subdomain] = rank;
2134 }
2135 *npart = nrecv;
2136
2137 /* Free temporary buffers... */
2138 if (sendbuf)
2139 free(sendbuf);
2140 if (recvbuf)
2141 free(recvbuf);
2142 free(send_counts);
2143 free(recv_counts);
2144 free(send_displs);
2145 free(recv_displs);
2146 free(offsets);
2147}
2148#endif
2149
2150/*****************************************************************************/
2151
2152#ifdef DD
2153void dd_init(
2154 const ctl_t *ctl,
2155 dd_t *dd,
2156 atm_t *atm) {
2157
2158 /* Check if enough tasks are requested... */
2159 int size;
2160 MPI_Comm_size(MPI_COMM_WORLD, &size);
2161 if (size != ctl->dd_subdomains_meridional * ctl->dd_subdomains_zonal)
2162 ERRMSG("Number of tasks and subdomains is not identical!");
2163
2164 /* Register the MPI_Particle data type... */
2165 const MPI_Datatype types[5] =
2166 { MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE };
2167 const int blocklengths[5] = { 1, 1, 1, 1, NQ };
2168 const MPI_Aint displacements[5] =
2169 { offsetof(particle_t, time), offsetof(particle_t, p),
2170 offsetof(particle_t, lon), offsetof(particle_t, lat),
2171 offsetof(particle_t, q)
2172 };
2173 MPI_Type_create_struct(5, blocklengths, displacements, types,
2174 &dd->MPI_Particle);
2175 MPI_Type_commit(&dd->MPI_Particle);
2176
2177 /* Check if particles are in subdomain... */
2178 dd_assign_subdomains(ctl, dd, atm, 1);
2179}
2180#endif
2181
2182/*****************************************************************************/
2183
2184#ifdef DD
2186 const dd_t *dd,
2187 double *lon,
2188 double *lat) {
2189
2190 const double lon_min = (dd->lon_glob[0] < 0) ? -180.0 : 0.0;
2191
2192 /* Normalize longitude to match global grid convention... */
2193 *lon = FMOD(*lon - lon_min, 360.0);
2194 if (*lon < 0.0)
2195 *lon += 360.0;
2196 *lon += lon_min;
2197
2198 /* Wrap latitude across the poles and shift longitude... */
2199 if (*lat > 90.0) {
2200 *lat = 180.0 - *lat;
2201 *lon += 180.0;
2202 } else if (*lat < -90.0) {
2203 *lat = -180.0 - *lat;
2204 *lon += 180.0;
2205 }
2206
2207 /* Renormalize longitude after pole crossing... */
2208 *lon = FMOD(*lon - lon_min, 360.0);
2209 if (*lon < 0.0)
2210 *lon += 360.0;
2211 *lon += lon_min;
2212}
2213#endif
2214
2215/*****************************************************************************/
2216
2217#ifdef DD
2218void dd_particles2atm(
2219 const ctl_t *ctl,
2220 cache_t *cache,
2221 const particle_t *particles,
2222 const int npart,
2223 atm_t *atm) {
2224
2225 /* Set timer... */
2226 SELECT_TIMER("DD_PARTICLES2ATM", "DD");
2227
2228 /* Check if particles are present... */
2229 if (npart == 0)
2230 return;
2231
2232 /* Check number of particles... */
2233 if (atm->np + npart > NP)
2234 ERRMSG("Too many particles. Increase NP!");
2235
2236#ifdef _OPENACC
2237#pragma acc enter data create(npart, particles[:npart])
2238#pragma acc update device(particles[:npart], npart)
2239#pragma acc data present(atm, ctl, cache, particles, npart)
2240#pragma acc parallel loop
2241#endif
2242 for (int ip = atm->np; ip < atm->np + npart; ip++) {
2243 atm->time[ip] = particles[ip - atm->np].time;
2244 atm->lon[ip] = particles[ip - atm->np].lon;
2245 atm->lat[ip] = particles[ip - atm->np].lat;
2246 atm->p[ip] = particles[ip - atm->np].p;
2247 for (int iq = 0; iq < ctl->nq; iq++)
2248 atm->q[iq][ip] = particles[ip - atm->np].q[iq];
2249 cache->dt[ip] = ctl->dt_mod;
2250 }
2251#ifdef _OPENACC
2252#pragma acc exit data delete(npart, particles)
2253#endif
2254
2255 /* Reset size... */
2256 atm->np += npart;
2257#ifdef _OPENACC
2258#pragma acc update device(atm->np)
2259#endif
2260}
2261#endif
2262
2263/*****************************************************************************/
2264
2265#ifdef DD
2266void dd_push(
2267 const ctl_t *ctl,
2268 atm_t *atm,
2269 cache_t *cache,
2270 int *npart) {
2271
2272 SELECT_TIMER("DD_PUSH", "DD");
2273
2274 int rank;
2275 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
2276
2277 /* Create a counter on the device... */
2278 int device_counter = 0;
2279 int *device_counter_ptr = (int *) acc_malloc(sizeof(int));
2280 if (device_counter_ptr == NULL) {
2281 ERRMSG("Failed to allocate device counter memory!");
2282 }
2283 acc_memcpy_to_device(device_counter_ptr, &device_counter, sizeof(int));
2284
2285 /* Push non local particles behind the end of the atm... */
2286#pragma acc parallel loop present(atm, cache) deviceptr(device_counter_ptr)
2287 for (int ip = 0; ip < atm->np; ip++) {
2288 if ((int) atm->q[ctl->qnt_subdomain][ip] != -1 &&
2289 (int) atm->q[ctl->qnt_destination][ip] != rank) {
2290
2291 int local_idx;
2292
2293#pragma acc atomic capture
2294 {
2295 local_idx = *device_counter_ptr;
2296 (*device_counter_ptr)++;
2297 }
2298
2299 int global_index = atm->np + local_idx;
2300
2301 /* Copy time, pressure, longitude, and latitude... */
2302 atm->time[global_index] = atm->time[ip];
2303 atm->p[global_index] = atm->p[ip];
2304 atm->lon[global_index] = atm->lon[ip];
2305 atm->lat[global_index] = atm->lat[ip];
2306
2307 /* Copy all quantity data (q array)... */
2308 for (int iq = 0; iq < NQ; iq++) {
2309 atm->q[iq][global_index] = atm->q[iq][ip];
2310 }
2311
2312 /* Mark the original parcel as processed... */
2313 atm->q[ctl->qnt_destination][ip] = -1;
2314 atm->q[ctl->qnt_subdomain][ip] = -1;
2315
2316 /* Reset cache->dt for the shifted particle... */
2317 cache->dt[global_index] = cache->dt[ip];
2318 cache->dt[ip] = 0;
2319 }
2320 }
2321
2322 /* Update host and free... */
2323 acc_memcpy_from_device(npart, device_counter_ptr, sizeof(int));
2324 acc_free(device_counter_ptr);
2325}
2326#endif
2327
2328/*****************************************************************************/
2329
2330#ifdef DD
2331void dd_sort(
2332 const ctl_t *ctl,
2333 const met_t *met0,
2334 atm_t *atm,
2335 dd_t *dd,
2336 int *npart) {
2337
2338 /* Set timer... */
2339 SELECT_TIMER("DD_SORT", "DD");
2340
2341 int rank;
2342 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
2343
2344 /* Allocate... */
2345 const int np = atm->np;
2346 double amax = (met0->nx * met0->ny + met0->ny) * met0->np + met0->np;
2347#ifdef _OPENACC
2348#pragma acc enter data create(amax)
2349#pragma acc update device(amax)
2350#pragma acc data present(ctl,met0,atm,dd,amax)
2351#endif
2352
2353 /* Get box index... */
2354#ifdef _OPENACC
2355#pragma acc parallel loop independent gang vector
2356#else
2357#pragma omp parallel for default(shared)
2358#endif
2359 for (int ip = 0; ip < np; ip++) {
2360 if ((int) atm->q[ctl->qnt_subdomain][ip] != -1) {
2361 if ((int) atm->q[ctl->qnt_destination][ip] == rank)
2362 dd->sort_key[ip] =
2363 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) *
2364 met0->ny + locate_irr(met0->lat, met0->ny, atm->lat[ip]))
2365 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
2366 else
2367 dd->sort_key[ip] = amax + 1;
2368 } else {
2369 dd->sort_key[ip] = amax + 2;
2370 }
2371 dd->perm[ip] = ip;
2372 }
2373
2374 /* Sorting... */
2375#ifdef THRUST
2376#ifdef _OPENACC
2377#pragma acc host_data use_device(dd->sort_key, dd->perm)
2378#endif
2379 thrustSortWrapper(dd->sort_key, np, dd->perm);
2380#else
2381 size_t *perm_sz = (size_t *) malloc((size_t) np * sizeof(size_t));
2382 if (perm_sz == NULL)
2383 ERRMSG("Out of memory!");
2384#ifdef _OPENACC
2385#pragma acc update self(dd->sort_key[0:np])
2386#endif
2387 gsl_sort_index(perm_sz, dd->sort_key, 1, (size_t) np);
2388 for (int ip = 0; ip < np; ++ip)
2389 dd->perm[ip] = (int) perm_sz[ip];
2390 free(perm_sz);
2391#ifdef _OPENACC
2392#pragma acc update device(dd->perm[0:np])
2393#endif
2394#endif
2395
2396 /* Sort data... */
2397 dd_sort_help(atm->time, dd, np);
2398 dd_sort_help(atm->p, dd, np);
2399 dd_sort_help(atm->lon, dd, np);
2400 dd_sort_help(atm->lat, dd, np);
2401 for (int iq = 0; iq < ctl->nq; iq++)
2402 dd_sort_help(atm->q[iq], dd, np);
2403
2404 /* Reset the size... */
2405 int nkeep = 0;
2406#ifdef _OPENACC
2407#pragma acc parallel loop reduction(+:nkeep) present(atm, ctl)
2408#endif
2409 for (int ip = 0; ip < np; ip++)
2410 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
2411 && ((int) atm->q[ctl->qnt_destination][ip] == rank))
2412 nkeep++;
2413
2414 /* Count number of particles to send... */
2415 int nsend = 0;
2416#ifdef _OPENACC
2417#pragma acc parallel loop reduction(+:nsend) present(atm, ctl)
2418#endif
2419 for (int ip = nkeep; ip < np; ip++)
2420 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
2421 && ((int) atm->q[ctl->qnt_destination][ip] != rank))
2422 nsend++;
2423
2424 /* Reset sizes... */
2425 *npart = nsend;
2426
2427 /* Count particles with -1 subdomain (these will be effectively lost) */
2428 int nlost = 0;
2429 for (int ip = 0; ip < np; ip++)
2430 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
2431 nlost++;
2432
2433 if (nlost > 0)
2434 WARN
2435 ("Rank %d: %d particles have subdomain index -1 and will be lost (kept: %d, to_send: %d, total_before: %d)",
2436 rank, nlost, nkeep, nsend, np);
2437
2438 atm->np = nkeep;
2439#ifdef _OPENACC
2440#pragma acc update device(atm->np)
2441#endif
2442
2443 /* Free... */
2444#ifdef _OPENACC
2445#pragma acc exit data delete(amax)
2446#endif
2447}
2448#endif
2449
2450/*****************************************************************************/
2451
2452#ifdef DD
2453void dd_sort_help(
2454 double *a,
2455 dd_t *dd,
2456 const int np) {
2457
2458 /* Reordering of array... */
2459#ifdef _OPENACC
2460#pragma acc data present(dd,a)
2461#pragma acc parallel loop independent gang vector
2462#else
2463#pragma omp parallel for default(shared)
2464#endif
2465 for (int ip = 0; ip < np; ip++)
2466 dd->tmp[ip] = a[dd->perm[ip]];
2467#ifdef _OPENACC
2468#pragma acc parallel loop independent gang vector
2469#else
2470#pragma omp parallel for default(shared)
2471#endif
2472 for (int ip = 0; ip < np; ip++)
2473 a[ip] = dd->tmp[ip];
2474}
2475#endif
2476
2477/*****************************************************************************/
2478
2480 const int year,
2481 const int doy,
2482 int *mon,
2483 int *day) {
2484
2485 const int
2486 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
2487 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
2488
2489 int i;
2490
2491 /* Get month and day... */
2492 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
2493 for (i = 11; i > 0; i--)
2494 if (d0l[i] <= doy)
2495 break;
2496 *mon = i + 1;
2497 *day = doy - d0l[i] + 1;
2498 } else {
2499 for (i = 11; i > 0; i--)
2500 if (d0[i] <= doy)
2501 break;
2502 *mon = i + 1;
2503 *day = doy - d0[i] + 1;
2504 }
2505}
2506
2507/*****************************************************************************/
2508
2510 double *fcReal,
2511 double *fcImag,
2512 const int n) {
2513
2514 double data[2 * EX];
2515
2516 /* Check size... */
2517 if (n > EX)
2518 ERRMSG("Too many data points!");
2519
2520 /* Allocate... */
2521 gsl_fft_complex_wavetable *wavetable =
2522 gsl_fft_complex_wavetable_alloc((size_t) n);
2523 gsl_fft_complex_workspace *workspace =
2524 gsl_fft_complex_workspace_alloc((size_t) n);
2525
2526 /* Set data (real, complex)... */
2527 for (int i = 0; i < n; i++) {
2528 data[2 * i] = fcReal[i];
2529 data[2 * i + 1] = fcImag[i];
2530 }
2531
2532 /* Calculate FFT... */
2533 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
2534
2535 /* Copy data... */
2536 for (int i = 0; i < n; i++) {
2537 fcReal[i] = data[2 * i];
2538 fcImag[i] = data[2 * i + 1];
2539 }
2540
2541 /* Free... */
2542 gsl_fft_complex_wavetable_free(wavetable);
2543 gsl_fft_complex_workspace_free(workspace);
2544}
2545
2546/*****************************************************************************/
2547
2549 const double z,
2550 const double lon,
2551 const double lat,
2552 double *x) {
2553
2554 const double radius = z + RE;
2555 const double latrad = DEG2RAD(lat);
2556 const double lonrad = DEG2RAD(lon);
2557 const double coslat = cos(latrad);
2558
2559 x[0] = radius * coslat * cos(lonrad);
2560 x[1] = radius * coslat * sin(lonrad);
2561 x[2] = radius * sin(latrad);
2562}
2563
2564/*****************************************************************************/
2565
2567 const ctl_t *ctl,
2568 const double t,
2569 const int direct,
2570 const char *metbase,
2571 const double dt_met,
2572 char *filename) {
2573
2574 char repl[LEN];
2575
2576 double t6, r;
2577
2578 int year, mon, day, hour, min, sec;
2579
2580 /* Round time to fixed intervals... */
2581 if (direct == -1)
2582 t6 = floor(t / dt_met) * dt_met;
2583 else
2584 t6 = ceil(t / dt_met) * dt_met;
2585
2586 /* Decode time... */
2587 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
2588
2589 /* Set filename of MPTRAC meteo files... */
2590 if (ctl->met_clams == 0) {
2591 if (ctl->met_type == 0)
2592 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
2593 else if (ctl->met_type == 1)
2594 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
2595 else if (ctl->met_type == 2)
2596 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
2597 else if (ctl->met_type == 3)
2598 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
2599 else if (ctl->met_type == 4)
2600 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
2601 else if (ctl->met_type == 5)
2602 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
2603 else if (ctl->met_type == 7)
2604 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
2605 else if (ctl->met_type == 8)
2606 sprintf(filename, "%s_YYYY_MM_DD_HH.lz4", metbase);
2607 sprintf(repl, "%d", year);
2608 get_met_replace(filename, "YYYY", repl);
2609 sprintf(repl, "%02d", mon);
2610 get_met_replace(filename, "MM", repl);
2611 sprintf(repl, "%02d", day);
2612 get_met_replace(filename, "DD", repl);
2613 sprintf(repl, "%02d", hour);
2614 get_met_replace(filename, "HH", repl);
2615 }
2616
2617 /* Set filename of CLaMS meteo files... */
2618 else {
2619 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
2620 sprintf(repl, "%d", year);
2621 get_met_replace(filename, "YYYY", repl);
2622 sprintf(repl, "%02d", year % 100);
2623 get_met_replace(filename, "YY", repl);
2624 sprintf(repl, "%02d", mon);
2625 get_met_replace(filename, "MM", repl);
2626 sprintf(repl, "%02d", day);
2627 get_met_replace(filename, "DD", repl);
2628 sprintf(repl, "%02d", hour);
2629 get_met_replace(filename, "HH", repl);
2630 }
2631}
2632
2633/*****************************************************************************/
2634
2636 char *orig,
2637 const char *search,
2638 const char *repl) {
2639
2640 char buffer[LEN];
2641
2642 /* Iterate... */
2643 for (int i = 0; i < 3; i++) {
2644
2645 /* Replace sub-string... */
2646 char *ch;
2647 if (!(ch = strstr(orig, search)))
2648 return;
2649 strncpy(buffer, orig, (size_t) (ch - orig));
2650 buffer[ch - orig] = 0;
2651 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
2652 orig[0] = 0;
2653 strcpy(orig, buffer);
2654 }
2655}
2656
2657/*****************************************************************************/
2658
2660 const int met_tropo,
2661 ctl_t *ctl,
2662 const clim_t *clim,
2663 met_t *met,
2664 const double *lons,
2665 const int nx,
2666 const double *lats,
2667 const int ny,
2668 double *pt,
2669 double *zt,
2670 double *tt,
2671 double *qt,
2672 double *o3t,
2673 double *ps,
2674 double *zs) {
2675
2677
2678 ctl->met_tropo = met_tropo;
2679 read_met_tropo(ctl, clim, met);
2680#pragma omp parallel for default(shared) private(ci,cw)
2681 for (int ix = 0; ix < nx; ix++)
2682 for (int iy = 0; iy < ny; iy++) {
2683 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
2684 &pt[iy * nx + ix], ci, cw, 1);
2685 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
2686 &ps[iy * nx + ix], ci, cw, 0);
2687 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
2688 &zs[iy * nx + ix], ci, cw, 0);
2689 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
2690 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
2691 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
2692 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
2693 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
2694 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
2695 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
2696 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
2697 }
2698}
2699
2700/*****************************************************************************/
2701
2703 const double *lons,
2704 const int nlon,
2705 const double *lats,
2706 const int nlat,
2707 const double lon,
2708 const double lat,
2709 double *lon2,
2710 double *lat2) {
2711
2712 /* Check longitude... */
2713 *lon2 = FMOD(lon, 360.);
2714 if (*lon2 < lons[0])
2715 *lon2 += 360;
2716 else if (*lon2 > lons[nlon - 1])
2717 *lon2 -= 360;
2718
2719 /* Check latitude... */
2720 *lat2 = lat;
2721 if (lats[0] < lats[nlat - 1])
2722 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
2723 else
2724 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
2725}
2726
2727/*****************************************************************************/
2728
2730 const double *lons,
2731 const int nlon,
2732 const double *lats,
2733 const int nlat,
2734 const double lon,
2735 const double lat,
2736 double *lon2,
2737 double *lat2) {
2738
2739 *lon2 = lon;
2740 if (lons[0] < lons[nlon - 1])
2741 *lon2 = MIN(MAX(lon, lons[0]), lons[nlon - 1]);
2742 else
2743 *lon2 = MIN(MAX(lon, lons[nlon - 1]), lons[0]);
2744
2745 *lat2 = lat;
2746 if (lats[0] < lats[nlat - 1])
2747 *lat2 = MIN(MAX(lat, lats[0]), lats[nlat - 1]);
2748 else
2749 *lat2 = MIN(MAX(lat, lats[nlat - 1]), lats[0]);
2750}
2751
2752
2753/*****************************************************************************/
2754
2756 const met_t *met0,
2757 float heights0[EX][EY][EP],
2758 float array0[EX][EY][EP],
2759 const met_t *met1,
2760 float heights1[EX][EY][EP],
2761 float array1[EX][EY][EP],
2762 const double ts,
2763 const double height,
2764 const double lon,
2765 const double lat,
2766 double *var,
2767 int *ci,
2768 double *cw,
2769 const int init) {
2770
2771 if (init) {
2772
2773 /* Check longitude and latitude... */
2774 double lon2, lat2;
2775
2776 if (met0->coord_type == 0)
2777 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
2778 &lon2, &lat2);
2779 else
2780 intpol_check_cartesian(met0->lon, met0->nx, met0->lat, met0->ny, lon,
2781 lat, &lon2, &lat2);
2782
2783 /* Get horizontal indizes... */
2784 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
2785 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
2786
2787 /* Locate the vertical indizes for each edge of the column... */
2788 int ind[2][4];
2789 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
2790 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
2791
2792 /* Find minimum and maximum indizes... */
2793 ci[2] = ind[0][0];
2794 int k_max = ind[0][0];
2795 for (int i = 0; i < 2; i++)
2796 for (int j = 0; j < 4; j++) {
2797 if (ci[2] > ind[i][j])
2798 ci[2] = ind[i][j];
2799 if (k_max < ind[i][j])
2800 k_max = ind[i][j];
2801 }
2802
2803 /* Get weighting factors for time, longitude and latitude... */
2804 cw[3] = (ts - met0->time) / (met1->time - met0->time);
2805 cw[0] = (lon2 - met0->lon[ci[0]]) /
2806 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
2807 cw[1] = (lat2 - met0->lat[ci[1]]) /
2808 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
2809
2810 /* Interpolate in time at the lowest level... */
2811 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
2812 - heights0[ci[0]][ci[1]][ci[2]])
2813 + heights0[ci[0]][ci[1]][ci[2]];
2814 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
2815 - heights0[ci[0]][ci[1] + 1][ci[2]])
2816 + heights0[ci[0]][ci[1] + 1][ci[2]];
2817 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
2818 - heights0[ci[0] + 1][ci[1]][ci[2]])
2819 + heights0[ci[0] + 1][ci[1]][ci[2]];
2820 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
2821 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
2822 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
2823
2824 /* Interpolate in latitude direction... */
2825 double height0 = cw[1] * (height01 - height00) + height00;
2826 double height1 = cw[1] * (height11 - height10) + height10;
2827
2828 /* Interpolate in longitude direction... */
2829 double height_bot = cw[0] * (height1 - height0) + height0;
2830
2831 /* Interpolate in time at the upper level... */
2832 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2833 - heights0[ci[0]][ci[1]][ci[2] + 1])
2834 + heights0[ci[0]][ci[1]][ci[2] + 1];
2835 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2836 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2837 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2838 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2839 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2840 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2841 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2842 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2843 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2844
2845 /* Interpolate in latitude direction... */
2846 height0 = cw[1] * (height01 - height00) + height00;
2847 height1 = cw[1] * (height11 - height10) + height10;
2848
2849 /* Interpolate in longitude direction... */
2850 double height_top = cw[0] * (height1 - height0) + height0;
2851
2852 /* Search at higher levels if height is not in box... */
2853 while (((heights0[0][0][0] > heights0[0][0][1]) &&
2854 ((height_bot <= height) || (height_top > height))
2855 && (height_bot >= height) && (ci[2] < k_max))
2856 ||
2857 ((heights0[0][0][0] < heights0[0][0][1]) &&
2858 ((height_bot >= height) || (height_top < height))
2859 && (height_bot <= height) && (ci[2] < k_max))
2860 ) {
2861
2862 ci[2]++;
2863 height_bot = height_top;
2864
2865 /* Interpolate in time at the next level... */
2866 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2867 - heights0[ci[0]][ci[1]][ci[2] + 1])
2868 + heights0[ci[0]][ci[1]][ci[2] + 1];
2869 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2870 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2871 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2872 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2873 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2874 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2875 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2876 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2877 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2878
2879 /* Interpolate in latitude direction... */
2880 height0 = cw[1] * (height01 - height00) + height00;
2881 height1 = cw[1] * (height11 - height10) + height10;
2882
2883 /* Interpolate in longitude direction... */
2884 height_top = cw[0] * (height1 - height0) + height0;
2885 }
2886
2887 /* Get vertical weighting factors... */
2888 cw[2] = (height - height_bot)
2889 / (height_top - height_bot);
2890 }
2891
2892 /* Calculate the needed array values... */
2893 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
2894 - array0[ci[0]][ci[1]][ci[2]])
2895 + array0[ci[0]][ci[1]][ci[2]];
2896 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
2897 - array0[ci[0] + 1][ci[1]][ci[2]])
2898 + array0[ci[0] + 1][ci[1]][ci[2]];
2899 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
2900 - array0[ci[0]][ci[1] + 1][ci[2]])
2901 + array0[ci[0]][ci[1] + 1][ci[2]];
2902 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
2903 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
2904 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
2905 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
2906 - array0[ci[0]][ci[1]][ci[2] + 1])
2907 + array0[ci[0]][ci[1]][ci[2] + 1];
2908 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2909 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2910 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2911 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2912 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2913 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2914 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2915 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2916 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2917
2918 const double array00 = cw[0] * (array100 - array000) + array000;
2919 const double array10 = cw[0] * (array110 - array010) + array010;
2920 const double array01 = cw[0] * (array101 - array001) + array001;
2921 const double array11 = cw[0] * (array111 - array011) + array011;
2922
2923 const double aux0 = cw[1] * (array10 - array00) + array00;
2924 const double aux1 = cw[1] * (array11 - array01) + array01;
2925
2926 /* Interpolate vertically... */
2927 *var = cw[2] * (aux1 - aux0) + aux0;
2928}
2929
2930/*****************************************************************************/
2931
2933 const met_t *met,
2934 float array[EX][EY][EP],
2935 const double p,
2936 const double lon,
2937 const double lat,
2938 double *var,
2939 int *ci,
2940 double *cw,
2941 const int init) {
2942
2943 /* Initialize interpolation... */
2944 if (init) {
2945
2946 /* Check longitude and latitude... */
2947 double lon2, lat2;
2948
2949 if (met->coord_type == 0)
2950 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2951 &lon2, &lat2);
2952 else
2953 intpol_check_cartesian(met->lon, met->nx, met->lat, met->ny, lon, lat,
2954 &lon2, &lat2);
2955
2956 /* Get interpolation indices... */
2957 ci[0] = locate_irr(met->p, met->np, p);
2958 ci[1] = locate_reg(met->lon, met->nx, lon2);
2959 ci[2] = locate_irr(met->lat, met->ny, lat2);
2960
2961 /* Get interpolation weights... */
2962 cw[0] = (met->p[ci[0] + 1] - p)
2963 / (met->p[ci[0] + 1] - met->p[ci[0]]);
2964 cw[1] = (met->lon[ci[1] + 1] - lon2)
2965 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2966 cw[2] = (met->lat[ci[2] + 1] - lat2)
2967 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2968 }
2969
2970 /* Interpolate vertically... */
2971 const double aux00 =
2972 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
2973 + array[ci[1]][ci[2]][ci[0] + 1];
2974 const double aux01 =
2975 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
2976 array[ci[1]][ci[2] + 1][ci[0] + 1])
2977 + array[ci[1]][ci[2] + 1][ci[0] + 1];
2978 const double aux10 =
2979 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
2980 array[ci[1] + 1][ci[2]][ci[0] + 1])
2981 + array[ci[1] + 1][ci[2]][ci[0] + 1];
2982 const double aux11 =
2983 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
2984 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
2985 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
2986
2987 /* Interpolate horizontally... */
2988 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2989 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2990 *var = cw[1] * (aux0 - aux1) + aux1;
2991}
2992
2993/*****************************************************************************/
2994
2996 const met_t *met,
2997 float array[EX][EY],
2998 const double lon,
2999 const double lat,
3000 double *var,
3001 int *ci,
3002 double *cw,
3003 const int init) {
3004
3005 /* Initialize interpolation... */
3006 if (init) {
3007
3008 /* Check longitude and latitude... */
3009 double lon2, lat2;
3010
3011 if (met->coord_type == 0)
3012 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
3013 &lon2, &lat2);
3014 else
3015 intpol_check_cartesian(met->lon, met->nx, met->lat, met->ny, lon, lat,
3016 &lon2, &lat2);
3017
3018
3019 /* Get interpolation indices... */
3020 ci[1] = locate_reg(met->lon, met->nx, lon2);
3021 ci[2] = locate_irr(met->lat, met->ny, lat2);
3022
3023 /* Get interpolation weights... */
3024 cw[1] = (met->lon[ci[1] + 1] - lon2)
3025 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
3026 cw[2] = (met->lat[ci[2] + 1] - lat2)
3027 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
3028 }
3029
3030 /* Set variables... */
3031 const double aux00 = array[ci[1]][ci[2]];
3032 const double aux01 = array[ci[1]][ci[2] + 1];
3033 const double aux10 = array[ci[1] + 1][ci[2]];
3034 const double aux11 = array[ci[1] + 1][ci[2] + 1];
3035
3036 /* Interpolate horizontally... */
3037 if (isfinite(aux00) && isfinite(aux01)
3038 && isfinite(aux10) && isfinite(aux11)) {
3039 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
3040 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
3041 *var = cw[1] * (aux0 - aux1) + aux1;
3042 } else {
3043 if (cw[2] < 0.5) {
3044 if (cw[1] < 0.5)
3045 *var = aux11;
3046 else
3047 *var = aux01;
3048 } else {
3049 if (cw[1] < 0.5)
3050 *var = aux10;
3051 else
3052 *var = aux00;
3053 }
3054 }
3055}
3056
3057/*****************************************************************************/
3058
3060 const met_t *met0,
3061 float array0[EX][EY][EP],
3062 const met_t *met1,
3063 float array1[EX][EY][EP],
3064 const double ts,
3065 const double p,
3066 const double lon,
3067 const double lat,
3068 double *var,
3069 int *ci,
3070 double *cw,
3071 const int init) {
3072
3073 double var0, var1;
3074
3075 /* Spatial interpolation... */
3076 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
3077 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
3078
3079 /* Get weighting factor... */
3080 const double wt = (met1->time - ts) / (met1->time - met0->time);
3081
3082 /* Interpolate... */
3083 *var = wt * (var0 - var1) + var1;
3084}
3085
3086/*****************************************************************************/
3087
3089 const met_t *met0,
3090 float array0[EX][EY],
3091 const met_t *met1,
3092 float array1[EX][EY],
3093 const double ts,
3094 const double lon,
3095 const double lat,
3096 double *var,
3097 int *ci,
3098 double *cw,
3099 const int init) {
3100
3101 double var0, var1;
3102
3103 /* Spatial interpolation... */
3104 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
3105 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
3106
3107 /* Get weighting factor... */
3108 const double wt = (met1->time - ts) / (met1->time - met0->time);
3109
3110 /* Interpolate... */
3111 if (isfinite(var0) && isfinite(var1))
3112 *var = wt * (var0 - var1) + var1;
3113 else if (wt < 0.5)
3114 *var = var1;
3115 else
3116 *var = var0;
3117}
3118
3119/*****************************************************************************/
3120
3122 const double time0,
3123 float array0[EX][EY],
3124 const double time1,
3125 float array1[EX][EY],
3126 const double lons[EX],
3127 const double lats[EY],
3128 const int nlon,
3129 const int nlat,
3130 const double time,
3131 const double lon,
3132 const double lat,
3133 const int method,
3134 double *var,
3135 double *sigma) {
3136
3137 double mean = 0;
3138
3139 int n = 0;
3140
3141 /* Check longitude and latitude... */
3142 double lon2, lat2;
3143 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
3144
3145 /* Get indices... */
3146 const int ix = locate_reg(lons, (int) nlon, lon2);
3147 const int iy = locate_irr(lats, (int) nlat, lat2);
3148
3149 /* Calculate standard deviation... */
3150 *sigma = 0;
3151 for (int dx = 0; dx < 2; dx++)
3152 for (int dy = 0; dy < 2; dy++) {
3153 if (isfinite(array0[ix + dx][iy + dy])) {
3154 mean += array0[ix + dx][iy + dy];
3155 *sigma += SQR(array0[ix + dx][iy + dy]);
3156 n++;
3157 }
3158 if (isfinite(array1[ix + dx][iy + dy])) {
3159 mean += array1[ix + dx][iy + dy];
3160 *sigma += SQR(array1[ix + dx][iy + dy]);
3161 n++;
3162 }
3163 }
3164 if (n > 0)
3165 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
3166
3167 /* Linear interpolation... */
3168 if (method == 1 && isfinite(array0[ix][iy])
3169 && isfinite(array0[ix][iy + 1])
3170 && isfinite(array0[ix + 1][iy])
3171 && isfinite(array0[ix + 1][iy + 1])
3172 && isfinite(array1[ix][iy])
3173 && isfinite(array1[ix][iy + 1])
3174 && isfinite(array1[ix + 1][iy])
3175 && isfinite(array1[ix + 1][iy + 1])) {
3176
3177 const double aux00 = LIN(lons[ix], array0[ix][iy],
3178 lons[ix + 1], array0[ix + 1][iy], lon2);
3179 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
3180 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
3181 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
3182
3183 const double aux10 = LIN(lons[ix], array1[ix][iy],
3184 lons[ix + 1], array1[ix + 1][iy], lon2);
3185 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
3186 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
3187 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
3188
3189 *var = LIN(time0, aux0, time1, aux1, time);
3190 }
3191
3192 /* Nearest neighbor interpolation... */
3193 else {
3194 const double aux00 = NN(lons[ix], array0[ix][iy],
3195 lons[ix + 1], array0[ix + 1][iy], lon2);
3196 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
3197 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
3198 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
3199
3200 const double aux10 = NN(lons[ix], array1[ix][iy],
3201 lons[ix + 1], array1[ix + 1][iy], lon2);
3202 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
3203 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
3204 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
3205
3206 *var = NN(time0, aux0, time1, aux1, time);
3207 }
3208}
3209
3210/*****************************************************************************/
3211
3213 const double jsec,
3214 int *year,
3215 int *mon,
3216 int *day,
3217 int *hour,
3218 int *min,
3219 int *sec,
3220 double *remain) {
3221
3222 struct tm t0, *t1;
3223
3224 t0.tm_year = 100;
3225 t0.tm_mon = 0;
3226 t0.tm_mday = 1;
3227 t0.tm_hour = 0;
3228 t0.tm_min = 0;
3229 t0.tm_sec = 0;
3230
3231 const time_t jsec0 = (time_t) jsec + timegm(&t0);
3232 t1 = gmtime(&jsec0);
3233
3234 *year = t1->tm_year + 1900;
3235 *mon = t1->tm_mon + 1;
3236 *day = t1->tm_mday;
3237 *hour = t1->tm_hour;
3238 *min = t1->tm_min;
3239 *sec = t1->tm_sec;
3240 *remain = jsec - floor(jsec);
3241}
3242
3243/*****************************************************************************/
3244
3246 const double kz[EP],
3247 const double kw[EP],
3248 const int nk,
3249 const double p) {
3250
3251 /* Check number of data points... */
3252 if (nk < 2)
3253 return 1.0;
3254
3255 /* Get altitude... */
3256 const double z = Z(p);
3257
3258 /* Get weighting factor... */
3259 if (z < kz[0])
3260 return kw[0];
3261 else if (z > kz[nk - 1])
3262 return kw[nk - 1];
3263 else {
3264 const int idx = locate_irr(kz, nk, z);
3265 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
3266 }
3267}
3268
3269/*****************************************************************************/
3270
3272 const double t,
3273 const double h2o) {
3274
3275 /*
3276 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
3277 and water vapor volume mixing ratio [1].
3278
3279 Reference: https://en.wikipedia.org/wiki/Lapse_rate
3280 */
3281
3282 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
3283
3284 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
3285}
3286
3287/*****************************************************************************/
3288
3290 ctl_t *ctl) {
3291
3292 if (0 == ctl->met_press_level_def) {
3293
3294 ERRMSG
3295 ("MET_PRESS_LEVEL_DEF=0 is disabled. Use 3 for the extended L137 set.");
3296
3297 } else if (1 == ctl->met_press_level_def) {
3298
3299 ERRMSG
3300 ("MET_PRESS_LEVEL_DEF=1 is disabled. Use 4 for the extended L91 set.");
3301
3302 } else if (2 == ctl->met_press_level_def) {
3303
3304 ERRMSG
3305 ("MET_PRESS_LEVEL_DEF=2 is disabled. Use 5 for the extended L60 set.");
3306
3307 } else if (3 == ctl->met_press_level_def) {
3308
3309 ctl->met_np = 147;
3310
3311 const double press[147] = {
3312 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
3313 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
3314 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
3315 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
3316 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
3317 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
3318 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
3319 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
3320 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
3321 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
3322 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
3323 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
3324 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
3325 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
3326 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
3327 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
3328 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
3329 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
3330 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
3331 1031.97,
3332 1035.09, 1038.21, 1041.33, 1044.45
3333 };
3334
3335 for (int ip = 0; ip < ctl->met_np; ip++)
3336 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3337
3338 } else if (4 == ctl->met_press_level_def) {
3339
3340 ctl->met_np = 101;
3341
3342 const double press[101] = {
3343 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
3344 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
3345 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
3346 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
3347 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
3348 113.6382,
3349 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
3350 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
3351 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
3352 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
3353 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
3354 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
3355 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
3356 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
3357 1028.85, 1031.97,
3358 1035.09, 1038.21, 1041.33, 1044.45
3359 };
3360
3361 for (int ip = 0; ip < ctl->met_np; ip++)
3362 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3363
3364 } else if (5 == ctl->met_press_level_def) {
3365
3366 ctl->met_np = 62;
3367
3368 const double press[62] = {
3369 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
3370 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
3371 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
3372 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
3373 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
3374 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
3375 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
3376 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
3377 1044.45
3378 };
3379
3380 for (int ip = 0; ip < ctl->met_np; ip++)
3381 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3382
3383 } else if (6 == ctl->met_press_level_def) {
3384
3385 ctl->met_np = 137;
3386
3387 const double press[137] = {
3388 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
3389 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
3390 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
3391 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
3392 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
3393 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
3394 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
3395 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
3396 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
3397 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
3398 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
3399 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
3400 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
3401 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
3402 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
3403 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
3404 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
3405 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
3406 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
3407 1030.06, 1037.25, 1044.45
3408 };
3409
3410 for (int ip = 0; ip < ctl->met_np; ip++)
3411 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3412
3413 } else if (7 == ctl->met_press_level_def) {
3414
3415 ctl->met_np = 59;
3416
3417 const double press[59] = {
3418 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
3419 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
3420 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
3421 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
3422 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
3423 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
3424 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
3425 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
3426 1028.53, 1046.13
3427 };
3428
3429 for (int ip = 0; ip < ctl->met_np; ip++)
3430 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
3431
3432 } else {
3433 ERRMSG("Use values between 3 and 7.");
3434 }
3435
3436 if (ctl->met_np > EP)
3437 ERRMSG("Recompile with larger EP to use this pressure level definition!");
3438}
3439
3440/*****************************************************************************/
3441
3443 const double *xx,
3444 const int n,
3445 const double x) {
3446
3447 int ilo = 0;
3448 int ihi = n - 1;
3449 int i = (ihi + ilo) >> 1;
3450
3451 if (xx[i] < xx[i + 1])
3452 while (ihi > ilo + 1) {
3453 i = (ihi + ilo) >> 1;
3454 if (xx[i] > x)
3455 ihi = i;
3456 else
3457 ilo = i;
3458 } else
3459 while (ihi > ilo + 1) {
3460 i = (ihi + ilo) >> 1;
3461 if (xx[i] <= x)
3462 ihi = i;
3463 else
3464 ilo = i;
3465 }
3466
3467 return ilo;
3468}
3469
3470/*****************************************************************************/
3471
3473 const float *xx,
3474 const int n,
3475 const double x,
3476 const int ig) {
3477
3478 int ilo = 0;
3479 int ihi = n - 1;
3480 int i = (ihi + ilo) >> 1;
3481
3482 if ((xx[ig] <= x && x < xx[ig + 1]) || (xx[ig] >= x && x > xx[ig + 1]))
3483 return ig;
3484
3485 if (xx[i] < xx[i + 1])
3486 while (ihi > ilo + 1) {
3487 i = (ihi + ilo) >> 1;
3488 if (xx[i] > x)
3489 ihi = i;
3490 else
3491 ilo = i;
3492 } else
3493 while (ihi > ilo + 1) {
3494 i = (ihi + ilo) >> 1;
3495 if (xx[i] <= x)
3496 ihi = i;
3497 else
3498 ilo = i;
3499 }
3500
3501 return ilo;
3502}
3503
3504/*****************************************************************************/
3505
3507 const double *xx,
3508 const int n,
3509 const double x) {
3510
3511 /* Calculate index... */
3512 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
3513
3514 /* Check range... */
3515 if (i < 0)
3516 return 0;
3517 else if (i > n - 2)
3518 return n - 2;
3519 else
3520 return i;
3521}
3522
3523/*****************************************************************************/
3524
3526 float profiles[EX][EY][EP],
3527 const int np,
3528 const int lon_ap_ind,
3529 const int lat_ap_ind,
3530 const double height_ap,
3531 int *ind) {
3532
3533 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
3534 np, height_ap, 0);
3535 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
3536 np, height_ap, ind[0]);
3537 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
3538 np, height_ap, ind[1]);
3539 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
3540 np, height_ap, ind[2]);
3541}
3542
3543/*****************************************************************************/
3544
3546 const ctl_t *ctl,
3547 const cache_t *cache,
3548 met_t *met0,
3549 met_t *met1,
3550 atm_t *atm) {
3551
3552 /* Set timer... */
3553 SELECT_TIMER("MODULE_ADVECT", "PHYSICS");
3554
3555 /* Use omega vertical velocity... */
3556 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
3557
3558 /* Loop over particles... */
3559 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3560
3561 /* Init... */
3563 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
3564 x[3] = { 0, 0, 0 };
3565
3566 /* Loop over integration nodes... */
3567 for (int i = 0; i < ctl->advect; i++) {
3568
3569 /* Set position... */
3570 if (i == 0) {
3571 dts = 0.0;
3572 x[0] = atm->lon[ip];
3573 x[1] = atm->lat[ip];
3574 x[2] = atm->p[ip];
3575 } else {
3576 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3577 x[0] = atm->lon[ip] + DX2COORD(met0, dts * u[i - 1], atm->lat[ip]);
3578 x[1] = atm->lat[ip] + DY2COORD(met0, dts * v[i - 1]);
3579 x[2] = atm->p[ip] + dts * w[i - 1];
3580 }
3581 const double tm = atm->time[ip] + dts;
3582
3583 /* Interpolate meteo data on pressure levels... */
3584 if (ctl->advect_vert_coord == 0) {
3585 intpol_met_time_3d(met0, met0->u, met1, met1->u,
3586 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3587 intpol_met_time_3d(met0, met0->v, met1, met1->v,
3588 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3589 intpol_met_time_3d(met0, met0->w, met1, met1->w,
3590 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3591 }
3592
3593 /* Interpolate meteo data on model levels... */
3594 else {
3595 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
3596 met1, met1->pl, met1->ul,
3597 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3598 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
3599 met1, met1->pl, met1->vl,
3600 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3601 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
3602 met1, met1->pl, met1->wl,
3603 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
3604 }
3605
3606 /* Get mean wind... */
3607 double k = 1.0;
3608 if (ctl->advect == 2)
3609 k = (i == 0 ? 0.0 : 1.0);
3610 else if (ctl->advect == 4)
3611 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3612 um += k * u[i];
3613 vm += k * v[i];
3614 wm += k * w[i];
3615 }
3616
3617 /* Set new position... */
3618 atm->time[ip] += cache->dt[ip];
3619 atm->lon[ip] += DX2COORD(met0, cache->dt[ip] * um,
3620 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3621 atm->lat[ip] += DY2COORD(met0, cache->dt[ip] * vm);
3622 atm->p[ip] += cache->dt[ip] * wm;
3623 }
3624 }
3625
3626 /* Use zeta or eta vertical velocity... */
3627 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
3628
3629 /* Select quantity index depending on coordinate... */
3630 const int qnt = (ctl->advect_vert_coord == 1
3631 ? ctl->qnt_zeta : ctl->qnt_eta);
3632
3633 /* Loop over particles... */
3634 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3635
3636 /* Convert pressure to vertical coordinate (zeta or eta)... */
3638 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
3639 met1, met1->pl, met1->zetal,
3640 atm->time[ip], atm->p[ip],
3641 atm->lon[ip], atm->lat[ip],
3642 &atm->q[qnt][ip], ci, cw, 1);
3643
3644 /* Init... */
3645 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
3646 wdotm = 0, x[3] = { 0, 0, 0 };
3647
3648 /* Loop over integration nodes (Runge–Kutta steps)... */
3649 for (int i = 0; i < ctl->advect; i++) {
3650
3651 /* Set position... */
3652 if (i == 0) {
3653 dts = 0.0;
3654 x[0] = atm->lon[ip];
3655 x[1] = atm->lat[ip];
3656 x[2] = atm->q[qnt][ip];
3657 } else {
3658 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3659 x[0] = atm->lon[ip] + DX2COORD(met0, dts * u[i - 1], atm->lat[ip]);
3660 x[1] = atm->lat[ip] + DY2COORD(met0, dts * v[i - 1]);
3661 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
3662 }
3663
3664 const double tm = atm->time[ip] + dts;
3665
3666 /* Interpolate meteo data... */
3667 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
3668 met1, met1->zetal, met1->ul,
3669 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3670 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
3671 met1, met1->zetal, met1->vl,
3672 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3673 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
3674 met1, met1->zetal, met1->zeta_dotl,
3675 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
3676
3677 /* Compute Runge–Kutta weights... */
3678 double k = 1.0;
3679 if (ctl->advect == 2)
3680 k = (i == 0 ? 0.0 : 1.0);
3681 else if (ctl->advect == 4)
3682 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3683
3684 um += k * u[i];
3685 vm += k * v[i];
3686 wdotm += k * wdot[i];
3687 }
3688
3689 /* Update particle position... */
3690 atm->time[ip] += cache->dt[ip];
3691 atm->lon[ip] += DX2COORD(met0, cache->dt[ip] * um,
3692 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3693 atm->lat[ip] += DY2COORD(met0, cache->dt[ip] * vm);
3694 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
3695
3696 /* Convert vertical coordinate (zeta or eta) back to pressure... */
3697 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
3698 met1, met1->zetal, met1->pl,
3699 atm->time[ip],
3700 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
3701 &atm->p[ip], ci, cw, 1);
3702 }
3703 }
3704}
3705
3706/*****************************************************************************/
3707
3709 const ctl_t *ctl,
3710 const cache_t *cache,
3711 met_t *met0,
3712 met_t *met1,
3713 atm_t *atm) {
3714
3715 /* Check parameters... */
3716 if (ctl->advect_vert_coord != 1)
3717 return;
3718
3719 /* Set timer... */
3720 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS");
3721
3722 /* Loop over particles... */
3723 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
3724
3725 /* Initialize pressure consistent with zeta... */
3727 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
3728 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
3729 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
3730 }
3731}
3732
3733/*****************************************************************************/
3734
3736 const ctl_t *ctl,
3737 const cache_t *cache,
3738 const clim_t *clim,
3739 met_t *met0,
3740 met_t *met1,
3741 atm_t *atm) {
3742
3743 /* Set timer... */
3744 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS");
3745
3746 /* Check quantity flags... */
3747 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
3748 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
3749 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
3750 return;
3751
3752 /* Loop over particles... */
3753 PARTICLE_LOOP(0, atm->np, 1,
3754 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3755
3756 /* Check latitude and pressure range... */
3757 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
3758 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
3759 continue;
3760
3761 /* Check surface layer... */
3762 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
3763 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
3764
3765 /* Get surface pressure... */
3766 double ps;
3768 INTPOL_2D(ps, 1);
3769
3770 /* Check pressure... */
3771 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
3772 continue;
3773
3774 /* Check height... */
3775 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
3776 continue;
3777
3778 /* Check zeta range... */
3779 if (ctl->bound_zetas > 0) {
3780 double t;
3781 INTPOL_3D(t, 1);
3782 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
3783 continue;
3784 }
3785
3786 /* Check planetary boundary layer... */
3787 if (ctl->bound_pbl) {
3788 double pbl;
3789 INTPOL_2D(pbl, 0);
3790 if (atm->p[ip] < pbl)
3791 continue;
3792 }
3793 }
3794
3795 /* Set mass and volume mixing ratio... */
3796 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
3797 atm->q[ctl->qnt_m][ip] =
3798 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
3799 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
3800 atm->q[ctl->qnt_vmr][ip] =
3801 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
3802
3803 /* Set CFC-10 volume mixing ratio... */
3804 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
3805 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
3806
3807 /* Set CFC-11 volume mixing ratio... */
3808 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
3809 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
3810
3811 /* Set CFC-12 volume mixing ratio... */
3812 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
3813 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
3814
3815 /* Set N2O volume mixing ratio... */
3816 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
3817 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
3818
3819 /* Set SF6 volume mixing ratio... */
3820 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
3821 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
3822
3823 /* Set age of air... */
3824 if (ctl->qnt_aoa >= 0)
3825 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
3826 }
3827}
3828
3829/*****************************************************************************/
3830
3832 const ctl_t *ctl,
3833 met_t *met0,
3834 met_t *met1,
3835 atm_t *atm,
3836 const double tt) {
3837
3838 if (met0->coord_type != 0)
3839 ERRMSG("Only lat/lon grid supported");
3840
3841 /* Check quantities... */
3842 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
3843 return;
3844 if (ctl->molmass <= 0)
3845 ERRMSG("Molar mass is not defined!");
3846
3847 /* Set timer... */
3848 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS");
3849
3850 /* Allocate... */
3851 const int ensemble_mode = (ctl->nens > 0);
3852 const int np = atm->np;
3853 const int nz = ctl->chemgrid_nz;
3854 const int nx = ctl->chemgrid_nx;
3855 const int ny = ctl->chemgrid_ny;
3856 const int ngrid = nx * ny * nz;
3857 const int nens = ensemble_mode ? ctl->nens : 1;
3858
3859 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
3860 double *restrict const press =
3861 (double *) malloc((size_t) nz * sizeof(double));
3862 double *restrict const mass =
3863 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
3864 double *restrict const area =
3865 (double *) malloc((size_t) ny * sizeof(double));
3866 double *restrict const lon =
3867 (double *) malloc((size_t) nx * sizeof(double));
3868 double *restrict const lat =
3869 (double *) malloc((size_t) ny * sizeof(double));
3870
3871 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3872 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3873 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3874
3875 /* Set grid box size... */
3876 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
3877 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
3878 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
3879
3880 /* Set vertical coordinates... */
3881#ifdef _OPENACC
3882#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])
3883#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
3884#pragma acc parallel loop independent gang vector
3885#else
3886#pragma omp parallel for default(shared)
3887#endif
3888 for (int iz = 0; iz < nz; iz++) {
3889 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
3890 press[iz] = P(z[iz]);
3891 }
3892
3893 /* Set time interval for output... */
3894 const double t0 = tt - 0.5 * ctl->dt_mod;
3895 const double t1 = tt + 0.5 * ctl->dt_mod;
3896
3897 /* Get indices... */
3898#ifdef _OPENACC
3899#pragma acc parallel loop independent gang vector
3900#else
3901#pragma omp parallel for default(shared)
3902#endif
3903 for (int ip = 0; ip < np; ip++) {
3904 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
3905 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
3906 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
3907 if (atm->time[ip] < t0 || atm->time[ip] > t1
3908 || ixs[ip] < 0 || ixs[ip] >= nx
3909 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
3910 izs[ip] = -1;
3911 }
3912
3913 /* Set horizontal coordinates... */
3914#ifdef _OPENACC
3915#pragma acc parallel loop independent gang vector
3916#else
3917#pragma omp parallel for default(shared)
3918#endif
3919 for (int ix = 0; ix < nx; ix++)
3920 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3921
3922#ifdef _OPENACC
3923#pragma acc parallel loop independent gang vector
3924#else
3925#pragma omp parallel for default(shared)
3926#endif
3927 for (int iy = 0; iy < ny; iy++) {
3928 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3929 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3930 }
3931
3932 /* Get mass per grid box... */
3933#ifdef _OPENACC
3934#pragma acc parallel loop independent gang vector
3935#endif
3936 for (int ip = 0; ip < np; ip++) {
3937 if (izs[ip] >= 0) {
3938 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3939 if (ensemble_mode) {
3940 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3941 mass_idx += ens * ngrid;
3942 }
3943#ifdef _OPENACC
3944#pragma acc atomic update
3945#endif
3946 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
3947 }
3948 }
3949
3950 /* Assign grid data to air parcels ... */
3951#ifdef _OPENACC
3952#pragma acc parallel loop independent gang vector
3953#else
3954#pragma omp parallel for default(shared)
3955#endif
3956 for (int ip = 0; ip < np; ip++)
3957 if (izs[ip] >= 0) {
3958
3959 /* Interpolate temperature... */
3960 double temp;
3962 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
3963 press[izs[ip]],
3964 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
3965
3966 /* Set mass... */
3967 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3968 if (ensemble_mode) {
3969 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3970 mass_idx += ens * ngrid;
3971 }
3972
3973 /* Calculate volume mixing ratio... */
3974 const double m = mass[mass_idx];
3975 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
3976 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
3977 }
3978
3979 /* Free... */
3980#ifdef _OPENACC
3981#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
3982#endif
3983 free(mass);
3984 free(lon);
3985 free(lat);
3986 free(area);
3987 free(z);
3988 free(press);
3989 free(ixs);
3990 free(iys);
3991 free(izs);
3992}
3993
3994/*****************************************************************************/
3995
3997 const ctl_t *ctl,
3998 const cache_t *cache,
3999 const clim_t *clim,
4000 met_t *met0,
4001 met_t *met1,
4002 atm_t *atm) {
4003
4004 /* Set timer... */
4005 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS");
4006
4007 /* Loop over particles... */
4008 PARTICLE_LOOP(0, atm->np, 0,
4009 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4010
4011 /* Set H2O and O3 using meteo data... */
4013 if (ctl->qnt_Ch2o >= 0) {
4014 double h2o;
4015 INTPOL_3D(h2o, 1);
4016 SET_ATM(qnt_Ch2o, h2o);
4017 }
4018 if (ctl->qnt_Co3 >= 0) {
4019 double o3;
4020 INTPOL_3D(o3, 1);
4021 SET_ATM(qnt_Co3, o3);
4022 }
4023
4024 /* Set radical species... */
4025 const double lat_ref =
4026 ctl->met_coord_type == 0 ? atm->lat[ip] : ctl->met_utm_ref_lat;
4027 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
4028 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4029 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
4030 lat_ref, atm->p[ip]));
4031 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
4032 lat_ref, atm->p[ip]));
4033 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
4034 lat_ref, atm->p[ip]));
4035 }
4036}
4037
4038/*****************************************************************************/
4039
4041 const ctl_t *ctl,
4042 cache_t *cache,
4043 met_t *met0,
4044 met_t *met1,
4045 atm_t *atm) {
4046
4047 /* Set timer... */
4048 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS");
4049
4050 /* Create random numbers... */
4051 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
4052
4053 /* Loop over particles... */
4054 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4055
4056 /* Interpolate surface pressure... */
4057 double ps;
4059 INTPOL_2D(ps, 1);
4060
4061 /* Initialize pressure range for vertical mixing... */
4062 double pbot = ps, ptop = ps;
4063
4064 /* Mixing in the PBL... */
4065 if (ctl->conv_mix_pbl) {
4066
4067 /* Interpolate PBL... */
4068 double pbl;
4069 INTPOL_2D(pbl, 0);
4070
4071 /* Set pressure range... */
4072 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
4073 }
4074
4075 /* Convective mixing... */
4076 if (ctl->conv_cape >= 0) {
4077
4078 /* Interpolate CAPE, CIN, and equilibrium level... */
4079 double cape, cin, pel;
4080 INTPOL_2D(cape, 0);
4081 INTPOL_2D(cin, 0);
4082 INTPOL_2D(pel, 0);
4083
4084 /* Set pressure range... */
4085 if (isfinite(cape) && cape >= ctl->conv_cape
4086 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
4087 ptop = GSL_MIN(ptop, pel);
4088 }
4089
4090 /* Apply vertical mixing... */
4091 if (ptop != pbot && atm->p[ip] >= ptop) {
4092
4093 /* Get density range... */
4094 double tbot, ttop;
4095 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
4096 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
4097 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
4098 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
4099 const double rhobot = pbot / tbot;
4100 const double rhotop = ptop / ttop;
4101
4102 /* Get new density... */
4103 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
4104
4105 /* Get pressure... */
4106 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
4107 }
4108 }
4109}
4110
4111/*****************************************************************************/
4112
4113#ifdef DD
4114void module_dd(
4115 const ctl_t *ctl,
4116 cache_t *cache,
4117 dd_t *dd,
4118 atm_t *atm,
4119 met_t **met) {
4120
4121 /* Initialize particles locally... */
4122 int npart = 0, capacity = 0;
4123 particle_t *particles = NULL;
4124
4125 /* Assign particles to new subdomains... */
4126 dd_assign_subdomains(ctl, dd, atm, 0);
4127
4128 /* Sort particles according to location and target rank... */
4129 if (fmod(t, ctl->dd_sort_dt) == 0)
4130 dd_sort(ctl, *met, atm, dd, &npart);
4131 else
4132 dd_push(ctl, atm, cache, &npart);
4133
4134 /* Ensure particle buffer is large enough for outgoing particles... */
4135 if (npart > capacity) {
4136 const int newcap = npart + npart / 2 + 1;
4137 particle_t *tmp =
4138 realloc(particles, (size_t) newcap * sizeof(particle_t));
4139 if (!tmp)
4140 ERRMSG("Out of memory!");
4141 particles = tmp;
4142 capacity = newcap;
4143 }
4144
4145 /* Transform from struct of array to array of struct... */
4146 dd_atm2particles(ctl, cache, atm, particles, npart);
4147
4148 SELECT_TIMER("SYNC", "DD");
4149 MPI_Barrier(MPI_COMM_WORLD);
4150
4151 /* Perform the communication... */
4152 dd_communicate_particles(ctl, dd, &particles, &npart, &capacity);
4153
4154 /* Transform from array of struct to struct of array... */
4155 dd_particles2atm(ctl, cache, particles, npart, atm);
4156
4157 /* Free local particle array... */
4158 free(particles);
4159}
4160#endif
4161
4162/*****************************************************************************/
4163
4165 const ctl_t *ctl,
4166 const cache_t *cache,
4167 const clim_t *clim,
4168 atm_t *atm) {
4169
4170 /* Set timer... */
4171 SELECT_TIMER("MODULE_DECAY", "PHYSICS");
4172
4173 /* Check quantity flags... */
4174 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4175 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4176
4177 /* Loop over particles... */
4178 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
4179
4180 /* Get weighting factor... */
4181 const double w = tropo_weight(ctl, clim, atm, ip);
4182
4183 /* Set lifetime... */
4184 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
4185
4186 /* Calculate exponential decay... */
4187 const double aux = exp(-cache->dt[ip] / tdec);
4188 if (ctl->qnt_m >= 0) {
4189 if (ctl->qnt_mloss_decay >= 0)
4190 atm->q[ctl->qnt_mloss_decay][ip]
4191 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4192 atm->q[ctl->qnt_m][ip] *= aux;
4193 if (ctl->qnt_loss_rate >= 0)
4194 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
4195 }
4196 if (ctl->qnt_vmr >= 0)
4197 atm->q[ctl->qnt_vmr][ip] *= aux;
4198 }
4199}
4200
4201/*****************************************************************************/
4202
4204 const ctl_t *ctl,
4205 cache_t *cache,
4206 met_t *met0,
4207 met_t *met1,
4208 atm_t *atm) {
4209
4210 /* Set timer... */
4211 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS");
4212
4213 /* Create random numbers... */
4214 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4215
4216 /* Loop over particles... */
4217 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4218
4219 /* Get indices... */
4220 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
4221 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
4222 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
4223
4224 /* Get standard deviations of local wind data... */
4225 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
4226 for (int i = 0; i < 2; i++)
4227 for (int j = 0; j < 2; j++)
4228 for (int k = 0; k < 2; k++) {
4229 umean += met0->u[ix + i][iy + j][iz + k];
4230 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
4231 vmean += met0->v[ix + i][iy + j][iz + k];
4232 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
4233 wmean += met0->w[ix + i][iy + j][iz + k];
4234 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
4235
4236 umean += met1->u[ix + i][iy + j][iz + k];
4237 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
4238 vmean += met1->v[ix + i][iy + j][iz + k];
4239 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
4240 wmean += met1->w[ix + i][iy + j][iz + k];
4241 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
4242 }
4243 usig = usig / 16.f - SQR(umean / 16.f);
4244 usig = (usig > 0 ? sqrtf(usig) : 0);
4245 vsig = vsig / 16.f - SQR(vmean / 16.f);
4246 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
4247 wsig = wsig / 16.f - SQR(wmean / 16.f);
4248 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
4249
4250 /* Set temporal correlations for mesoscale fluctuations... */
4251 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
4252 const double r2 = sqrt(1 - r * r);
4253
4254 /* Calculate horizontal mesoscale wind fluctuations... */
4255 if (ctl->turb_mesox > 0) {
4256 cache->uvwp[ip][0] =
4257 (float) (r * cache->uvwp[ip][0] +
4258 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
4259 atm->lon[ip] +=
4260 DX2COORD(met0, cache->uvwp[ip][0] * cache->dt[ip], atm->lat[ip]);
4261
4262 cache->uvwp[ip][1] =
4263 (float) (r * cache->uvwp[ip][1] +
4264 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
4265 atm->lat[ip] += DY2COORD(met0, cache->uvwp[ip][1] * cache->dt[ip]);
4266 }
4267
4268 /* Calculate vertical mesoscale wind fluctuations... */
4269 if (ctl->turb_mesoz > 0) {
4270 cache->uvwp[ip][2] =
4271 (float) (r * cache->uvwp[ip][2] +
4272 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
4273 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
4274 }
4275 }
4276}
4277
4278/*****************************************************************************/
4279
4281 const ctl_t *ctl,
4282 cache_t *cache,
4283 met_t *met0,
4284 met_t *met1,
4285 atm_t *atm) {
4286
4287 /* Set timer... */
4288 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS");
4289
4290 /* Create random numbers... */
4291 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4292
4293 /* Loop over particles... */
4294 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4295
4296 double pbl, ps, dsigw_dz = 0.0, sig_u, sig_w, tau_u, tau_w;
4297
4298 /* Get PBL pressure... */
4300 INTPOL_2D(pbl, 1);
4301
4302 /* Let the background diffusion scheme handle particles above the PBL. */
4303 if (atm->p[ip] < pbl)
4304 continue;
4305
4306 /* Get surface pressure... */
4307 INTPOL_2D(ps, 0);
4308
4309 /* Calculate heights... */
4310 const double p = MIN(atm->p[ip], ps);
4311 const double zs = Z(ps);
4312 const double z = 1e3 * (Z(p) - zs);
4313 const double zi = 1e3 * (Z(pbl) - zs);
4314 const double zratio = z / zi;
4315
4316 /* Calculate friction velocity... */
4317 double ess, nss, h2o, t;
4318 INTPOL_2D(ess, 0);
4319 INTPOL_2D(nss, 0);
4320 INTPOL_3D(t, 1);
4321 INTPOL_3D(h2o, 0);
4322 const double thetav = THETAVIRT(p, t, h2o);
4323 const double rho = RHO(p, TVIRT(t, h2o));
4324 const double tau = sqrt(SQR(ess) + SQR(nss));
4325 const double ustar = sqrt(tau / rho);
4326 const double ust = MAX(1e-4, ustar);
4327 const double zeta = MAX(zratio, 1e-6);
4328 const double z_m = MAX(z, 1.0);
4329
4330 /* Get surface sensible heat flux... */
4331 double shf;
4332 INTPOL_2D(shf, 1);
4333
4334 /* Estimate Monin-Obukhov length to distinguish
4335 neutral, stable, and unstable cases. */
4336 double ol = 1e12;
4337 if (fabs(shf) > 1e-6 && ust > 0.0)
4338 ol = thetav * rho * CPD * (ust * ust * ust) / (KARMAN * G0 * shf);
4339
4340 /* Neutral conditions... */
4341 if (zi / fabs(ol) < 1.0) {
4342 const double corr = z_m / ust;
4343 const double sigw0 = 1.3 * ust * exp(-2e-4 * corr);
4344 sig_u = 1e-2 + 2.0 * ust * exp(-3e-4 * corr);
4345 sig_w = 1e-2 + sigw0;
4346 dsigw_dz = -2e-4 * sigw0;
4347 tau_u = 0.5 * z_m / sig_w / (1.0 + 1.5e-3 * corr);
4348 tau_w = tau_u;
4349 }
4350
4351 /* Unstable conditions... */
4352 else if (ol < 0.0) {
4353
4354 /* Convective velocity... */
4355 const double wstar =
4356 pow(-G0 / thetav * shf / (rho * CPD) * zi, 1. / 3.);
4357
4358 /* Hanna/FLEXPART turbulent velocity variances... */
4359 sig_u = 1e-2 + ust * pow(12.0 - 0.5 * zi / ol, 1.0 / 3.0);
4360 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zeta)
4361 * pow(zeta, 2.0 / 3.0)
4362 + (1.8 - 1.4 * zeta) * SQR(ust));
4363
4364 /* Calculate derivative dsig_w/dz... */
4365 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ust)
4366 + SQR(wstar) *
4367 (0.8 * pow(MAX(zeta, 1e-3), -1.0 / 3.0)
4368 - 1.8 * pow(zeta, 2.0 / 3.0)));
4369
4370 /* Hanna/FLEXPART Lagrangian timescales... */
4371 tau_u = 0.15 * zi / sig_u;
4372 if (z_m < fabs(ol))
4373 tau_w = 0.1 * z_m / (sig_w * (0.55 - 0.38 * fabs(z_m / ol)));
4374 else if (zeta < 0.1)
4375 tau_w = 0.59 * z_m / sig_w;
4376 else
4377 tau_w = 0.15 * zi / sig_w * (1.0 - exp(-5.0 * zeta));
4378 }
4379
4380 /* Stable conditions... */
4381 else {
4382 sig_u = 1e-2 + 2.0 * ust * (1.0 - zeta);
4383 sig_w = 1e-2 + 1.3 * ust * (1.0 - zeta);
4384 dsigw_dz = -1.3 * ust / zi;
4385 tau_u = 0.15 * zi / sig_u * sqrt(zeta);
4386 tau_w = 0.1 * zi / sig_w * pow(zeta, 0.8);
4387 }
4388
4389 /* Apply lower bounds for numerical robustness... */
4390 sig_u = MAX(sig_u, 0.25);
4391 sig_w = MAX(sig_w, 0.1);
4392 tau_u = MAX(tau_u, 10.);
4393 tau_w = MAX(tau_w, 30.);
4394
4395 /* Update perturbations... */
4396 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
4397 const double ru2 = sqrt(1.0 - SQR(ru));
4398 cache->uvwp[ip][0]
4399 = (float) (cache->uvwp[ip][0] * ru + sig_u * ru2 * cache->rs[3 * ip]);
4400 cache->uvwp[ip][1]
4401 = (float) (cache->uvwp[ip][1] * ru
4402 + sig_u * ru2 * cache->rs[3 * ip + 1]);
4403
4404 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
4405 const double rw2 = sqrt(1.0 - SQR(rw));
4406 const double dsigw2_dz = 2.0 * sig_w * dsigw_dz;
4407 const double rhoaux = -1.0 / (1e3 * H0);
4408 cache->uvwp[ip][2]
4409 = (float) (cache->uvwp[ip][2] * rw + sig_w * rw2 * cache->rs[3 * ip + 2]
4410 + tau_w * (1.0 - rw) * (dsigw2_dz + rhoaux * SQR(sig_w)));
4411
4412 /* Calculate new air parcel position... */
4413 atm->lon[ip] +=
4414 DX2COORD(met0, cache->uvwp[ip][0] * cache->dt[ip], atm->lat[ip]);
4415 atm->lat[ip] += DY2COORD(met0, cache->uvwp[ip][1] * cache->dt[ip]);
4416
4417 /* Calculate new air parcel height... */
4418 double znew = z + cache->uvwp[ip][2] * cache->dt[ip];
4419 while (znew < 0.0 || znew > zi) {
4420 if (znew < 0.0)
4421 znew = -znew;
4422 if (znew > zi)
4423 znew = 2.0 * zi - znew;
4424 }
4425 atm->p[ip] += DZ2DP((znew - z) / 1000., atm->p[ip]);
4426 }
4427}
4428
4429/*****************************************************************************/
4430
4432 const ctl_t *ctl,
4433 cache_t *cache,
4434 const clim_t *clim,
4435 met_t *met0,
4436 met_t *met1,
4437 atm_t *atm) {
4438
4439 /* Set timer... */
4440 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS");
4441
4442 /* Create random numbers... */
4443 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
4444
4445 /* Loop over particles... */
4446 PARTICLE_LOOP(0, atm->np, 1,
4447 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4448
4449 /* Get PBL and surface pressure... */
4450 double pbl, ps;
4452 INTPOL_2D(pbl, 1);
4453 INTPOL_2D(ps, 0);
4454
4455 /* Let optional PBL closure schemes handle turbulent diffusion inside the PBL. */
4456 if (ctl->turb_pbl_scheme > 0 && atm->p[ip] >= pbl)
4457 continue;
4458
4459 /* Get weighting factors... */
4460 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
4461 const double wtrop = tropo_weight(ctl, clim, atm, ip) * (1.0 - wpbl);
4462 const double wstrat = 1.0 - wpbl - wtrop;
4463
4464 /* Set diffusivity... */
4465 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
4466 + wstrat * ctl->turb_dx_strat;
4467 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
4468 + wstrat * ctl->turb_dz_strat;
4469
4470 /* Horizontal turbulent diffusion... */
4471 if (dx > 0) {
4472 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip]));
4473 atm->lon[ip] += DX2COORD(met0, cache->rs[3 * ip] * sigma, atm->lat[ip]);
4474 atm->lat[ip] += DY2COORD(met0, cache->rs[3 * ip + 1] * sigma);
4475 }
4476
4477 /* Vertical turbulent diffusion... */
4478 if (dz > 0) {
4479 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
4480 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
4481 }
4482 }
4483}
4484
4485/*****************************************************************************/
4486
4488 const ctl_t *ctl,
4489 const cache_t *cache,
4490 met_t *met0,
4491 met_t *met1,
4492 atm_t *atm) {
4493
4494 /* Set timer... */
4495 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS");
4496
4497 /* Check quantity flags... */
4498 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4499 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4500
4501 /* Loop over particles... */
4502 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4503
4504 /* Get surface pressure... */
4505 double ps;
4507 INTPOL_2D(ps, 1);
4508
4509 /* Check whether particle is above the surface layer... */
4510 if (atm->p[ip] < ps - ctl->dry_depo_dp)
4511 continue;
4512
4513 /* Set depth of surface layer... */
4514 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
4515
4516 /* Calculate sedimentation velocity for particles... */
4517 double v_dep;
4518 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
4519
4520 /* Get temperature... */
4521 double t;
4522 INTPOL_3D(t, 1);
4523
4524 /* Set deposition velocity... */
4525 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4526 atm->q[ctl->qnt_rhop][ip]);
4527 }
4528
4529 /* Use explicit sedimentation velocity for gases... */
4530 else
4531 v_dep = ctl->dry_depo_vdep;
4532
4533 /* Calculate loss of mass based on deposition velocity... */
4534 const double aux = exp(-cache->dt[ip] * v_dep / dz);
4535 if (ctl->qnt_m >= 0) {
4536 if (ctl->qnt_mloss_dry >= 0)
4537 atm->q[ctl->qnt_mloss_dry][ip]
4538 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4539 atm->q[ctl->qnt_m][ip] *= aux;
4540 if (ctl->qnt_loss_rate >= 0)
4541 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
4542 }
4543 if (ctl->qnt_vmr >= 0)
4544 atm->q[ctl->qnt_vmr][ip] *= aux;
4545 }
4546}
4547
4548/*****************************************************************************/
4549
4551 const ctl_t *ctl,
4552 const cache_t *cache,
4553 const clim_t *clim,
4554 met_t *met0,
4555 met_t *met1,
4556 atm_t *atm) {
4557
4558 if (ctl->met_coord_type != 0)
4559 ERRMSG("Only lat/lon grid supported");
4560
4561 /* Set timer... */
4562 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS");
4563
4564 /* Check quantity flags... */
4565 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4566 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4567
4568 /* Parameter of SO2 correction... */
4569 const double a = 3.12541941e-06;
4570 const double b = -5.72532259e-01;
4571 const double low = pow(1. / a, 1. / b);
4572
4573 /* Loop over particles... */
4574 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4575
4576 /* Check whether particle is inside cloud... */
4577 double lwc, rwc;
4579 INTPOL_3D(lwc, 1);
4580 INTPOL_3D(rwc, 0);
4581 if (!(lwc > 0 || rwc > 0))
4582 continue;
4583
4584 /* Get temperature... */
4585 double t;
4586 INTPOL_3D(t, 0);
4587
4588 /* Get molecular density... */
4589 const double M = MOLEC_DENS(atm->p[ip], t);
4590
4591 /* Reaction rate (Berglen et al., 2004)... */
4592 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
4593
4594 /* Henry constant of SO2... */
4595 const double H_SO2 =
4596 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
4597 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
4598
4599 /* Henry constant of H2O2... */
4600 const double H_h2o2 =
4601 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
4602
4603 /* Correction factor for high SO2 concentration
4604 (if qnt_Cx is defined, the correction is switched on)... */
4605 double cor = 1.0;
4606 if (ctl->qnt_Cx >= 0)
4607 cor = atm->q[ctl->qnt_Cx][ip] >
4608 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
4609
4610 const double h2o2 = H_h2o2
4611 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
4612 * M * cor * 1000. / AVO; /* unit: mol/L */
4613
4614 /* Volume water content in cloud [m^3 m^(-3)]... */
4615 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
4616 const double CWC = (lwc + rwc) * rho_air / 1e3;
4617
4618 /* Calculate exponential decay (Rolph et al., 1992)... */
4619 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
4620 const double aux = exp(-cache->dt[ip] * rate_coef);
4621 if (ctl->qnt_m >= 0) {
4622 if (ctl->qnt_mloss_h2o2 >= 0)
4623 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
4624 atm->q[ctl->qnt_m][ip] *= aux;
4625 if (ctl->qnt_loss_rate >= 0)
4626 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4627 }
4628 if (ctl->qnt_vmr >= 0)
4629 atm->q[ctl->qnt_vmr][ip] *= aux;
4630 }
4631}
4632
4633/*****************************************************************************/
4634
4636 const ctl_t *ctl,
4637 cache_t *cache,
4638 met_t *met0,
4639 met_t *met1,
4640 atm_t *atm) {
4641
4642 double t;
4643
4644 /* Set timer... */
4645 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS");
4646
4647 /* Save pressure... */
4648 if (ctl->isosurf == 1) {
4649 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
4650 cache->iso_var[ip] = atm->p[ip];
4651 }
4652 }
4653
4654 /* Save density... */
4655 else if (ctl->isosurf == 2) {
4656 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4658 INTPOL_3D(t, 1);
4659 cache->iso_var[ip] = atm->p[ip] / t;
4660 }
4661 }
4662
4663 /* Save potential temperature... */
4664 else if (ctl->isosurf == 3) {
4665 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
4667 INTPOL_3D(t, 1);
4668 cache->iso_var[ip] = THETA(atm->p[ip], t);
4669 }
4670 }
4671
4672 /* Read balloon pressure data... */
4673 else if (ctl->isosurf == 4) {
4674
4675 /* Write info... */
4676 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
4677
4678 /* Open file... */
4679 FILE *in;
4680 if (!(in = fopen(ctl->balloon, "r")))
4681 ERRMSG("Cannot open file!");
4682
4683 /* Read pressure time series... */
4684 char line[LEN];
4685 while (fgets(line, LEN, in))
4686 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
4687 &(cache->iso_ps[cache->iso_n])) == 2)
4688 if ((++cache->iso_n) > NP)
4689 ERRMSG("Too many data points!");
4690
4691 /* Check number of points... */
4692 if (cache->iso_n < 1)
4693 ERRMSG("Could not read any data!");
4694
4695 /* Close file... */
4696 fclose(in);
4697
4698 /* Update of cache data on device... */
4699 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
4700 }
4701}
4702
4703/*****************************************************************************/
4704
4706 const ctl_t *ctl,
4707 const cache_t *cache,
4708 met_t *met0,
4709 met_t *met1,
4710 atm_t *atm) {
4711
4712 /* Set timer... */
4713 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS");
4714
4715 /* Loop over particles... */
4716 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
4717
4718 /* Init... */
4719 double t;
4721
4722 /* Restore pressure... */
4723 if (ctl->isosurf == 1)
4724 atm->p[ip] = cache->iso_var[ip];
4725
4726 /* Restore density... */
4727 else if (ctl->isosurf == 2) {
4728 INTPOL_3D(t, 1);
4729 atm->p[ip] = cache->iso_var[ip] * t;
4730 }
4731
4732 /* Restore potential temperature... */
4733 else if (ctl->isosurf == 3) {
4734 INTPOL_3D(t, 1);
4735 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
4736 }
4737
4738 /* Interpolate pressure... */
4739 else if (ctl->isosurf == 4) {
4740 if (atm->time[ip] <= cache->iso_ts[0])
4741 atm->p[ip] = cache->iso_ps[0];
4742 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
4743 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
4744 else {
4745 const int idx =
4746 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
4747 atm->p[ip] =
4748 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
4749 cache->iso_ps[idx + 1], atm->time[ip]);
4750 }
4751 }
4752 }
4753}
4754
4755/*****************************************************************************/
4756
4757#ifdef KPP
4758void module_kpp_chem(
4759 ctl_t *ctl,
4760 cache_t *cache,
4761 clim_t *clim,
4762 met_t *met0,
4763 met_t *met1,
4764 atm_t *atm) {
4765
4766 /* Set timer... */
4767 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS");
4768
4769 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
4770 double rtol[1] = { 1.0e-3 };
4771 double atol[1] = { 1.0 };
4772
4773 /* Loop over particles... */
4774#ifdef _OPENACC
4775#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
4776#endif
4777 PARTICLE_LOOP(0, atm->np, 1,
4778 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
4779
4780 /* Initialize... */
4781 double var[nvar], fix[nfix], rconst[nreact];
4782 for (int i = 0; i < nvar; i++)
4783 var[i] = 0.0;
4784 for (int i = 0; i < nfix; i++)
4785 fix[i] = 0.0;
4786 for (int i = 0; i < nreact; i++)
4787 rconst[i] = 0.0;
4788 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
4789
4790 /* Integrate... */
4791 double rpar[20];
4792 int ipar[20];
4793 for (int i = 0; i < 20; i++) {
4794 ipar[i] = 0;
4795 rpar[i] = 0.0;
4796 }
4797 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) */
4798 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
4799 ipar[3] = 4; /* choice of the method:Rodas3 */
4800 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
4801 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
4802
4803 /* Save results.. */
4804 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
4805 }
4806}
4807#endif
4808
4809/*****************************************************************************/
4810
4812 const ctl_t *ctl,
4813 const cache_t *cache,
4814 const clim_t *clim,
4815 met_t *met0,
4816 met_t *met1,
4817 atm_t *atm) {
4818
4819 /* Set timer... */
4820 SELECT_TIMER("MODULE_METEO", "PHYSICS");
4821
4822 /* Check quantity flags... */
4823 if (ctl->qnt_tsts >= 0)
4824 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
4825 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
4826
4827 /* Loop over particles... */
4828 PARTICLE_LOOP(0, atm->np, 0,
4829 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4830
4831 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
4832 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
4833 o3, lwc, rwc, iwc, swc, cc, z, zt;
4834
4835 /* Interpolate meteo data... */
4837 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
4838
4839 /* Set quantities... */
4840 SET_ATM(qnt_ps, ps);
4841 SET_ATM(qnt_ts, ts);
4842 SET_ATM(qnt_zs, zs);
4843 SET_ATM(qnt_us, us);
4844 SET_ATM(qnt_vs, vs);
4845 SET_ATM(qnt_ess, ess);
4846 SET_ATM(qnt_nss, nss);
4847 SET_ATM(qnt_shf, shf);
4848 SET_ATM(qnt_lsm, lsm);
4849 SET_ATM(qnt_sst, sst);
4850 SET_ATM(qnt_pbl, pbl);
4851 SET_ATM(qnt_pt, pt);
4852 SET_ATM(qnt_tt, tt);
4853 SET_ATM(qnt_zt, zt);
4854 SET_ATM(qnt_h2ot, h2ot);
4855 SET_ATM(qnt_zg, z);
4856 SET_ATM(qnt_p, atm->p[ip]);
4857 SET_ATM(qnt_t, t);
4858 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
4859 SET_ATM(qnt_u, u);
4860 SET_ATM(qnt_v, v);
4861 SET_ATM(qnt_w, w);
4862 SET_ATM(qnt_h2o, h2o);
4863 SET_ATM(qnt_o3, o3);
4864 SET_ATM(qnt_lwc, lwc);
4865 SET_ATM(qnt_rwc, rwc);
4866 SET_ATM(qnt_iwc, iwc);
4867 SET_ATM(qnt_swc, swc);
4868 SET_ATM(qnt_cc, cc);
4869 SET_ATM(qnt_pct, pct);
4870 SET_ATM(qnt_pcb, pcb);
4871 SET_ATM(qnt_cl, cl);
4872 SET_ATM(qnt_plcl, plcl);
4873 SET_ATM(qnt_plfc, plfc);
4874 SET_ATM(qnt_pel, pel);
4875 SET_ATM(qnt_cape, cape);
4876 SET_ATM(qnt_cin, cin);
4877 SET_ATM(qnt_o3c, o3c);
4878 const double lat_ref =
4879 ctl->met_coord_type == 0 ? atm->lat[ip] : ctl->met_utm_ref_lat;
4880 SET_ATM(qnt_hno3,
4881 clim_zm(&clim->hno3, atm->time[ip], lat_ref, atm->p[ip]));
4882 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
4883 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4884 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
4885 lat_ref, atm->p[ip]));
4886 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip], lat_ref, atm->p[ip]));
4887 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip], lat_ref, atm->p[ip]));
4888 SET_ATM(qnt_vh, sqrt(u * u + v * v));
4889 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
4890 SET_ATM(qnt_psat, PSAT(t));
4891 SET_ATM(qnt_psice, PSICE(t));
4892 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
4893 SET_ATM(qnt_sh, SH(h2o));
4894 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
4895 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
4896 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
4897 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
4898 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
4899 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
4900 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
4901 SET_ATM(qnt_eta_dot, atm->q[ctl->qnt_eta_dot][ip]);
4902 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
4903 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
4904 SET_ATM(qnt_pv, pv);
4905 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
4906 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
4907 SET_ATM(qnt_tnat,
4908 nat_temperature(atm->p[ip], h2o,
4909 clim_zm(&clim->hno3, atm->time[ip],
4910 atm->lat[ip], atm->p[ip])));
4911 SET_ATM(qnt_tsts,
4912 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
4913 }
4914}
4915
4916/*****************************************************************************/
4917
4919 const ctl_t *ctl,
4920 const clim_t *clim,
4921 atm_t *atm,
4922 const double t) {
4923
4924 /* Set timer... */
4925 SELECT_TIMER("MODULE_MIXING", "PHYSICS");
4926
4927 /* Allocate... */
4928 const int np = atm->np;
4929 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
4930 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
4931 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
4932
4933 /* Set grid box size... */
4934 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
4935 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
4936 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
4937
4938 /* Set time interval... */
4939 const double t0 = t - 0.5 * ctl->dt_mod;
4940 const double t1 = t + 0.5 * ctl->dt_mod;
4941
4942 /* Get indices... */
4943#ifdef _OPENACC
4944#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
4945#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
4946#pragma acc parallel loop independent gang vector
4947#else
4948#pragma omp parallel for default(shared)
4949#endif
4950 for (int ip = 0; ip < np; ip++) {
4951 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
4952 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
4953 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
4954 if (atm->time[ip] < t0 || atm->time[ip] > t1
4955 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
4956 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
4957 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
4958 izs[ip] = -1;
4959 }
4960
4961 /* Calculate interparcel mixing... */
4962 const int use_ensemble = (ctl->nens > 0);
4963
4964 const int quantities[] = {
4965 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
4966 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
4967 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
4968 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
4969 ctl->qnt_Csf6, ctl->qnt_aoa, ctl->qnt_Arn222, ctl->qnt_Apb210,
4970 ctl->qnt_Abe7, ctl->qnt_Acs137, ctl->qnt_Ai131, ctl->qnt_Axe133
4971 };
4972 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
4973
4974 for (int i = 0; i < n_qnt; i++)
4975 if (quantities[i] >= 0)
4976 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
4977 use_ensemble);
4978
4979 /* Free... */
4980#ifdef _OPENACC
4981#pragma acc exit data delete(ixs,iys,izs)
4982#endif
4983 free(ixs);
4984 free(iys);
4985 free(izs);
4986}
4987
4988/*****************************************************************************/
4989
4991 const ctl_t *ctl,
4992 const clim_t *clim,
4993 atm_t *atm,
4994 const int *ixs,
4995 const int *iys,
4996 const int *izs,
4997 const int qnt_idx,
4998 const int use_ensemble) {
4999
5000 const int np = atm->np;
5001 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
5002 const int nens = use_ensemble ? ctl->nens : 1;
5003 const int total_grid = ngrid * nens;
5004
5005 double *restrict const cmean =
5006 (double *) malloc((size_t) total_grid * sizeof(double));
5007 int *restrict const count =
5008 (int *) malloc((size_t) total_grid * sizeof(int));
5009
5010 /* Init... */
5011#ifdef _OPENACC
5012#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
5013#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
5014#pragma acc parallel loop independent gang vector
5015#else
5016#ifdef __NVCOMPILER
5017#pragma novector
5018#endif
5019#pragma omp parallel for
5020#endif
5021 for (int i = 0; i < total_grid; i++) {
5022 count[i] = 0;
5023 cmean[i] = 0.0;
5024 }
5025
5026 /* Loop over particles... */
5027#ifdef _OPENACC
5028#pragma acc parallel loop independent gang vector
5029#endif
5030 for (int ip = 0; ip < np; ip++)
5031 if (izs[ip] >= 0) {
5032 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
5033 const int idx =
5034 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
5035 ctl->mixing_nz);
5036#ifdef _OPENACC
5037#pragma acc atomic update
5038#endif
5039 cmean[idx] += atm->q[qnt_idx][ip];
5040#ifdef _OPENACC
5041#pragma acc atomic update
5042#endif
5043 count[idx]++;
5044 }
5045
5046 /* Compute means... */
5047#ifdef _OPENACC
5048#pragma acc parallel loop independent gang vector
5049#else
5050#ifdef __NVCOMPILER
5051#pragma novector
5052#endif
5053#pragma omp parallel for
5054#endif
5055 for (int i = 0; i < total_grid; i++)
5056 if (count[i] > 0)
5057 cmean[i] /= count[i];
5058
5059 /* Interparcel mixing... */
5060#ifdef _OPENACC
5061#pragma acc parallel loop independent gang vector
5062#else
5063#pragma omp parallel for
5064#endif
5065 for (int ip = 0; ip < np; ip++) {
5066 if (izs[ip] >= 0) {
5067 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
5068
5069 double mixparam = 1.0;
5070 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
5071 const double w = tropo_weight(ctl, clim, atm, ip);
5072 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
5073 }
5074
5075 const int idx =
5076 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
5077 ctl->mixing_nz);
5078 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
5079 }
5080 }
5081
5082 /* Free... */
5083#ifdef _OPENACC
5084#pragma acc exit data delete(cmean,count)
5085#endif
5086 free(cmean);
5087 free(count);
5088}
5089
5090/*****************************************************************************/
5091
5093 const ctl_t *ctl,
5094 const cache_t *cache,
5095 const clim_t *clim,
5096 met_t *met0,
5097 met_t *met1,
5098 atm_t *atm) {
5099
5100 /* Set timer... */
5101 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS");
5102
5103 /* Check quantity flags... */
5104 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5105 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5106
5107 /* Parameter of SO2 correction... */
5108 const double a = 4.71572206e-08;
5109 const double b = -8.28782867e-01;
5110 const double low = pow(1. / a, 1. / b);
5111
5112 /* Loop over particles... */
5113 PARTICLE_LOOP(0, atm->np, 1,
5114 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5115
5116 /* Get temperature... */
5117 double t;
5119 INTPOL_3D(t, 1);
5120
5121 /* Calculate molecular density... */
5122 const double M = MOLEC_DENS(atm->p[ip], t);
5123
5124 /* Use constant reaction rate... */
5125 double k = NAN;
5126 if (ctl->oh_chem_reaction == 1)
5127 k = ctl->oh_chem[0];
5128
5129 /* Calculate bimolecular reaction rate... */
5130 else if (ctl->oh_chem_reaction == 2)
5131 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
5132
5133 /* Calculate termolecular reaction rate... */
5134 if (ctl->oh_chem_reaction == 3) {
5135
5136 /* Calculate rate coefficient for X + OH + M -> XOH + M
5137 (JPL Publication 19-05) ... */
5138 const double k0 =
5139 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
5140 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
5141 const double ki =
5142 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
5143 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
5144 const double c = log10(k0 * M / ki);
5145 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
5146 }
5147
5148 /* Correction factor for high SO2 concentration
5149 (if qnt_Cx is defined, the correction is switched on)... */
5150 double cor = 1;
5151 if (ctl->qnt_Cx >= 0)
5152 cor =
5153 atm->q[ctl->qnt_Cx][ip] >
5154 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
5155
5156 /* Calculate exponential decay... */
5157 const double rate_coef =
5158 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
5159 atm->lat[ip], atm->p[ip]) * M * cor;
5160 const double aux = exp(-cache->dt[ip] * rate_coef);
5161 if (ctl->qnt_m >= 0) {
5162 if (ctl->qnt_mloss_oh >= 0)
5163 atm->q[ctl->qnt_mloss_oh][ip]
5164 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5165 atm->q[ctl->qnt_m][ip] *= aux;
5166 if (ctl->qnt_loss_rate >= 0)
5167 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
5168 }
5169 if (ctl->qnt_vmr >= 0)
5170 atm->q[ctl->qnt_vmr][ip] *= aux;
5171 }
5172}
5173
5174/*****************************************************************************/
5175
5177 const cache_t *cache,
5178 met_t *met0,
5179 met_t *met1,
5180 atm_t *atm) {
5181
5182 /* Set timer... */
5183 SELECT_TIMER("MODULE_POSITION", "PHYSICS");
5184
5185 /* Loop over particles... */
5186 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
5187
5188 /* Init... */
5189 double ps;
5191
5192 if (met0->coord_type == 0) {
5193 /* Calculate modulo... */
5194 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
5195 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
5196
5197 /* Check latitude... */
5198 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
5199 if (atm->lat[ip] > 90) {
5200 atm->lat[ip] = 180 - atm->lat[ip];
5201 atm->lon[ip] += 180;
5202 }
5203 if (atm->lat[ip] < -90) {
5204 atm->lat[ip] = -180 - atm->lat[ip];
5205 atm->lon[ip] += 180;
5206 }
5207 }
5208
5209 /* Check longitude... */
5210 while (atm->lon[ip] < -180)
5211 atm->lon[ip] += 360;
5212 while (atm->lon[ip] >= 180)
5213 atm->lon[ip] -= 360;
5214 } else {
5215 intpol_check_cartesian(met0->lon, met0->nx, met0->lat, met0->ny,
5216 atm->lon[ip], atm->lat[ip], &atm->lon[ip],
5217 &atm->lat[ip]);
5218 }
5219
5220
5221 /* Check pressure... */
5222 if (atm->p[ip] < met0->p[met0->np - 1]) {
5223 atm->p[ip] = met0->p[met0->np - 1];
5224 } else if (atm->p[ip] > 300.) {
5225 INTPOL_2D(ps, 1);
5226 if (atm->p[ip] > ps)
5227 atm->p[ip] = ps;
5228 }
5229 }
5230}
5231
5232/*****************************************************************************/
5233
5235 const ctl_t *ctl,
5236 const cache_t *cache,
5237 atm_t *atm) {
5238
5239 /* Set timer... */
5240 SELECT_TIMER("MODULE_RADIO_DECAY", "PHYSICS");
5241
5242 /* Set decay constants of radioactive species [s^-1]... */
5243 const double lambda_rn222 = log(2.0) / (3.8235 * 86400.0);
5244 const double lambda_pb210 = log(2.0) / (22.3 * 365.25 * 86400.0);
5245 const double lambda_be7 = log(2.0) / (53.22 * 86400.0);
5246 const double lambda_cs137 = log(2.0) / (30.05 * 365.25 * 86400.0);
5247 const double lambda_i131 = log(2.0) / (8.02 * 86400.0);
5248 const double lambda_xe133 = log(2.0) / (5.2474 * 86400.0);
5249
5250 /* Loop over particles... */
5251 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,atm)") {
5252
5253 /* Set timestep... */
5254 const double dt = cache->dt[ip];
5255
5256 /* Loss for Pb-210... */
5257 if (ctl->qnt_Apb210 >= 0)
5258 atm->q[ctl->qnt_Apb210][ip] *= exp(-dt * lambda_pb210);
5259
5260 /* Loss for Rn-222... */
5261 if (ctl->qnt_Arn222 >= 0) {
5262 const double old = atm->q[ctl->qnt_Arn222][ip];
5263 const double aux = exp(-dt * lambda_rn222);
5264 const double lost = old * (1.0 - aux);
5265 atm->q[ctl->qnt_Arn222][ip] = old * aux;
5266
5267 /* Parent-daughter process for Pb-210... */
5268 if (ctl->qnt_Apb210 >= 0)
5269 atm->q[ctl->qnt_Apb210][ip] += lost * lambda_pb210 / lambda_rn222;
5270 }
5271
5272 /* Loss for Be-7... */
5273 if (ctl->qnt_Abe7 >= 0)
5274 atm->q[ctl->qnt_Abe7][ip] *= exp(-dt * lambda_be7);
5275
5276 /* Loss for Cs-137... */
5277 if (ctl->qnt_Acs137 >= 0)
5278 atm->q[ctl->qnt_Acs137][ip] *= exp(-dt * lambda_cs137);
5279
5280 /* Loss for I-131... */
5281 if (ctl->qnt_Ai131 >= 0)
5282 atm->q[ctl->qnt_Ai131][ip] *= exp(-dt * lambda_i131);
5283
5284 /* Loss for Xe-133... */
5285 if (ctl->qnt_Axe133 >= 0)
5286 atm->q[ctl->qnt_Axe133][ip] *= exp(-dt * lambda_xe133);
5287 }
5288}
5289
5290/*****************************************************************************/
5291
5293 const int ntask) {
5294
5295 /* Initialize GSL random number generators... */
5296 gsl_rng_env_setup();
5297 if (omp_get_max_threads() > NTHREADS)
5298 ERRMSG("Too many threads!");
5299 for (int i = 0; i < NTHREADS; i++) {
5300 rng[i] = gsl_rng_alloc(gsl_rng_default);
5301 gsl_rng_set(rng[i], gsl_rng_default_seed
5302 + (long unsigned) (ntask * NTHREADS + i));
5303 }
5304
5305 /* Initialize cuRAND random number generators... */
5306#ifdef CURAND
5307 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
5308 CURAND_STATUS_SUCCESS)
5309 ERRMSG("Cannot create random number generator!");
5310 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
5311 CURAND_STATUS_SUCCESS)
5312 ERRMSG("Cannot set seed for random number generator!");
5313 if (curandSetStream
5314 (rng_curand,
5315 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
5316 CURAND_STATUS_SUCCESS)
5317 ERRMSG("Cannot set stream for random number generator!");
5318#endif
5319}
5320
5321/*****************************************************************************/
5322
5324 const ctl_t *ctl,
5325 double *rs,
5326 const size_t n,
5327 const int method) {
5328
5329 /* Use GSL random number generators... */
5330 if (ctl->rng_type == 0) {
5331
5332 /* Uniform distribution... */
5333 if (method == 0) {
5334#pragma omp parallel for default(shared)
5335 for (size_t i = 0; i < n; ++i)
5336 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
5337 }
5338
5339 /* Normal distribution... */
5340 else if (method == 1) {
5341#pragma omp parallel for default(shared)
5342 for (size_t i = 0; i < n; ++i)
5343 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
5344 }
5345
5346 /* Update of random numbers on device... */
5347#ifdef _OPENACC
5348 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
5349#pragma acc update device(rs[:n])
5350#endif
5351 }
5352
5353 /* Use Squares random number generator (Widynski, 2022)... */
5354 else if (ctl->rng_type == 1) {
5355
5356 /* Set key (don't change this!)... */
5357 const uint64_t key = 0xc8e4fd154ce32f6d;
5358
5359 /* Uniform distribution... */
5360#ifdef _OPENACC
5361#pragma acc data present(rs)
5362#pragma acc parallel loop independent gang vector
5363#else
5364#pragma omp parallel for default(shared)
5365#endif
5366 for (size_t i = 0; i < n + 1; ++i) {
5367 uint64_t r, t, x, y, z;
5368 y = x = (rng_ctr + i) * key;
5369 z = y + key;
5370 x = x * x + y;
5371 x = (x >> 32) | (x << 32);
5372 x = x * x + z;
5373 x = (x >> 32) | (x << 32);
5374 x = x * x + y;
5375 x = (x >> 32) | (x << 32);
5376 t = x = x * x + z;
5377 x = (x >> 32) | (x << 32);
5378 r = t ^ ((x * x + y) >> 32);
5379 rs[i] = (double) r / (double) UINT64_MAX;
5380 }
5381 rng_ctr += n + 1;
5382
5383 /* Normal distribution... */
5384 if (method == 1) {
5385#ifdef _OPENACC
5386#pragma acc parallel loop independent gang vector
5387#else
5388#pragma omp parallel for default(shared)
5389#endif
5390 for (size_t i = 0; i < n; i += 2) {
5391 const double r = sqrt(-2.0 * log(rs[i]));
5392 const double phi = 2.0 * M_PI * rs[i + 1];
5393 rs[i] = r * cosf((float) phi);
5394 rs[i + 1] = r * sinf((float) phi);
5395 }
5396 }
5397 }
5398
5399 /* Use cuRAND random number generators... */
5400 else if (ctl->rng_type == 2) {
5401#ifdef CURAND
5402#pragma acc host_data use_device(rs)
5403 {
5404
5405 /* Uniform distribution... */
5406 if (method == 0) {
5407 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
5408 CURAND_STATUS_SUCCESS)
5409 ERRMSG("Cannot create random numbers!");
5410 }
5411
5412 /* Normal distribution... */
5413 else if (method == 1) {
5414 if (curandGenerateNormalDouble
5415 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
5416 1.0) != CURAND_STATUS_SUCCESS)
5417 ERRMSG("Cannot create random numbers!");
5418 }
5419 }
5420#else
5421 ERRMSG("MPTRAC was compiled without cuRAND!");
5422#endif
5423 }
5424}
5425
5426/*****************************************************************************/
5427
5429 const ctl_t *ctl,
5430 const cache_t *cache,
5431 met_t *met0,
5432 met_t *met1,
5433 atm_t *atm) {
5434
5435 /* Set timer... */
5436 SELECT_TIMER("MODULE_SEDI", "PHYSICS")
5437 /* Loop over particles... */
5438 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5439
5440 /* Get temperature... */
5441 double t;
5443 INTPOL_3D(t, 1);
5444
5445 /* Sedimentation velocity... */
5446 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
5447 atm->q[ctl->qnt_rhop][ip]);
5448
5449 /* Calculate pressure change... */
5450 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
5451 }
5452}
5453
5454/*****************************************************************************/
5455
5457 const ctl_t *ctl,
5458 const met_t *met0,
5459 atm_t *atm) {
5460
5461 /* Set timer... */
5462 SELECT_TIMER("MODULE_SORT", "PHYSICS");
5463
5464 /* Allocate... */
5465 const int np = atm->np;
5466 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
5467 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
5468 if (a == NULL || p == NULL)
5469 ERRMSG("Out of memory!");
5470
5471#ifdef _OPENACC
5472#pragma acc enter data create(a[0:np],p[0:np])
5473#pragma acc data present(ctl,met0,atm,a,p)
5474#endif
5475
5476 /* Get box index... */
5477#ifdef _OPENACC
5478#pragma acc parallel loop independent gang vector
5479#else
5480#pragma omp parallel for default(shared)
5481#endif
5482 for (int ip = 0; ip < np; ip++) {
5483 a[ip] =
5484 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
5485 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
5486 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
5487 p[ip] = ip;
5488 }
5489
5490 /* Sorting... */
5491#ifdef THRUST
5492#ifdef _OPENACC
5493#pragma acc host_data use_device(a,p)
5494#endif
5495 thrustSortWrapper(a, np, p);
5496#else
5497 size_t *perm_sz = (size_t *) malloc((size_t) np * sizeof(size_t));
5498 if (perm_sz == NULL)
5499 ERRMSG("Out of memory!");
5500#ifdef _OPENACC
5501#pragma acc update self(a[0:np])
5502#endif
5503 gsl_sort_index(perm_sz, a, 1, (size_t) np);
5504 for (int ip = 0; ip < np; ++ip)
5505 p[ip] = (int) perm_sz[ip];
5506 free(perm_sz);
5507#ifdef _OPENACC
5508#pragma acc update device(p[0:np])
5509#endif
5510#endif
5511
5512 /* Sort data... */
5513 module_sort_help(atm->time, p, np);
5514 module_sort_help(atm->p, p, np);
5515 module_sort_help(atm->lon, p, np);
5516 module_sort_help(atm->lat, p, np);
5517 for (int iq = 0; iq < ctl->nq; iq++)
5518 module_sort_help(atm->q[iq], p, np);
5519
5520 /* Free... */
5521#ifdef _OPENACC
5522#pragma acc exit data delete(a,p)
5523#endif
5524 free(a);
5525 free(p);
5526}
5527
5528/*****************************************************************************/
5529
5531 double *a,
5532 const int *p,
5533 const int np) {
5534
5535 /* Allocate... */
5536 double *restrict const help =
5537 (double *) malloc((size_t) np * sizeof(double));
5538 if (help == NULL)
5539 ERRMSG("Out of memory!");
5540
5541 /* Reordering of array... */
5542#ifdef _OPENACC
5543#pragma acc enter data create(help[0:np])
5544#pragma acc data present(a,p,help)
5545#pragma acc parallel loop independent gang vector
5546#else
5547#pragma omp parallel for default(shared)
5548#endif
5549 for (int ip = 0; ip < np; ip++)
5550 help[ip] = a[p[ip]];
5551#ifdef _OPENACC
5552#pragma acc parallel loop independent gang vector
5553#else
5554#pragma omp parallel for default(shared)
5555#endif
5556 for (int ip = 0; ip < np; ip++)
5557 a[ip] = help[ip];
5558
5559 /* Free... */
5560#ifdef _OPENACC
5561#pragma acc exit data delete(help)
5562#endif
5563 free(help);
5564}
5565
5566/*****************************************************************************/
5567
5569 const ctl_t *ctl,
5570 cache_t *cache,
5571 met_t *met0,
5572 atm_t *atm,
5573 const double t) {
5574
5575 /* Set timer... */
5576 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS");
5577
5578 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
5579 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
5580
5581 const int local =
5582 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
5583
5584 /* Loop over particles... */
5585 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
5586
5587 /* Set time step for each air parcel... */
5588 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
5589 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
5590 && ctl->direction * (atm->time[ip] - t) < 0))
5591 cache->dt[ip] = t - atm->time[ip];
5592 else
5593 cache->dt[ip] = 0.0;
5594
5595 /* Check horizontal boundaries of local meteo data... */
5596#ifndef DD
5597 int dd = 1;
5598#else
5599 int dd = 0;
5600#endif
5601 if (dd) {
5602 if (local && (atm->lon[ip] <= met0->lon[0]
5603 || atm->lon[ip] >= met0->lon[met0->nx - 1]
5604 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
5605 cache->dt[ip] = 0.0;
5606 } else {
5607 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
5608 cache->dt[ip] = 0;
5609 }
5610 }
5611}
5612
5613/*****************************************************************************/
5614
5616 ctl_t *ctl,
5617 const atm_t *atm) {
5618
5619 /* Set timer... */
5620 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS");
5621
5622 /* Set start time... */
5623 if (ctl->direction == 1) {
5624 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
5625 if (ctl->t_stop > 1e99)
5626 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
5627 } else {
5628 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
5629 if (ctl->t_stop > 1e99)
5630 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
5631 }
5632
5633 /* Check time interval... */
5634 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
5635 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
5636
5637 /* Round start time... */
5638 if (ctl->direction == 1)
5639 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
5640 else
5641 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
5642}
5643
5644/*****************************************************************************/
5645
5647 const ctl_t *ctl,
5648 const cache_t *cache,
5649 const clim_t *clim,
5650 met_t *met0,
5651 met_t *met1,
5652 atm_t *atm) {
5653
5654 if (ctl->met_coord_type != 0)
5655 ERRMSG("Only lat/lon grid supported");
5656
5657 /* Set timer... */
5658 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS");
5659
5660 /* Loop over particles... */
5661 PARTICLE_LOOP(0, atm->np, 1,
5662 "acc data present(ctl,cache,clim,met0,met1,atm)") {
5663
5664 /* Get temperature... */
5665 double t;
5667 INTPOL_3D(t, 1);
5668
5669 /* Get molecular density... */
5670 const double M = MOLEC_DENS(atm->p[ip], t);
5671
5672 /* Get total column ozone... */
5673 double o3c;
5674 INTPOL_2D(o3c, 1);
5675
5676 /* Get solar zenith angle... */
5677 const double sza =
5678 acos(cos_sza(atm->time[ip], atm->lon[ip], atm->lat[ip]));
5679
5680 /* Get O(1D) volume mixing ratio... */
5681 const double o1d =
5682 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
5683
5684 /* Reactions for CFC-10... */
5685 if (ctl->qnt_Cccl4 >= 0) {
5686 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
5687 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
5688 atm->p[ip], sza, o3c);
5689 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5690 }
5691
5692 /* Reactions for CFC-11... */
5693 if (ctl->qnt_Cccl3f >= 0) {
5694 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
5695 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
5696 atm->p[ip], sza, o3c);
5697 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5698 }
5699
5700 /* Reactions for CFC-12... */
5701 if (ctl->qnt_Cccl2f2 >= 0) {
5702 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
5703 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
5704 atm->p[ip], sza, o3c);
5705 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5706 }
5707
5708 /* Reactions for N2O... */
5709 if (ctl->qnt_Cn2o >= 0) {
5710 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
5711 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
5712 atm->p[ip], sza, o3c);
5713 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5714 }
5715 }
5716}
5717
5718/*****************************************************************************/
5719
5721 const ctl_t *ctl,
5722 const cache_t *cache,
5723 met_t *met0,
5724 met_t *met1,
5725 atm_t *atm) {
5726
5727 /* Set timer... */
5728 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS");
5729
5730 /* Check quantity flags... */
5731 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5732 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5733
5734 /* Loop over particles... */
5735 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5736
5737 /* Check whether particle is below cloud top... */
5738 double pct;
5740 INTPOL_2D(pct, 1);
5741 if (!isfinite(pct) || atm->p[ip] <= pct)
5742 continue;
5743
5744 /* Get cloud bottom pressure... */
5745 double pcb;
5746 INTPOL_2D(pcb, 0);
5747
5748 /* Estimate precipitation rate (Pisso et al., 2019)... */
5749 double cl;
5750 INTPOL_2D(cl, 0);
5751 const double Is =
5752 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
5753 if (Is < 0.01)
5754 continue;
5755
5756 /* Check whether particle is inside or below cloud... */
5757 double lwc, rwc, iwc, swc;
5758 INTPOL_3D(lwc, 1);
5759 INTPOL_3D(rwc, 0);
5760 INTPOL_3D(iwc, 0);
5761 INTPOL_3D(swc, 0);
5762 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
5763
5764 /* Get temperature... */
5765 double t;
5766 INTPOL_3D(t, 0);
5767
5768 /* Calculate in-cloud scavenging coefficient... */
5769 double lambda = 0;
5770 if (inside) {
5771
5772 /* Calculate retention factor... */
5773 double eta;
5774 if (t > 273.15)
5775 eta = 1;
5776 else if (t <= 238.15)
5777 eta = ctl->wet_depo_ic_ret_ratio;
5778 else
5779 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
5780
5781 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5782 if (ctl->wet_depo_ic_a > 0)
5783 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
5784
5785 /* Use Henry's law for gases... */
5786 else if (ctl->wet_depo_ic_h[0] > 0) {
5787
5788 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5789 double h = ctl->wet_depo_ic_h[0]
5790 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
5791
5792 /* Use effective Henry's constant for SO2
5793 (Berglen, 2004; Simpson, 2012)... */
5794 if (ctl->wet_depo_so2_ph > 0) {
5795 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
5796 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
5797 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
5798 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
5799 }
5800
5801 /* Estimate depth of cloud layer... */
5802 const double dz = 1e3 * (Z(pct) - Z(pcb));
5803
5804 /* Calculate scavenging coefficient... */
5805 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5806 }
5807 }
5808
5809 /* Calculate below-cloud scavenging coefficient... */
5810 else {
5811
5812 /* Calculate retention factor... */
5813 double eta;
5814 if (t > 270)
5815 eta = 1;
5816 else
5817 eta = ctl->wet_depo_bc_ret_ratio;
5818
5819 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5820 if (ctl->wet_depo_bc_a > 0)
5821 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
5822
5823 /* Use Henry's law for gases... */
5824 else if (ctl->wet_depo_bc_h[0] > 0) {
5825
5826 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5827 const double h = ctl->wet_depo_bc_h[0]
5828 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
5829
5830 /* Estimate depth of cloud layer... */
5831 const double dz = 1e3 * (Z(pct) - Z(pcb));
5832
5833 /* Calculate scavenging coefficient... */
5834 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5835 }
5836 }
5837
5838 /* Calculate exponential decay of mass... */
5839 const double aux = exp(-cache->dt[ip] * lambda);
5840 if (ctl->qnt_m >= 0) {
5841 if (ctl->qnt_mloss_wet >= 0)
5842 atm->q[ctl->qnt_mloss_wet][ip]
5843 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5844 atm->q[ctl->qnt_m][ip] *= aux;
5845 if (ctl->qnt_loss_rate >= 0)
5846 atm->q[ctl->qnt_loss_rate][ip] += lambda;
5847 }
5848 if (ctl->qnt_vmr >= 0)
5849 atm->q[ctl->qnt_vmr][ip] *= aux;
5850 }
5851}
5852
5853/*****************************************************************************/
5854
5856 ctl_t **ctl,
5857 cache_t **cache,
5858 clim_t **clim,
5859 met_t **met0,
5860 met_t **met1,
5861 atm_t **atm,
5862 dd_t **dd) {
5863
5864 /* Initialize GPU... */
5865#ifdef _OPENACC
5866 SELECT_TIMER("ACC_INIT", "INIT");
5867 int rank = 0;
5868#ifdef MPI
5869 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5870#endif
5871 if (acc_get_num_devices(acc_device_nvidia) <= 0)
5872 ERRMSG("Not running on a GPU device!");
5873 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
5874 acc_device_nvidia);
5875 acc_device_t device_type = acc_get_device_type();
5876 acc_init(device_type);
5877#endif
5878
5879 /* Allocate... */
5880 SELECT_TIMER("ALLOC", "MEMORY");
5881 ALLOC(*ctl, ctl_t, 1);
5882 ALLOC(*cache, cache_t, 1);
5883 ALLOC(*clim, clim_t, 1);
5884 ALLOC(*met0, met_t, 1);
5885 ALLOC(*met1, met_t, 1);
5886 ALLOC(*atm, atm_t, 1);
5887 ALLOC(*dd, dd_t, 1);
5888
5889 /* Create data region on GPU... */
5890#ifdef _OPENACC
5891 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY");
5892 ctl_t *ctlup = *ctl;
5893 cache_t *cacheup = *cache;
5894 clim_t *climup = *clim;
5895 met_t *met0up = *met0;
5896 met_t *met1up = *met1;
5897 atm_t *atmup = *atm;
5898#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
5899#ifdef DD
5900 dd_t *ddup = *dd;
5901#pragma acc enter data create(ddup[:1])
5902#endif
5903#endif
5904}
5905
5906/*****************************************************************************/
5907
5909 ctl_t *ctl,
5910 cache_t *cache,
5911 clim_t *clim,
5912 met_t *met0,
5913 met_t *met1,
5914 atm_t *atm,
5915 dd_t *dd) {
5916
5917 /* Delete data region on GPU... */
5918#ifdef _OPENACC
5919 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY");
5920#pragma acc exit data delete(ctl,cache,clim,met0,met1,atm)
5921#ifdef DD
5922#pragma acc exit data delete(dd)
5923#endif
5924#endif
5925
5926 /* Free... */
5927 SELECT_TIMER("FREE", "MEMORY");
5928 free(atm);
5929 free(ctl);
5930 free(cache);
5931 free(clim);
5932 free(met0);
5933 free(met1);
5934
5935 /* Free MPI datatype... */
5936#ifdef DD
5937 MPI_Type_free(&dd->MPI_Particle);
5938#endif
5939 free(dd);
5940}
5941
5942/*****************************************************************************/
5943
5945 ctl_t *ctl,
5946 clim_t *clim,
5947 const double t,
5948 met_t **met0,
5949 met_t **met1,
5950 dd_t *dd) {
5951
5952 static int init;
5953
5954 met_t *mets;
5955
5956 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
5957
5958 /* Set timer... */
5959 SELECT_TIMER("GET_MET", "INPUT");
5960
5961 /* Init... */
5962 if (t == ctl->t_start || !init) {
5963 init = 1;
5964
5965 /* Read meteo data... */
5966 get_met_filename(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
5967 ctl->metbase, ctl->dt_met, filename);
5968 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5969 ERRMSG("Cannot open file!");
5970
5971 get_met_filename(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
5972 ctl->metbase, ctl->dt_met, filename);
5973 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5974 ERRMSG("Cannot open file!");
5975
5976 /* Update GPU... */
5977 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
5978 SELECT_TIMER("GET_MET", "INPUT");
5979
5980 /* Caching... */
5981 if (ctl->met_cache && t != ctl->t_stop) {
5982 get_met_filename(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
5983 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
5984 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5985 LOG(1, "Caching: %s", cachefile);
5986 if (system(cmd) != 0)
5987 WARN("Caching command failed!");
5988 }
5989 }
5990
5991 /* Read new data for forward trajectories... */
5992 if (t > (*met1)->time) {
5993
5994 /* Pointer swap... */
5995 mets = *met1;
5996 *met1 = *met0;
5997 *met0 = mets;
5998
5999 /* Read new meteo data... */
6000 get_met_filename(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
6001 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
6002 ERRMSG("Cannot open file!");
6003
6004 /* Update GPU... */
6005 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
6006 SELECT_TIMER("GET_MET", "INPUT");
6007
6008 /* Caching... */
6009 if (ctl->met_cache && t != ctl->t_stop) {
6010 get_met_filename(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
6011 cachefile);
6012 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6013 LOG(1, "Caching: %s", cachefile);
6014 if (system(cmd) != 0)
6015 WARN("Caching command failed!");
6016 }
6017 }
6018
6019 /* Read new data for backward trajectories... */
6020 if (t < (*met0)->time) {
6021
6022 /* Pointer swap... */
6023 mets = *met1;
6024 *met1 = *met0;
6025 *met0 = mets;
6026
6027 /* Read new meteo data... */
6028 get_met_filename(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
6029 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
6030 ERRMSG("Cannot open file!");
6031
6032 /* Update GPU... */
6033 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
6034 SELECT_TIMER("GET_MET", "INPUT");
6035
6036 /* Caching... */
6037 if (ctl->met_cache && t != ctl->t_stop) {
6038 get_met_filename(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
6039 cachefile);
6040 sprintf(cmd, "cat %s > /dev/null &", cachefile);
6041 LOG(1, "Caching: %s", cachefile);
6042 if (system(cmd) != 0)
6043 WARN("Caching command failed!");
6044 }
6045 }
6046
6047 if ((*met0)->coord_type != (*met1)->coord_type)
6048 ERRMSG("Coordinate types do not match!");
6049
6050 /* Check that grids are consistent... */
6051 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
6052 if ((*met0)->nx != (*met1)->nx
6053 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
6054 ERRMSG("Meteo grid dimensions do not match!");
6055 for (int ix = 0; ix < (*met0)->nx; ix++)
6056 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
6057 ERRMSG("Meteo grid longitudes do not match!");
6058 for (int iy = 0; iy < (*met0)->ny; iy++)
6059 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
6060 ERRMSG("Meteo grid latitudes do not match!");
6061 for (int ip = 0; ip < (*met0)->np; ip++)
6062 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
6063 ERRMSG("Meteo grid pressure levels do not match!");
6064 }
6065}
6066
6067/*****************************************************************************/
6068
6070 ctl_t *ctl,
6071 cache_t *cache,
6072 clim_t *clim,
6073 atm_t *atm,
6074 const int ntask) {
6075
6076 /* Initialize timesteps... */
6077 module_timesteps_init(ctl, atm);
6078
6079 /* Initialize random number generator... */
6080 module_rng_init(ntask);
6081
6082 /* Update GPU memory... */
6083 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
6084}
6085
6086/*****************************************************************************/
6087
6089 const char *filename,
6090 const ctl_t *ctl,
6091 atm_t *atm) {
6092
6093 int result;
6094
6095 /* Set timer... */
6096 SELECT_TIMER("READ_ATM", "INPUT");
6097
6098 /* Init... */
6099 atm->np = 0;
6100
6101 /* Write info... */
6102 LOG(1, "Read atmospheric data: %s", filename);
6103
6104 /* Read ASCII data... */
6105 if (ctl->atm_type == 0)
6106 result = read_atm_asc(filename, ctl, atm);
6107
6108 /* Read binary data... */
6109 else if (ctl->atm_type == 1)
6110 result = read_atm_bin(filename, ctl, atm);
6111
6112 /* Read netCDF data... */
6113 else if (ctl->atm_type == 2)
6114 result = read_atm_nc(filename, ctl, atm);
6115
6116 /* Read CLaMS data... */
6117 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
6118 result = read_atm_clams(filename, ctl, atm);
6119
6120 /* Error... */
6121 else
6122 ERRMSG("Atmospheric data type not supported!");
6123
6124 /* Check result... */
6125 if (result != 1)
6126 return 0;
6127
6128 /* Check number of air parcels... */
6129 if (atm->np < 1)
6130 ERRMSG("Can not read any data!");
6131
6132 /* Write info... */
6133 double mini, maxi;
6134 LOG(2, "Number of particles: %d", atm->np);
6135 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6136 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6137 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6138 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6139 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6140 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6141 LOG(2, "%s range: %g ... %g %s",
6142 ctl->met_coord_type == 0 ? "Longitude" : "X coordinate", mini, maxi,
6143 ctl->met_coord_type == 0 ? "deg" : "m");
6144 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6145 LOG(2, "%s range: %g ... %g %s",
6146 ctl->met_coord_type == 0 ? "Latitude" : "Y coordinate", mini, maxi,
6147 ctl->met_coord_type == 0 ? "deg" : "m");
6148 for (int iq = 0; iq < ctl->nq; iq++) {
6149 char msg[5 * LEN];
6150 sprintf(msg, "Quantity %s range: %s ... %s %s",
6151 ctl->qnt_name[iq], ctl->qnt_format[iq],
6152 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6153 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6154 LOG(2, msg, mini, maxi);
6155 }
6156
6157 /* Return success... */
6158 return 1;
6159}
6160
6161/*****************************************************************************/
6162
6164 const ctl_t *ctl,
6165 clim_t *clim) {
6166
6167 /* Set timer... */
6168 SELECT_TIMER("READ_CLIM", "INPUT");
6169
6170 /* Init tropopause climatology... */
6171 clim_tropo_init(clim);
6172
6173 /* Read photolysis rates... */
6174 if (ctl->clim_photo[0] != '-')
6175 read_clim_photo(ctl->clim_photo, &clim->photo);
6176
6177 /* Read HNO3 climatology... */
6178 if (ctl->clim_hno3_filename[0] != '-')
6179 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
6180
6181 /* Read OH climatology... */
6182 if (ctl->clim_oh_filename[0] != '-') {
6183 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
6184 if (ctl->oh_chem_beta > 0)
6185 clim_oh_diurnal_correction(ctl, clim);
6186 }
6187
6188 /* Read H2O2 climatology... */
6189 if (ctl->clim_h2o2_filename[0] != '-')
6190 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
6191
6192 /* Read HO2 climatology... */
6193 if (ctl->clim_ho2_filename[0] != '-')
6194 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
6195
6196 /* Read O(1D) climatology... */
6197 if (ctl->clim_o1d_filename[0] != '-')
6198 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
6199
6200 /* Read CFC-10 time series... */
6201 if (ctl->clim_ccl4_timeseries[0] != '-')
6203
6204 /* Read CFC-11 time series... */
6205 if (ctl->clim_ccl3f_timeseries[0] != '-')
6207
6208 /* Read CFC-12 time series... */
6209 if (ctl->clim_ccl2f2_timeseries[0] != '-')
6211
6212 /* Read N2O time series... */
6213 if (ctl->clim_n2o_timeseries[0] != '-')
6214 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
6215
6216 /* Read SF6 time series... */
6217 if (ctl->clim_sf6_timeseries[0] != '-')
6218 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
6219}
6220
6221/*****************************************************************************/
6222
6224 const char *filename,
6225 int argc,
6226 char *argv[],
6227 ctl_t *ctl) {
6228
6229 /* Set timer... */
6230 SELECT_TIMER("READ_CTL", "INPUT");
6231
6232 /* Write info... */
6233 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
6234 "(executable: %s | version: %s | compiled: %s, %s)\n",
6235 argv[0], VERSION, __DATE__, __TIME__);
6236
6237 /* Initialize quantity indices... */
6238 ctl->qnt_idx = -1;
6239 ctl->qnt_ens = -1;
6240 ctl->qnt_stat = -1;
6241 ctl->qnt_m = -1;
6242 ctl->qnt_vmr = -1;
6243 ctl->qnt_rp = -1;
6244 ctl->qnt_rhop = -1;
6245 ctl->qnt_ps = -1;
6246 ctl->qnt_ts = -1;
6247 ctl->qnt_zs = -1;
6248 ctl->qnt_us = -1;
6249 ctl->qnt_vs = -1;
6250 ctl->qnt_ess = -1;
6251 ctl->qnt_nss = -1;
6252 ctl->qnt_shf = -1;
6253 ctl->qnt_lsm = -1;
6254 ctl->qnt_sst = -1;
6255 ctl->qnt_pbl = -1;
6256 ctl->qnt_pt = -1;
6257 ctl->qnt_tt = -1;
6258 ctl->qnt_zt = -1;
6259 ctl->qnt_h2ot = -1;
6260 ctl->qnt_zg = -1;
6261 ctl->qnt_p = -1;
6262 ctl->qnt_t = -1;
6263 ctl->qnt_rho = -1;
6264 ctl->qnt_u = -1;
6265 ctl->qnt_v = -1;
6266 ctl->qnt_w = -1;
6267 ctl->qnt_h2o = -1;
6268 ctl->qnt_o3 = -1;
6269 ctl->qnt_lwc = -1;
6270 ctl->qnt_rwc = -1;
6271 ctl->qnt_iwc = -1;
6272 ctl->qnt_swc = -1;
6273 ctl->qnt_cc = -1;
6274 ctl->qnt_pct = -1;
6275 ctl->qnt_pcb = -1;
6276 ctl->qnt_cl = -1;
6277 ctl->qnt_plcl = -1;
6278 ctl->qnt_plfc = -1;
6279 ctl->qnt_pel = -1;
6280 ctl->qnt_cape = -1;
6281 ctl->qnt_cin = -1;
6282 ctl->qnt_o3c = -1;
6283 ctl->qnt_hno3 = -1;
6284 ctl->qnt_oh = -1;
6285 ctl->qnt_h2o2 = -1;
6286 ctl->qnt_ho2 = -1;
6287 ctl->qnt_o1d = -1;
6288 ctl->qnt_mloss_oh = -1;
6289 ctl->qnt_mloss_h2o2 = -1;
6290 ctl->qnt_mloss_kpp = -1;
6291 ctl->qnt_mloss_wet = -1;
6292 ctl->qnt_mloss_dry = -1;
6293 ctl->qnt_mloss_decay = -1;
6294 ctl->qnt_loss_rate = -1;
6295 ctl->qnt_psat = -1;
6296 ctl->qnt_psice = -1;
6297 ctl->qnt_pw = -1;
6298 ctl->qnt_sh = -1;
6299 ctl->qnt_rh = -1;
6300 ctl->qnt_rhice = -1;
6301 ctl->qnt_theta = -1;
6302 ctl->qnt_zeta = -1;
6303 ctl->qnt_zeta_d = -1;
6304 ctl->qnt_zeta_dot = -1;
6305 ctl->qnt_eta = -1;
6306 ctl->qnt_eta_dot = -1;
6307 ctl->qnt_tvirt = -1;
6308 ctl->qnt_lapse = -1;
6309 ctl->qnt_vh = -1;
6310 ctl->qnt_vz = -1;
6311 ctl->qnt_pv = -1;
6312 ctl->qnt_tdew = -1;
6313 ctl->qnt_tice = -1;
6314 ctl->qnt_tsts = -1;
6315 ctl->qnt_tnat = -1;
6316 ctl->qnt_Cx = -1;
6317 ctl->qnt_Ch2o = -1;
6318 ctl->qnt_Co3 = -1;
6319 ctl->qnt_Cco = -1;
6320 ctl->qnt_Coh = -1;
6321 ctl->qnt_Ch = -1;
6322 ctl->qnt_Cho2 = -1;
6323 ctl->qnt_Ch2o2 = -1;
6324 ctl->qnt_Co1d = -1;
6325 ctl->qnt_Co3p = -1;
6326 ctl->qnt_Cccl4 = -1;
6327 ctl->qnt_Cccl3f = -1;
6328 ctl->qnt_Cccl2f2 = -1;
6329 ctl->qnt_Cn2o = -1;
6330 ctl->qnt_Csf6 = -1;
6331 ctl->qnt_aoa = -1;
6332 ctl->qnt_Arn222 = -1;
6333 ctl->qnt_Apb210 = -1;
6334 ctl->qnt_Abe7 = -1;
6335 ctl->qnt_Acs137 = -1;
6336 ctl->qnt_Ai131 = -1;
6337 ctl->qnt_Axe133 = -1;
6338 ctl->qnt_subdomain = -1;
6339 ctl->qnt_destination = -1;
6340
6341 /* Read quantities... */
6342 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
6343 if (ctl->nq > NQ)
6344 ERRMSG("Too many quantities!");
6345 for (int iq = 0; iq < ctl->nq; iq++) {
6346
6347 /* Read quantity name and format... */
6348 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
6349 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
6350 ctl->qnt_longname[iq]);
6351 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
6352 ctl->qnt_format[iq]);
6353 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
6354 sprintf(ctl->qnt_format[iq], "%%.2f");
6355
6356 /* Try to identify quantity... */
6357 SET_QNT(qnt_idx, "idx", "particle index", "-")
6358 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
6359 SET_QNT(qnt_stat, "stat", "station flag", "-")
6360 SET_QNT(qnt_m, "m", "mass", "kg")
6361 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
6362 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
6363 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
6364 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
6365 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
6366 SET_QNT(qnt_zs, "zs", "surface height", "km")
6367 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
6368 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
6369 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
6370 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
6371 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
6372 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
6373 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
6374 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
6375 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
6376 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
6377 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
6378 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
6379 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
6380 SET_QNT(qnt_p, "p", "pressure", "hPa")
6381 SET_QNT(qnt_t, "t", "temperature", "K")
6382 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
6383 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
6384 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
6385 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
6386 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
6387 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
6388 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
6389 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
6390 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
6391 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
6392 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
6393 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
6394 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
6395 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
6396 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
6397 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
6398 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
6399 SET_QNT(qnt_cape, "cape", "convective available potential energy",
6400 "J/kg")
6401 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
6402 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
6403 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
6404 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
6405 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
6406 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
6407 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
6408 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
6409 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
6410 "mass loss due to H2O2 chemistry", "kg")
6411 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
6412 "kg")
6413 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
6414 "kg")
6415 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
6416 "kg")
6417 SET_QNT(qnt_mloss_decay, "mloss_decay",
6418 "mass loss due to exponential decay", "kg")
6419 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
6420 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
6421 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
6422 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
6423 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
6424 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
6425 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
6426 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
6427 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
6428 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
6429 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
6430 "K/day")
6431 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
6432 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
6433 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
6434 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
6435 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
6436 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
6437 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
6438 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
6439 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
6440 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
6441 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
6442 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
6443 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
6444 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
6445 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
6446 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
6447 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
6448 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
6449 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
6450 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
6451 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
6452 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
6453 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
6454 "ppv")
6455 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
6456 "ppv")
6457 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
6458 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
6459 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
6460 SET_QNT(qnt_Arn222, "Arn222", "Rn-222 activity", "Bq")
6461 SET_QNT(qnt_Apb210, "Apb210", "Pb-210 activity", "Bq")
6462 SET_QNT(qnt_Abe7, "Abe7", "Be-7 activity", "Bq")
6463 SET_QNT(qnt_Acs137, "Acs137", "Cs-137 activity", "Bq")
6464 SET_QNT(qnt_Ai131, "Ai131", "I-131 activity", "Bq")
6465 SET_QNT(qnt_Axe133, "Axe133", "Xe-133 activity", "Bq")
6466 SET_QNT(qnt_subdomain, "subdomain", "current subdomain index", "-")
6467 SET_QNT(qnt_destination, "destination",
6468 "subdomain index of destination", "-")
6469 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
6470 }
6471
6472 ctl->met_coord_type =
6473 (int) scan_ctl(filename, argc, argv, "MET_COORD_TYPE", -1, "0", NULL);
6474 if (ctl->met_coord_type < 0 || ctl->met_coord_type > 1)
6475 ERRMSG("MET_COORD_TYPE must be 0 or 1!");
6476 ctl->met_utm_ref_lat = 0.0;
6477 ctl->met_utm_ref_lon = 0.0;
6478 if (ctl->met_coord_type == 1) {
6479 ctl->met_utm_ref_lat =
6480 scan_ctl(filename, argc, argv, "MET_UTM_REF_LAT", -1, "", NULL);
6481 ctl->met_utm_ref_lon =
6482 scan_ctl(filename, argc, argv, "MET_UTM_REF_LON", -1, "", NULL);
6483 }
6484
6485 /* Vertical coordinate and velocity... */
6486 ctl->advect_vert_coord =
6487 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
6488 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
6489 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
6490
6491 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
6492 ERRMSG("Add quantity zeta for diabatic advection!");
6493 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
6494 ERRMSG("Add quantity eta for etadot avection!");
6495
6496 ctl->met_vert_coord =
6497 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
6498 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
6499 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
6500
6501 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
6502 ERRMSG
6503 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
6504 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
6505 ERRMSG
6506 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
6507
6508 /* Time steps of simulation... */
6509 ctl->direction =
6510 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
6511 if (ctl->direction != -1 && ctl->direction != 1)
6512 ERRMSG("Set DIRECTION to -1 or 1!");
6513 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
6514 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
6515
6516 /* Meteo data... */
6517 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
6518 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
6519 ctl->met_convention =
6520 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
6521 ctl->met_type =
6522 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
6523 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
6524 ERRMSG
6525 ("Please use meteo files in netcdf format for diabatic calculations.");
6526 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
6527 ERRMSG
6528 ("Please use meteo files in netcdf format for etadot calculations.");
6529 ctl->met_clams =
6530 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
6531 ctl->met_nc_scale =
6532 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
6533 ctl->met_nc_level =
6534 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
6535 ctl->met_nc_quant =
6536 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
6537 ctl->met_zstd_level =
6538 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "-3", NULL);
6539 ctl->met_zstd_nworkers =
6540 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_NWORKERS", -1, "4", NULL);
6541 ctl->met_lz4_accel =
6542 (int) scan_ctl(filename, argc, argv, "MET_LZ4_ACCEL", -1, "8", NULL);
6543 ctl->met_pck_zstd =
6544 (int) scan_ctl(filename, argc, argv, "MET_PCK_ZSTD", -1, "0", NULL);
6545 if (ctl->met_pck_zstd != 0 && ctl->met_pck_zstd != 1)
6546 ERRMSG("Set MET_PCK_ZSTD to 0 or 1!");
6547#ifndef ZSTD
6548 if (ctl->met_type == 2 && ctl->met_pck_zstd)
6549 ERRMSG("MET_PCK_ZSTD requires MPTRAC to be compiled with ZSTD support!");
6550#endif
6551 const int def_lossy_scale =
6552 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", -1, "0", NULL);
6553 for (int i = 0; i < METVAR; i++) {
6554 char defprec_zfp[LEN] = "7", deftol_zfp[LEN] = "0.0";
6555 char defprec_sz3[LEN] = "6", deftol_sz3[LEN] = "0.0";
6556 if (i == 0) { /* geopotential height */
6557 sprintf(defprec_zfp, "12");
6558 sprintf(defprec_sz3, "11");
6559 } else if (i == 1) { /* temperature */
6560 sprintf(defprec_zfp, "11");
6561 sprintf(defprec_sz3, "7");
6562 } else if (i == 2 || i == 3) { /* horizontal wind */
6563 sprintf(defprec_zfp, "7");
6564 sprintf(defprec_sz3, "7");
6565 } else if (i == 4) { /* vertical wind */
6566 sprintf(defprec_zfp, "6");
6567 sprintf(defprec_sz3, "13");
6568 } else if (i == 5) { /* potential vorticity */
6569 sprintf(defprec_zfp, "7");
6570 sprintf(defprec_sz3, "20");
6571 } else if (i == 6) { /* water vapor */
6572 sprintf(defprec_zfp, "10");
6573 sprintf(defprec_sz3, "18");
6574 } else if (i == 7) { /* ozone */
6575 sprintf(defprec_zfp, "9");
6576 sprintf(defprec_sz3, "10");
6577 } else if (i >= 8 && i <= 11) { /* cloud water fields */
6578 sprintf(defprec_zfp, "6");
6579 sprintf(defprec_sz3, "13");
6580 } else if (i == 12) { /* cloud cover */
6581 sprintf(defprec_zfp, "9");
6582 sprintf(defprec_sz3, "6");
6583 }
6584 ctl->met_zfp_prec[i] =
6585 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", i, defprec_zfp,
6586 NULL);
6587 ctl->met_zfp_tol[i] =
6588 scan_ctl(filename, argc, argv, "MET_ZFP_TOL", i, deftol_zfp, NULL);
6589 ctl->met_sz3_prec[i] =
6590 (int) scan_ctl(filename, argc, argv, "MET_SZ3_PREC", i, defprec_sz3,
6591 NULL);
6592 ctl->met_sz3_tol[i] =
6593 scan_ctl(filename, argc, argv, "MET_SZ3_TOL", i, deftol_sz3, NULL);
6594 char defscale[LEN];
6595 snprintf(defscale, LEN, "%d", def_lossy_scale);
6596 ctl->met_lossy_scale[i] =
6597 (int) scan_ctl(filename, argc, argv, "MET_LOSSY_SCALE", i, defscale,
6598 NULL);
6599 if (ctl->met_lossy_scale[i] < 0 || ctl->met_lossy_scale[i] > 1)
6600 ERRMSG("Set MET_LOSSY_SCALE to 0 or 1!");
6601 }
6602
6603 /* Scan compression diagnostics file... */
6604 scan_ctl(filename, argc, argv, "MET_COMP_LOGFILE", -1, "-",
6605 ctl->met_comp_logfile);
6606 ctl->met_cms_batch =
6607 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
6608 ctl->met_cms_zstd =
6609 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
6610 ctl->met_cms_nd0x =
6611 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0X", -1, "48", NULL);
6612 ctl->met_cms_nd0y =
6613 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0Y", -1, "24", NULL);
6614 ctl->met_cms_maxlev =
6615 (int) scan_ctl(filename, argc, argv, "MET_CMS_MAXLEV", -1, "6", NULL);
6616 for (int i = 0; i < METVAR; i++) {
6617 char defeps[LEN] = "1.0";
6618 if (i == 1 || i == 2 || i == 3)
6619 sprintf(defeps, "0.05");
6620 ctl->met_cms_eps[i] =
6621 scan_ctl(filename, argc, argv, "MET_CMS_EPS", i, defeps, NULL);
6622 }
6623 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
6624 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
6625 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
6626 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
6627 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
6628 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
6629 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
6630 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
6631 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
6632 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
6633 ctl->met_detrend =
6634 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
6635 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
6636 if (ctl->met_np > EP)
6637 ERRMSG("Too many pressure levels!");
6638 ctl->met_press_level_def =
6639 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
6640 NULL);
6641 if (ctl->met_press_level_def >= 0) {
6642 level_definitions(ctl);
6643 } else {
6644 if (ctl->met_np > 0) {
6645 for (int ip = 0; ip < ctl->met_np; ip++)
6646 ctl->met_p[ip] =
6647 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
6648 }
6649 }
6650 ctl->met_nlev =
6651 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
6652 if (ctl->met_nlev > EP)
6653 ERRMSG("Too many model levels!");
6654 for (int ip = 0; ip < ctl->met_nlev; ip++)
6655 ctl->met_lev_hyam[ip] =
6656 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
6657 for (int ip = 0; ip < ctl->met_nlev; ip++)
6658 ctl->met_lev_hybm[ip] =
6659 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
6660 ctl->met_geopot_sx =
6661 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
6662 ctl->met_geopot_sy =
6663 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
6664 ctl->met_relhum =
6665 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
6666 ctl->met_cape =
6667 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
6668 if (ctl->met_cape < 0 || ctl->met_cape > 1)
6669 ERRMSG("Set MET_CAPE to 0 or 1!");
6670 ctl->met_pbl =
6671 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
6672 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
6673 ERRMSG("Set MET_PBL to 0 ... 3!");
6674 ctl->met_pbl_min =
6675 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
6676 ctl->met_pbl_max =
6677 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
6678 ctl->met_tropo =
6679 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
6680 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
6681 ERRMSG("Set MET_TROPO to 0 ... 5!");
6682 ctl->met_tropo_pv =
6683 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
6684 ctl->met_tropo_theta =
6685 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
6686 ctl->met_tropo_spline =
6687 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
6688 ctl->met_dt_out =
6689 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
6690 ctl->met_cache =
6691 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
6692 ctl->met_mpi_share =
6693 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
6694
6695 /* Sorting... */
6696 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
6697
6698 /* Isosurface parameters... */
6699 ctl->isosurf =
6700 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
6701 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
6702
6703 /* Random number generator... */
6704 ctl->rng_type =
6705 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
6706 if (ctl->rng_type < 0 || ctl->rng_type > 2)
6707 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
6708
6709 /* Advection parameters... */
6710 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
6711 if (!(ctl->advect == 1 || ctl->advect == 2 || ctl->advect == 4))
6712 ERRMSG("Set ADVECT to 1, 2, or 4!");
6713
6714 /* Diffusion parameters... */
6715 ctl->diffusion
6716 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
6717 if (ctl->diffusion < 0 || ctl->diffusion > 1)
6718 ERRMSG("Set DIFFUSION to 0 or 1!");
6719 ctl->turb_pbl_scheme =
6720 (int) scan_ctl(filename, argc, argv, "TURB_PBL_SCHEME", -1, "0", NULL);
6721 if (ctl->turb_pbl_scheme < 0 || ctl->turb_pbl_scheme > 1)
6722 ERRMSG("Set TURB_PBL_SCHEME to 0 or 1!");
6723 ctl->turb_dx_pbl =
6724 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
6725 ctl->turb_dx_trop =
6726 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
6727 ctl->turb_dx_strat =
6728 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
6729 ctl->turb_dz_pbl =
6730 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
6731 ctl->turb_dz_trop =
6732 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
6733 ctl->turb_dz_strat =
6734 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
6735 ctl->turb_mesox =
6736 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
6737 ctl->turb_mesoz =
6738 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
6739 ctl->turb_pbl_trans =
6740 scan_ctl(filename, argc, argv, "TURB_PBL_TRANS", -1, "0", NULL);
6741
6742 /* Convection... */
6743 ctl->conv_mix_pbl
6744 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
6745 ctl->conv_pbl_trans
6746 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
6747 ctl->conv_cape
6748 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
6749 ctl->conv_cin
6750 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
6751 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
6752
6753 /* Boundary conditions... */
6754 ctl->bound_mass =
6755 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
6756 ctl->bound_mass_trend =
6757 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
6758 ctl->bound_vmr =
6759 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
6760 ctl->bound_vmr_trend =
6761 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
6762 ctl->bound_lat0 =
6763 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
6764 ctl->bound_lat1 =
6765 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
6766 ctl->bound_p0 =
6767 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
6768 ctl->bound_p1 =
6769 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
6770 ctl->bound_dps =
6771 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
6772 ctl->bound_dzs =
6773 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
6774 ctl->bound_zetas =
6775 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
6776 ctl->bound_pbl =
6777 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
6778
6779 /* Species parameters... */
6780 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
6781 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
6782 ctl->molmass = 120.907;
6783 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
6784 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
6785 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
6786 ctl->molmass = 137.359;
6787 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
6788 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
6789 } else if (strcasecmp(ctl->species, "CH4") == 0) {
6790 ctl->molmass = 16.043;
6791 ctl->oh_chem_reaction = 2;
6792 ctl->oh_chem[0] = 2.45e-12;
6793 ctl->oh_chem[1] = 1775;
6794 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
6795 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6796 } else if (strcasecmp(ctl->species, "CO") == 0) {
6797 ctl->molmass = 28.01;
6798 ctl->oh_chem_reaction = 3;
6799 ctl->oh_chem[0] = 6.9e-33;
6800 ctl->oh_chem[1] = 2.1;
6801 ctl->oh_chem[2] = 1.1e-12;
6802 ctl->oh_chem[3] = -1.3;
6803 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
6804 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
6805 } else if (strcasecmp(ctl->species, "CO2") == 0) {
6806 ctl->molmass = 44.009;
6807 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
6808 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6809 } else if (strcasecmp(ctl->species, "H2O") == 0) {
6810 ctl->molmass = 18.01528;
6811 } else if (strcasecmp(ctl->species, "N2O") == 0) {
6812 ctl->molmass = 44.013;
6813 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
6814 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
6815 } else if (strcasecmp(ctl->species, "NH3") == 0) {
6816 ctl->molmass = 17.031;
6817 ctl->oh_chem_reaction = 2;
6818 ctl->oh_chem[0] = 1.7e-12;
6819 ctl->oh_chem[1] = 710;
6820 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
6821 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
6822 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
6823 ctl->molmass = 63.012;
6824 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
6825 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
6826 } else if (strcasecmp(ctl->species, "NO") == 0) {
6827 ctl->molmass = 30.006;
6828 ctl->oh_chem_reaction = 3;
6829 ctl->oh_chem[0] = 7.1e-31;
6830 ctl->oh_chem[1] = 2.6;
6831 ctl->oh_chem[2] = 3.6e-11;
6832 ctl->oh_chem[3] = 0.1;
6833 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
6834 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6835 } else if (strcasecmp(ctl->species, "NO2") == 0) {
6836 ctl->molmass = 46.005;
6837 ctl->oh_chem_reaction = 3;
6838 ctl->oh_chem[0] = 1.8e-30;
6839 ctl->oh_chem[1] = 3.0;
6840 ctl->oh_chem[2] = 2.8e-11;
6841 ctl->oh_chem[3] = 0.0;
6842 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
6843 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6844 } else if (strcasecmp(ctl->species, "O3") == 0) {
6845 ctl->molmass = 47.997;
6846 ctl->oh_chem_reaction = 2;
6847 ctl->oh_chem[0] = 1.7e-12;
6848 ctl->oh_chem[1] = 940;
6849 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
6850 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
6851 } else if (strcasecmp(ctl->species, "SF6") == 0) {
6852 ctl->molmass = 146.048;
6853 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
6854 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
6855 } else if (strcasecmp(ctl->species, "SO2") == 0) {
6856 ctl->molmass = 64.066;
6857 ctl->oh_chem_reaction = 3;
6858 ctl->oh_chem[0] = 2.9e-31;
6859 ctl->oh_chem[1] = 4.1;
6860 ctl->oh_chem[2] = 1.7e-12;
6861 ctl->oh_chem[3] = -0.2;
6862 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
6863 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
6864 }
6865
6866 /* Molar mass... */
6867 char defstr[LEN];
6868 sprintf(defstr, "%g", ctl->molmass);
6869 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
6870
6871 /* OH chemistry... */
6872 sprintf(defstr, "%d", ctl->oh_chem_reaction);
6873 ctl->oh_chem_reaction =
6874 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
6875 NULL);
6876 for (int ip = 0; ip < 4; ip++) {
6877 sprintf(defstr, "%g", ctl->oh_chem[ip]);
6878 ctl->oh_chem[ip] =
6879 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
6880 }
6881 ctl->oh_chem_beta =
6882 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
6883
6884 /* H2O2 chemistry... */
6885 ctl->h2o2_chem_reaction =
6886 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
6887
6888 /* KPP chemistry... */
6889 ctl->kpp_chem =
6890 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
6891 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
6892
6893 /* First order tracer chemistry... */
6894 ctl->tracer_chem =
6895 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
6896
6897 /* Radioactive decay... */
6898 ctl->radio_decay =
6899 (int) scan_ctl(filename, argc, argv, "RADIO_DECAY", -1, "0", NULL);
6900
6901 /* Wet deposition... */
6902 for (int ip = 0; ip < 2; ip++) {
6903 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
6904 ctl->wet_depo_ic_h[ip] =
6905 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
6906 }
6907 for (int ip = 0; ip < 1; ip++) {
6908 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
6909 ctl->wet_depo_bc_h[ip] =
6910 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
6911 }
6912 ctl->wet_depo_so2_ph =
6913 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
6914 ctl->wet_depo_ic_a =
6915 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
6916 ctl->wet_depo_ic_b =
6917 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
6918 ctl->wet_depo_bc_a =
6919 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
6920 ctl->wet_depo_bc_b =
6921 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
6922 ctl->wet_depo_pre[0] =
6923 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
6924 ctl->wet_depo_pre[1] =
6925 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
6927 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
6929 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
6930
6931 /* Dry deposition... */
6932 ctl->dry_depo_vdep =
6933 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
6934 ctl->dry_depo_dp =
6935 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
6936
6937 /* Climatological data... */
6938 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
6939 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
6940 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
6941 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
6942 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
6943 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
6944 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
6945 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
6946 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
6947 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
6948 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
6949 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
6950 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
6951 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
6952 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
6953 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
6954 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
6955 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
6956 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
6957 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
6958 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
6959 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
6960
6961 /* Mixing... */
6962 ctl->mixing_dt =
6963 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
6964 ctl->mixing_trop =
6965 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
6966 ctl->mixing_strat =
6967 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
6968 ctl->mixing_z0 =
6969 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
6970 ctl->mixing_z1 =
6971 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
6972 ctl->mixing_nz =
6973 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
6974 ctl->mixing_lon0 =
6975 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
6976 ctl->mixing_lon1 =
6977 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
6978 ctl->mixing_nx =
6979 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
6980 ctl->mixing_lat0 =
6981 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
6982 ctl->mixing_lat1 =
6983 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
6984 ctl->mixing_ny =
6985 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
6986
6987 /* Chemistry grid... */
6988 ctl->chemgrid_z0 =
6989 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
6990 ctl->chemgrid_z1 =
6991 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
6992 ctl->chemgrid_nz =
6993 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
6994 ctl->chemgrid_lon0 =
6995 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
6996 ctl->chemgrid_lon1 =
6997 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
6998 ctl->chemgrid_nx =
6999 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
7000 ctl->chemgrid_lat0 =
7001 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
7002 ctl->chemgrid_lat1 =
7003 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
7004 ctl->chemgrid_ny =
7005 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
7006
7007 /* Exponential decay... */
7008 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
7009 ctl->tdec_strat =
7010 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
7011
7012 /* PSC analysis... */
7013 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
7014 ctl->psc_hno3 =
7015 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
7016
7017 /* Output of atmospheric data... */
7018 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
7019 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
7020 ctl->atm_dt_out =
7021 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
7022 ctl->atm_filter =
7023 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
7024 ctl->atm_stride =
7025 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
7026 ctl->atm_type =
7027 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
7028 ctl->atm_type_out =
7029 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
7030 if (ctl->atm_type_out == -1)
7031 ctl->atm_type_out = ctl->atm_type;
7032 ctl->atm_nc_level =
7033 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
7034 for (int iq = 0; iq < ctl->nq; iq++)
7035 ctl->atm_nc_quant[iq] =
7036 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
7037 ctl->obs_type =
7038 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
7039
7040 /* Output of CSI data... */
7041 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
7042 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
7043 ctl->csi_dt_out =
7044 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
7045 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
7046 ctl->csi_obsmin =
7047 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
7048 ctl->csi_modmin =
7049 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
7050 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
7051 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
7052 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
7053 ctl->csi_lon0 =
7054 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
7055 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
7056 ctl->csi_nx =
7057 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
7058 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
7059 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
7060 ctl->csi_ny =
7061 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
7062
7063 /* Output of ensemble data... */
7064 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
7065 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
7066 ctl->ens_dt_out =
7067 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
7068
7069 /* Output of grid data... */
7070 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
7071 ctl->grid_basename);
7072 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
7073 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
7074 ctl->grid_dt_out =
7075 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
7076 ctl->grid_sparse =
7077 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
7078 ctl->grid_nc_level =
7079 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
7080 for (int iq = 0; iq < ctl->nq; iq++)
7081 ctl->grid_nc_quant[iq] =
7082 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
7083 ctl->grid_stddev =
7084 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
7085 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
7086 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
7087 ctl->grid_nz =
7088 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
7089 ctl->grid_lon0 =
7090 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
7091 ctl->grid_lon1 =
7092 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
7093 ctl->grid_nx =
7094 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
7095 ctl->grid_lat0 =
7096 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
7097 ctl->grid_lat1 =
7098 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
7099 ctl->grid_ny =
7100 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
7101 ctl->grid_type =
7102 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
7103
7104 /* Output of profile data... */
7105 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
7106 ctl->prof_basename);
7107 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
7108 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
7109 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
7110 ctl->prof_nz =
7111 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
7112 ctl->prof_lon0 =
7113 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
7114 ctl->prof_lon1 =
7115 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
7116 ctl->prof_nx =
7117 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
7118 ctl->prof_lat0 =
7119 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
7120 ctl->prof_lat1 =
7121 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
7122 ctl->prof_ny =
7123 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
7124
7125 /* Output of sample data... */
7126 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
7127 ctl->sample_basename);
7128 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
7129 ctl->sample_kernel);
7130 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
7131 ctl->sample_obsfile);
7132 ctl->sample_dx =
7133 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
7134 ctl->sample_dz =
7135 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
7136
7137 /* Output of station data... */
7138 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
7139 ctl->stat_basename);
7140 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
7141 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
7142 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
7143 ctl->stat_t0 =
7144 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
7145 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
7146
7147 /* Output of VTK data... */
7148 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
7149 ctl->vtk_dt_out =
7150 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
7151 ctl->vtk_stride =
7152 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
7153 ctl->vtk_scale =
7154 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
7155 ctl->vtk_offset =
7156 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
7157 ctl->vtk_sphere =
7158 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
7159
7160 /* Domain decomposition... */
7161 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
7163 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
7164 (ctl->dd == 1) ? "2" : "1", NULL);
7165 ctl->dd_subdomains_zonal =
7166 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
7167 (ctl->dd == 1) ? "2" : "1", NULL);
7169 ctl->dd = 1;
7170 else if (ctl->dd == 1)
7171 ERRMSG("Please provide zonal and meridional subdomain numbers!");
7172 ctl->dd_halos_size =
7173 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
7174}
7175
7176/*****************************************************************************/
7177
7179 const char *filename,
7180 const ctl_t *ctl,
7181 const clim_t *clim,
7182 met_t *met,
7183 dd_t *dd) {
7184
7185 /* Write info... */
7186 LOG(1, "Read meteo data: %s", filename);
7187
7188 /* Set rank... */
7189 int rank = 0;
7190#ifdef MPI
7191 if (ctl->met_mpi_share)
7192 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
7193#endif
7194
7195 /* Check rank... */
7196 if (!ctl->met_mpi_share || rank == 0) {
7197
7198 /* Read netCDF data... */
7199 if (ctl->met_type == 0) {
7200 if (read_met_nc(filename, ctl, met, dd) != 1)
7201 return 0;
7202 }
7203
7204 /* Read binary data... */
7205 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
7206 || ctl->met_type == 7 || ctl->met_type == 8) {
7207 if (read_met_bin(filename, ctl, met) != 1)
7208 return 0;
7209 }
7210#ifdef ECCODES
7211 /* Read grib data... */
7212 else if (ctl->met_type == 6) {
7213 if (read_met_grib(filename, ctl, met) != 1)
7214 return 0;
7215 }
7216#endif
7217
7218 /* Not implemented... */
7219 else
7220 ERRMSG("MET_TYPE not implemented!");
7221
7222 /* Preprocessing for netCDF and grib files... */
7223 if (ctl->met_type == 0 || ctl->met_type == 6) {
7224
7225 /* Extrapolate data for lower boundary... */
7227
7228 /* Fix polar winds... */
7230
7231 /* Create periodic boundary conditions... */
7232#ifndef DD
7233 read_met_periodic(met);
7234#endif
7235
7236 /* Downsampling... */
7237 read_met_sample(ctl, met);
7238
7239 /* Calculate geopotential heights... */
7240 read_met_geopot(ctl, met);
7241
7242 /* Calculate potential vorticity... */
7243 read_met_pv(met);
7244
7245 /* Calculate boundary layer data... */
7246 read_met_pbl(ctl, met);
7247
7248 /* Calculate tropopause data... */
7249 read_met_tropo(ctl, clim, met);
7250
7251 /* Calculate cloud properties... */
7252 read_met_cloud(met);
7253
7254 /* Calculate convective available potential energy... */
7255 read_met_cape(ctl, clim, met);
7256
7257 /* Calculate total column ozone... */
7258 read_met_ozone(met);
7259
7260 /* Detrending... */
7261 read_met_detrend(ctl, met);
7262
7263 /* Check meteo data and smooth zeta profiles ... */
7264 read_met_monotonize(ctl, met);
7265 }
7266 }
7267
7268 /* Broadcast data via MPI... */
7269#ifdef MPI
7270 if (ctl->met_mpi_share) {
7271
7272 /* Set timer... */
7273 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM");
7274 LOG(2, "Broadcast data on rank %d...", rank);
7275
7276 /* Broadcast... */
7277 broadcast_large_data(met, sizeof(met_t));
7278 }
7279#endif
7280
7281 /* Return success... */
7282 return 1;
7283}
7284
7285/*****************************************************************************/
7286
7288 ctl_t *ctl,
7289 cache_t *cache,
7290 clim_t *clim,
7291 met_t **met0,
7292 met_t **met1,
7293 atm_t *atm,
7294 double t,
7295 dd_t *dd) {
7296
7297 /* Initialize modules... */
7298 if (t == ctl->t_start) {
7299
7300 /* Initialize isosurface data... */
7301 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7302 module_isosurf_init(ctl, cache, *met0, *met1, atm);
7303
7304 /* Initialize advection... */
7305 module_advect_init(ctl, cache, *met0, *met1, atm);
7306
7307 /* Initialize chemistry... */
7308 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
7309 }
7310
7311 /* Set time steps of air parcels... */
7312 module_timesteps(ctl, cache, *met0, atm, t);
7313
7314 /* Sort particles... */
7315 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
7316 module_sort(ctl, *met0, atm);
7317
7318 /* Check positions (initial)... */
7319 module_position(cache, *met0, *met1, atm);
7320
7321 /* Advection... */
7322 if (ctl->advect > 0)
7323 module_advect(ctl, cache, *met0, *met1, atm);
7324
7325 /* Turbulent diffusion... */
7326 if (ctl->diffusion
7327 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
7328 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
7329 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
7330 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
7331
7332 /* Optional PBL-specific diffusion scheme... */
7333 if (ctl->diffusion && ctl->turb_pbl_scheme == 1)
7334 module_diff_pbl(ctl, cache, *met0, *met1, atm);
7335
7336 /* Mesoscale diffusion... */
7337 if (ctl->diffusion && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
7338 module_diff_meso(ctl, cache, *met0, *met1, atm);
7339
7340 /* Convection... */
7341 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
7342 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
7343 module_convection(ctl, cache, *met0, *met1, atm);
7344
7345 /* Sedimentation... */
7346 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
7347 module_sedi(ctl, cache, *met0, *met1, atm);
7348
7349 /* Isosurface... */
7350 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
7351 module_isosurf(ctl, cache, *met0, *met1, atm);
7352
7353 /* Check positions (final)... */
7354 module_position(cache, *met0, *met1, atm);
7355
7356 /* Interpolate meteo data... */
7357 if (ctl->met_dt_out > 0
7358 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
7359 module_meteo(ctl, cache, clim, *met0, *met1, atm);
7360
7361 /* Check boundary conditions (initial)... */
7362 if ((ctl->bound_lat0 < ctl->bound_lat1)
7363 && (ctl->bound_p0 > ctl->bound_p1))
7364 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
7365
7366 /* Initialize quantity of total loss rate... */
7367 if (ctl->qnt_loss_rate >= 0) {
7368 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
7369 atm->q[ctl->qnt_loss_rate][ip] = 0;
7370 }
7371 }
7372
7373 /* Decay of particle mass... */
7374 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
7375 module_decay(ctl, cache, clim, atm);
7376
7377 /* Interparcel mixing... */
7378 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
7379 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
7380 module_mixing(ctl, clim, atm, t);
7381
7382 /* Calculate the tracer vmr in the chemistry grid... */
7383 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
7384 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
7385 module_chem_grid(ctl, *met0, *met1, atm, t);
7386
7387 /* OH chemistry... */
7388 if (ctl->oh_chem_reaction != 0)
7389 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
7390
7391 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
7392 if (ctl->h2o2_chem_reaction != 0)
7393 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
7394
7395 /* First-order tracer chemistry... */
7396 if (ctl->tracer_chem)
7397 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
7398
7399 /* Radioactive decay... */
7400 if (ctl->radio_decay)
7401 module_radio_decay(ctl, cache, atm);
7402
7403 /* Domain decomposition... */
7404 if (ctl->dd) {
7405#ifdef DD
7406 module_dd(ctl, cache, dd, atm, met0);
7407#else
7408 ERRMSG("Code was compiled without DD!");
7409
7410 /* This will never execute, hack to avoid compilation error... */
7411 LOG(3, "%d", dd->nx_glob);
7412#endif
7413 }
7414
7415 /* KPP chemistry... */
7416 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
7417#ifdef KPP
7418 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
7419#else
7420 ERRMSG("Code was compiled without KPP!");
7421#endif
7422 }
7423
7424 /* Wet deposition... */
7425 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
7426 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
7427 module_wet_depo(ctl, cache, *met0, *met1, atm);
7428
7429 /* Dry deposition... */
7430 if (ctl->dry_depo_vdep > 0)
7431 module_dry_depo(ctl, cache, *met0, *met1, atm);
7432
7433 /* Check boundary conditions (final)... */
7434 if ((ctl->bound_lat0 < ctl->bound_lat1)
7435 && (ctl->bound_p0 > ctl->bound_p1))
7436 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
7437}
7438
7439/*****************************************************************************/
7440
7442 const ctl_t *ctl,
7443 const cache_t *cache,
7444 const clim_t *clim,
7445 met_t **met0,
7446 met_t **met1,
7447 const atm_t *atm) {
7448
7449 /* Update GPU... */
7450 if (ctl != NULL) {
7451#ifdef _OPENACC
7452 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7453#pragma acc update device(ctl[:1])
7454#endif
7455 }
7456
7457 if (cache != NULL) {
7458#ifdef _OPENACC
7459 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7460#pragma acc update device(cache[:1])
7461#endif
7462 }
7463
7464 if (clim != NULL) {
7465#ifdef _OPENACC
7466 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7467#pragma acc update device(clim[:1])
7468#endif
7469 }
7470
7471 if (met0 != NULL) {
7472#ifdef _OPENACC
7473 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7474 met_t *met0up = *met0;
7475#pragma acc update device(met0up[:1])
7476#endif
7477 }
7478
7479 if (met1 != NULL) {
7480#ifdef _OPENACC
7481 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7482 met_t *met1up = *met1;
7483#pragma acc update device(met1up[:1])
7484#endif
7485 }
7486
7487 if (atm != NULL) {
7488#ifdef _OPENACC
7489 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
7490#pragma acc update device(atm[:1])
7491#endif
7492 }
7493}
7494
7495/*****************************************************************************/
7496
7498 const ctl_t *ctl,
7499 const cache_t *cache,
7500 const clim_t *clim,
7501 met_t **met0,
7502 met_t **met1,
7503 const atm_t *atm) {
7504
7505 /* Update GPU... */
7506 if (ctl != NULL) {
7507#ifdef _OPENACC
7508 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7509#pragma acc update host(ctl[:1])
7510#endif
7511 }
7512
7513 if (cache != NULL) {
7514#ifdef _OPENACC
7515 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7516#pragma acc update host(cache[:1])
7517#endif
7518 }
7519
7520 if (clim != NULL) {
7521#ifdef _OPENACC
7522 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7523#pragma acc update host(clim[:1])
7524#endif
7525 }
7526
7527 if (met0 != NULL) {
7528#ifdef _OPENACC
7529 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7530 met_t *met0up = *met0;
7531#pragma acc update host(met0up[:1])
7532#endif
7533 }
7534
7535 if (met1 != NULL) {
7536#ifdef _OPENACC
7537 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7538 met_t *met1up = *met1;
7539#pragma acc update host(met1up[:1])
7540#endif
7541 }
7542
7543 if (atm != NULL) {
7544#ifdef _OPENACC
7545 SELECT_TIMER("UPDATE_HOST", "MEMORY");
7546#pragma acc update host(atm[:1])
7547#endif
7548 }
7549}
7550
7551/*****************************************************************************/
7552
7554 const char *filename,
7555 const ctl_t *ctl,
7556 const atm_t *atm,
7557 const double t) {
7558
7559 /* Set timer... */
7560 SELECT_TIMER("WRITE_ATM", "OUTPUT");
7561
7562 /* Write info... */
7563 LOG(1, "Write atmospheric data: %s", filename);
7564
7565 /* Write ASCII data... */
7566 if (ctl->atm_type_out == 0)
7567 write_atm_asc(filename, ctl, atm, t);
7568
7569 /* Write binary data... */
7570 else if (ctl->atm_type_out == 1)
7571 write_atm_bin(filename, ctl, atm);
7572
7573 /* Write netCDF data... */
7574 else if (ctl->atm_type_out == 2)
7575 write_atm_nc(filename, ctl, atm);
7576
7577 /* Write CLaMS trajectory data... */
7578 else if (ctl->atm_type_out == 3)
7579 write_atm_clams_traj(filename, ctl, atm, t);
7580
7581 /* Write CLaMS pos data... */
7582 else if (ctl->atm_type_out == 4)
7583 write_atm_clams(filename, ctl, atm);
7584
7585 /* Error... */
7586 else
7587 ERRMSG("Atmospheric data type not supported!");
7588
7589 /* Write info... */
7590 double mini, maxi;
7591 LOG(2, "Number of particles: %d", atm->np);
7592 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
7593 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
7594 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
7595 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
7596 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
7597 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
7598 LOG(2, "%s range: %g ... %g %s",
7599 ctl->met_coord_type == 0 ? "Longitude" : "X coordinate", mini, maxi,
7600 ctl->met_coord_type == 0 ? "deg" : "m");
7601 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
7602 LOG(2, "%s range: %g ... %g %s",
7603 ctl->met_coord_type == 0 ? "Latitude" : "Y coordinate", mini, maxi,
7604 ctl->met_coord_type == 0 ? "deg" : "m");
7605 for (int iq = 0; iq < ctl->nq; iq++) {
7606 char msg[5 * LEN];
7607 sprintf(msg, "Quantity %s range: %s ... %s %s",
7608 ctl->qnt_name[iq], ctl->qnt_format[iq],
7609 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
7610 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
7611 LOG(2, msg, mini, maxi);
7612 }
7613}
7614
7615/*****************************************************************************/
7616
7618 const char *filename,
7619 const ctl_t *ctl,
7620 met_t *met) {
7621
7622 /* Set timer... */
7623 SELECT_TIMER("WRITE_MET", "OUTPUT");
7624
7625 /* Write info... */
7626 LOG(1, "Write meteo data: %s", filename);
7627
7628 /* Check compression flags... */
7629#ifndef ZFP
7630 if (ctl->met_type == 3)
7631 ERRMSG("MPTRAC was compiled without ZFP compression!");
7632#endif
7633#ifndef ZSTD
7634 if (ctl->met_type == 4)
7635 ERRMSG("MPTRAC was compiled without ZSTD compression!");
7636#endif
7637#ifndef LZ4
7638 if (ctl->met_type == 8)
7639 ERRMSG("MPTRAC was compiled without LZ4 compression!");
7640#endif
7641#ifndef CMS
7642 if (ctl->met_type == 5)
7643 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
7644#endif
7645#ifndef SZ3
7646 if (ctl->met_type == 7)
7647 ERRMSG("MPTRAC was compiled without SZ3 compression!");
7648#endif
7649
7650 /* Write netCDF data... */
7651 if (ctl->met_type == 0)
7652 write_met_nc(filename, ctl, met);
7653
7654 /* Write binary data... */
7655 else if ((ctl->met_type >= 1 && ctl->met_type <= 5)
7656 || ctl->met_type == 7 || ctl->met_type == 8)
7657 write_met_bin(filename, ctl, met);
7658
7659 /* Not implemented... */
7660 else
7661 ERRMSG("MET_TYPE not implemented!");
7662}
7663
7664/*****************************************************************************/
7665
7667 const char *dirname,
7668 const ctl_t *ctl,
7669 met_t *met0,
7670 met_t *met1,
7671 atm_t *atm,
7672 const double t) {
7673
7674 char ext[10], filename[2 * LEN];
7675
7676 double r;
7677
7678 int year, mon, day, hour, min, sec;
7679
7680 /* Get time... */
7681 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
7682
7683 /* Update host... */
7684 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
7685 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
7686 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
7687 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
7688 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
7689 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
7690 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
7691
7692 /* Write atmospheric data... */
7693 if (ctl->atm_basename[0] != '-' &&
7694 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
7695 if (ctl->atm_type_out == 0)
7696 sprintf(ext, "tab");
7697 else if (ctl->atm_type_out == 1)
7698 sprintf(ext, "bin");
7699 else if (ctl->atm_type_out >= 2)
7700 sprintf(ext, "nc");
7701 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
7702 dirname, ctl->atm_basename, year, mon, day, hour, min, sec, ext);
7703 mptrac_write_atm(filename, ctl, atm, t);
7704 }
7705
7706 /* Write gridded data... */
7707 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
7708 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.%s",
7709 dirname, ctl->grid_basename, year, mon, day, hour, min, sec,
7710 ctl->grid_type == 0 ? "tab" : "nc");
7711 write_grid(filename, ctl, met0, met1, atm, t);
7712 }
7713
7714 /* Write CSI data... */
7715 if (ctl->csi_basename[0] != '-') {
7716 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
7717 write_csi(filename, ctl, atm, t);
7718 }
7719
7720 /* Write ensemble data... */
7721 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
7722 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d_%02d.tab",
7723 dirname, ctl->ens_basename, year, mon, day, hour, min, sec);
7724 write_ens(filename, ctl, atm, t);
7725 }
7726
7727 /* Write profile data... */
7728 if (ctl->prof_basename[0] != '-') {
7729 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
7730 write_prof(filename, ctl, met0, met1, atm, t);
7731 }
7732
7733 /* Write sample data... */
7734 if (ctl->sample_basename[0] != '-') {
7735 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
7736 write_sample(filename, ctl, met0, met1, atm, t);
7737 }
7738
7739 /* Write station data... */
7740 if (ctl->stat_basename[0] != '-') {
7741 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
7742 write_station(filename, ctl, atm, t);
7743 }
7744
7745 /* Write VTK data... */
7746 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
7747 static int nvtk;
7748 if (t == ctl->t_start)
7749 nvtk = 0;
7750 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
7751 write_vtk(filename, ctl, atm, t);
7752 }
7753}
7754
7755/*****************************************************************************/
7756
7758 const double p,
7759 const double h2o,
7760 const double hno3) {
7761
7762 /* Check water vapor volume mixing ratio... */
7763 const double h2o_help = MAX(h2o, 0.1e-6);
7764
7765 /* Calculate T_NAT... */
7766 const double p_hno3 = hno3 * p / 1.333224;
7767 const double p_h2o = h2o_help * p / 1.333224;
7768 const double a = 0.009179 - 0.00088 * log10(p_h2o);
7769 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
7770 const double c = -11397.0 / a;
7771 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
7772 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
7773 if (x2 > 0)
7774 tnat = x2;
7775
7776 return tnat;
7777}
7778
7779/*****************************************************************************/
7780
7782 const ctl_t *ctl,
7783 const atm_t *atm,
7784 const int ip,
7785 const double pbl,
7786 const double ps) {
7787
7788 /* Get pressure range... */
7789 const double p1 = pbl - ctl->turb_pbl_trans * (ps - pbl);
7790 const double p0 = pbl;
7791
7792 /* Get weighting factor... */
7793 if (atm->p[ip] > p0)
7794 return 1;
7795 else if (atm->p[ip] < p1)
7796 return 0;
7797 else
7798 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
7799}
7800
7801/*****************************************************************************/
7802
7804 const char *filename,
7805 const ctl_t *ctl,
7806 atm_t *atm) {
7807
7808 /* Open file... */
7809 FILE *in;
7810 if (!(in = fopen(filename, "r"))) {
7811 WARN("Cannot open file!");
7812 return 0;
7813 }
7814
7815 /* Read line... */
7816 char line[LEN];
7817 while (fgets(line, LEN, in)) {
7818
7819 /* Read data... */
7820 char *tok;
7821 TOK(line, tok, "%lg", atm->time[atm->np]);
7822 TOK(NULL, tok, "%lg", atm->p[atm->np]);
7823 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
7824 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
7825 for (int iq = 0; iq < ctl->nq; iq++)
7826 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
7827
7828 /* Convert altitude to pressure... */
7829 atm->p[atm->np] = P(atm->p[atm->np]);
7830
7831 /* Increment data point counter... */
7832 if ((++atm->np) > NP)
7833 ERRMSG("Too many data points!");
7834 }
7835
7836 /* Close file... */
7837 fclose(in);
7838
7839 /* Return success... */
7840 return 1;
7841}
7842
7843/*****************************************************************************/
7844
7846 const char *filename,
7847 const ctl_t *ctl,
7848 atm_t *atm) {
7849
7850 /* Open file... */
7851 FILE *in;
7852 if (!(in = fopen(filename, "r")))
7853 return 0;
7854
7855 /* Check version of binary data... */
7856 int version;
7857 FREAD(&version, int,
7858 1,
7859 in);
7860 if (version != 100)
7861 ERRMSG("Wrong version of binary data!");
7862
7863 /* Read data... */
7864 FREAD(&atm->np, int,
7865 1,
7866 in);
7867 FREAD(atm->time, double,
7868 (size_t) atm->np,
7869 in);
7870 FREAD(atm->p, double,
7871 (size_t) atm->np,
7872 in);
7873 FREAD(atm->lon, double,
7874 (size_t) atm->np,
7875 in);
7876 FREAD(atm->lat, double,
7877 (size_t) atm->np,
7878 in);
7879 for (int iq = 0; iq < ctl->nq; iq++)
7880 FREAD(atm->q[iq], double,
7881 (size_t) atm->np,
7882 in);
7883
7884 /* Read final flag... */
7885 int final;
7886 FREAD(&final, int,
7887 1,
7888 in);
7889 if (final != 999)
7890 ERRMSG("Error while reading binary data!");
7891
7892 /* Close file... */
7893 fclose(in);
7894
7895 /* Return success... */
7896 return 1;
7897}
7898
7899/*****************************************************************************/
7900
7902 const char *filename,
7903 const ctl_t *ctl,
7904 atm_t *atm) {
7905
7906 if (ctl->met_coord_type != 0)
7907 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
7908
7909 int ncid, varid;
7910
7911 /* Open file... */
7912 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7913 return 0;
7914
7915 /* Get dimensions... */
7916 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
7917
7918 /* Get time... */
7919 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
7920 NC(nc_get_var_double(ncid, varid, atm->time));
7921 } else {
7922 WARN("TIME_INIT not found use time instead!");
7923 double time_init;
7924 NC_GET_DOUBLE("time", &time_init, 1);
7925 for (int ip = 0; ip < atm->np; ip++) {
7926 atm->time[ip] = time_init;
7927 }
7928 }
7929
7930 /* Read zeta coordinate, pressure is optional... */
7931 if (ctl->advect_vert_coord == 1) {
7932 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
7933 NC_GET_DOUBLE("PRESS", atm->p, 0);
7934 }
7935
7936 /* Read pressure, zeta coordinate is optional... */
7937 else {
7938 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
7939 NC(nc_get_var_double(ncid, varid, atm->p));
7940 } else {
7941 WARN("PRESS_INIT not found use PRESS instead!");
7942 nc_inq_varid(ncid, "PRESS", &varid);
7943 NC(nc_get_var_double(ncid, varid, atm->p));
7944 }
7945 }
7946
7947 /* Read further quantities if requested... */
7948 for (int iq = 0; iq < ctl->nq; iq++)
7949 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7950
7951 /* Read longitude and latitude... */
7952 NC_GET_DOUBLE("LON", atm->lon, 1);
7953 NC_GET_DOUBLE("LAT", atm->lat, 1);
7954
7955 /* Close file... */
7956 NC(nc_close(ncid));
7957
7958 /* Return success... */
7959 return 1;
7960}
7961
7962/*****************************************************************************/
7963
7965 const char *filename,
7966 const ctl_t *ctl,
7967 atm_t *atm) {
7968
7969 int ncid, varid;
7970
7971 /* Open file... */
7972 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7973 return 0;
7974
7975 /* Get dimensions... */
7976 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
7977
7978 /* Read geolocations... */
7979 NC_GET_DOUBLE("time", atm->time, 1);
7980 NC_GET_DOUBLE("press", atm->p, 1);
7981 NC_GET_DOUBLE("lon", atm->lon, 1);
7982 NC_GET_DOUBLE("lat", atm->lat, 1);
7983
7984 /* Read variables... */
7985 for (int iq = 0; iq < ctl->nq; iq++)
7986 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7987
7988 /* Close file... */
7989 NC(nc_close(ncid));
7990
7991 /* Return success... */
7992 return 1;
7993}
7994
7995/*****************************************************************************/
7996
7998 const char *filename,
7999 clim_photo_t *photo) {
8000
8001 int ncid, varid;
8002
8003 /* Write info... */
8004 LOG(1, "Read photolysis rates: %s", filename);
8005
8006 /* Open netCDF file... */
8007 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8008 WARN("Photolysis rate data are missing!");
8009 return;
8010 }
8011
8012 /* Read pressure data... */
8013 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
8014 NC_GET_DOUBLE("press", photo->p, 1);
8015 if (photo->p[0] < photo->p[1])
8016 ERRMSG("Pressure data are not descending!");
8017
8018 /* Read total column ozone data... */
8019 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
8020 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
8021 if (photo->o3c[0] > photo->o3c[1])
8022 ERRMSG("Total column ozone data are not ascending!");
8023
8024 /* Read solar zenith angle data... */
8025 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
8026 NC_GET_DOUBLE("sza", photo->sza, 1);
8027 if (photo->sza[0] > photo->sza[1])
8028 ERRMSG("Solar zenith angle data are not ascending!");
8029
8030 /* Read data... */
8031 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
8032 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
8033 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
8034 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
8035 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
8036 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
8037 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
8038 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
8039 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
8040
8041 /* Close netCDF file... */
8042 NC(nc_close(ncid));
8043
8044 /* Write info... */
8045 LOG(2, "Number of pressure levels: %d", photo->np);
8046 LOG(2, "Altitude levels: %g, %g ... %g km",
8047 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
8048 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8049 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
8050 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
8051 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
8052 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
8053 RAD2DEG(photo->sza[photo->nsza - 1]));
8054 LOG(2, "Number of total column ozone values: %d", photo->no3c);
8055 LOG(2, "Total column ozone: %g, %g ... %g DU",
8056 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
8057 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
8058 photo->n2o[0][0][0], photo->n2o[1][0][0],
8059 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8060 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
8061 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
8062 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8063 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
8064 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
8065 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8066 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
8067 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
8068 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8069 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
8070 photo->o2[0][0][0], photo->o2[1][0][0],
8071 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8072 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
8073 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
8074 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8075 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
8076 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
8077 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8078 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
8079 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
8080 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8081 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
8082 photo->h2o[0][0][0], photo->h2o[1][0][0],
8083 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
8084}
8085
8086/*****************************************************************************/
8087
8089 const int ncid,
8090 const char *varname,
8091 const clim_photo_t *photo,
8092 double var[CP][CSZA][CO3]) {
8093
8094 /* Allocate... */
8095 double *help;
8096 ALLOC(help, double,
8097 photo->np * photo->nsza * photo->no3c);
8098
8099 /* Read varible... */
8100 int varid;
8101 NC_GET_DOUBLE(varname, help, 1);
8102
8103 /* Copy data... */
8104 for (int ip = 0; ip < photo->np; ip++)
8105 for (int is = 0; is < photo->nsza; is++)
8106 for (int io = 0; io < photo->no3c; io++)
8107 var[ip][is][io] =
8108 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
8109
8110 /* Free... */
8111 free(help);
8112}
8113
8114/*****************************************************************************/
8115
8117 const char *filename,
8118 clim_ts_t *ts) {
8119
8120 /* Write info... */
8121 LOG(1, "Read climatological time series: %s", filename);
8122
8123 /* Open file... */
8124 FILE *in;
8125 if (!(in = fopen(filename, "r"))) {
8126 WARN("Cannot open file!");
8127 return 0;
8128 }
8129
8130 /* Read data... */
8131 char line[LEN];
8132 int nh = 0;
8133 while (fgets(line, LEN, in))
8134 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
8135
8136 /* Convert years to seconds... */
8137 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
8138
8139 /* Check data... */
8140 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
8141 ERRMSG("Time series must be ascending!");
8142
8143 /* Count time steps... */
8144 if ((++nh) >= CTS)
8145 ERRMSG("Too many data points!");
8146 }
8147
8148 /* Close file... */
8149 fclose(in);
8150
8151 /* Check number of data points... */
8152 ts->ntime = nh;
8153 if (nh < 2)
8154 ERRMSG("Not enough data points!");
8155
8156 /* Write info... */
8157 LOG(2, "Number of time steps: %d", ts->ntime);
8158 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
8159 ts->time[nh - 1]);
8160 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
8161 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
8162 (size_t) nh));
8163
8164 /* Exit success... */
8165 return 1;
8166}
8167
8168/*****************************************************************************/
8169
8171 const char *filename,
8172 const char *varname,
8173 clim_zm_t *zm) {
8174
8175 int ncid, varid, it, iy, iz, iz2, nt;
8176
8177 double *help, varmin = 1e99, varmax = -1e99;
8178
8179 /* Write info... */
8180 LOG(1, "Read %s data: %s", varname, filename);
8181
8182 /* Open netCDF file... */
8183 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8184 WARN("%s climatology data are missing!", varname);
8185 return;
8186 }
8187
8188 /* Read pressure data... */
8189 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
8190 NC_GET_DOUBLE("press", zm->p, 1);
8191 if (zm->p[0] < zm->p[1])
8192 ERRMSG("Pressure data are not descending!");
8193
8194 /* Read latitudes... */
8195 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
8196 NC_GET_DOUBLE("lat", zm->lat, 1);
8197 if (zm->lat[0] > zm->lat[1])
8198 ERRMSG("Latitude data are not ascending!");
8199
8200 /* Set time data (for monthly means)... */
8201 zm->ntime = 12;
8202 zm->time[0] = 1209600.00;
8203 zm->time[1] = 3888000.00;
8204 zm->time[2] = 6393600.00;
8205 zm->time[3] = 9072000.00;
8206 zm->time[4] = 11664000.00;
8207 zm->time[5] = 14342400.00;
8208 zm->time[6] = 16934400.00;
8209 zm->time[7] = 19612800.00;
8210 zm->time[8] = 22291200.00;
8211 zm->time[9] = 24883200.00;
8212 zm->time[10] = 27561600.00;
8213 zm->time[11] = 30153600.00;
8214
8215 /* Check number of timesteps... */
8216 NC_INQ_DIM("time", &nt, 12, 12, 1);
8217
8218 /* Read data... */
8219 ALLOC(help, double,
8220 zm->nlat * zm->np * zm->ntime);
8221 NC_GET_DOUBLE(varname, help, 1);
8222 for (it = 0; it < zm->ntime; it++)
8223 for (iz = 0; iz < zm->np; iz++)
8224 for (iy = 0; iy < zm->nlat; iy++)
8225 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
8226 free(help);
8227
8228 /* Fix data gaps... */
8229 for (it = 0; it < zm->ntime; it++)
8230 for (iy = 0; iy < zm->nlat; iy++)
8231 for (iz = 0; iz < zm->np; iz++) {
8232 if (zm->vmr[it][iz][iy] < 0) {
8233 for (iz2 = 0; iz2 < zm->np; iz2++)
8234 if (zm->vmr[it][iz2][iy] >= 0) {
8235 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8236 break;
8237 }
8238 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
8239 if (zm->vmr[it][iz2][iy] >= 0) {
8240 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
8241 break;
8242 }
8243 }
8244 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
8245 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
8246 }
8247
8248 /* Close netCDF file... */
8249 NC(nc_close(ncid));
8250
8251 /* Write info... */
8252 LOG(2, "Number of time steps: %d", zm->ntime);
8253 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
8254 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
8255 LOG(2, "Number of pressure levels: %d", zm->np);
8256 LOG(2, "Altitude levels: %g, %g ... %g km",
8257 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
8258 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
8259 zm->p[1], zm->p[zm->np - 1]);
8260 LOG(2, "Number of latitudes: %d", zm->nlat);
8261 LOG(2, "Latitudes: %g, %g ... %g deg",
8262 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
8263 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
8264 varmax);
8265}
8266
8267/*****************************************************************************/
8268
8270 const char *filename,
8271 double kz[EP],
8272 double kw[EP],
8273 int *nk) {
8274
8275 /* Write info... */
8276 LOG(1, "Read kernel function: %s", filename);
8277
8278 /* Open file... */
8279 FILE *in;
8280 if (!(in = fopen(filename, "r")))
8281 ERRMSG("Cannot open file!");
8282
8283 /* Read data... */
8284 char line[LEN];
8285 int n = 0;
8286 while (fgets(line, LEN, in))
8287 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
8288 if (n > 0 && kz[n] < kz[n - 1])
8289 ERRMSG("Height levels must be ascending!");
8290 if ((++n) >= EP)
8291 ERRMSG("Too many height levels!");
8292 }
8293
8294 /* Close file... */
8295 fclose(in);
8296
8297 /* Check number of data points... */
8298 *nk = n;
8299 if (n < 2)
8300 ERRMSG("Not enough height levels!");
8301
8302 /* Normalize kernel function... */
8303 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
8304 for (int iz = 0; iz < n; iz++)
8305 kw[iz] /= kmax;
8306}
8307
8308/*****************************************************************************/
8309
8311 const char *filename,
8312 const ctl_t *ctl,
8313 met_t *met) {
8314
8315 FILE *in;
8316
8317 double r;
8318
8319 int year, mon, day, hour, min, sec;
8320
8321 /* Set timer... */
8322 SELECT_TIMER("READ_MET_BIN", "INPUT");
8323
8324 /* Open file... */
8325 if (!(in = fopen(filename, "r"))) {
8326 WARN("Cannot open file!");
8327 return 0;
8328 }
8329
8330 /* Check type of binary data... */
8331 int met_type;
8332 FREAD(&met_type, int,
8333 1,
8334 in);
8335 if (met_type != ctl->met_type)
8336 ERRMSG("Wrong MET_TYPE of binary data!");
8337
8338 /* Check version of binary data... */
8339 int version;
8340 FREAD(&version, int,
8341 1,
8342 in);
8343 if (version != 104)
8344 ERRMSG("Wrong version of binary data!");
8345
8346 /* Read time... */
8347 FREAD(&met->time, double,
8348 1,
8349 in);
8350 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8351 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8352 met->time, year, mon, day, hour, min);
8353 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8354 || day < 1 || day > 31 || hour < 0 || hour > 23)
8355 ERRMSG("Error while reading time!");
8356
8357 /* Read dimensions... */
8358 met->coord_type = ctl->met_coord_type;
8359
8360 FREAD(&met->nx, int,
8361 1,
8362 in);
8363 LOG(2, "Number of %s: %d",
8364 (met->coord_type == 0) ? "longitudes" : "x coordinates", met->nx);
8365 if (met->nx < 2 || met->nx > EX)
8366 ERRMSG(met->coord_type == 0
8367 ? "Number of longitudes out of range!"
8368 : "Number of x coordinates out of range!");
8369
8370 FREAD(&met->ny, int,
8371 1,
8372 in);
8373 LOG(2, "Number of %s: %d",
8374 (met->coord_type == 0) ? "latitudes" : "y coordinates", met->ny);
8375 if (met->ny < 2 || met->ny > EY)
8376 ERRMSG(met->coord_type == 0
8377 ? "Number of latitudes out of range!"
8378 : "Number of y coordinates out of range!");
8379
8380 FREAD(&met->np, int,
8381 1,
8382 in);
8383 LOG(2, "Number of levels: %d", met->np);
8384 if (met->np < 2 || met->np > EP)
8385 ERRMSG("Number of levels out of range!");
8386
8387 /* Read grid... */
8388 FREAD(met->lon, double,
8389 (size_t) met->nx,
8390 in);
8391 LOG(2, "%s: %g, %g ... %g %s",
8392 met->coord_type == 0 ? "Longitudes" : "X coordinates",
8393 met->lon[0], met->lon[1], met->lon[met->nx - 1],
8394 met->coord_type == 0 ? "deg" : "m");
8395
8396 FREAD(met->lat, double,
8397 (size_t) met->ny,
8398 in);
8399 LOG(2, "%s: %g, %g ... %g %s",
8400 met->coord_type == 0 ? "Latitudes" : "Y coordinates",
8401 met->lat[0], met->lat[1], met->lat[met->ny - 1],
8402 met->coord_type == 0 ? "deg" : "m");
8403
8404 FREAD(met->p, double,
8405 (size_t) met->np,
8406 in);
8407 LOG(2, "Altitude levels: %g, %g ... %g km",
8408 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
8409 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8410 met->p[0], met->p[1], met->p[met->np - 1]);
8411
8412 /* Read surface data... */
8413 read_met_bin_2d(in, met, met->ps, "PS");
8414 read_met_bin_2d(in, met, met->ts, "TS");
8415 read_met_bin_2d(in, met, met->zs, "ZS");
8416 read_met_bin_2d(in, met, met->us, "US");
8417 read_met_bin_2d(in, met, met->vs, "VS");
8418 read_met_bin_2d(in, met, met->ess, "ESS");
8419 read_met_bin_2d(in, met, met->nss, "NSS");
8420 read_met_bin_2d(in, met, met->shf, "SHF");
8421 read_met_bin_2d(in, met, met->lsm, "LSM");
8422 read_met_bin_2d(in, met, met->sst, "SST");
8423 read_met_bin_2d(in, met, met->pbl, "PBL");
8424 read_met_bin_2d(in, met, met->pt, "PT");
8425 read_met_bin_2d(in, met, met->tt, "TT");
8426 read_met_bin_2d(in, met, met->zt, "ZT");
8427 read_met_bin_2d(in, met, met->h2ot, "H2OT");
8428 read_met_bin_2d(in, met, met->pct, "PCT");
8429 read_met_bin_2d(in, met, met->pcb, "PCB");
8430 read_met_bin_2d(in, met, met->cl, "CL");
8431 read_met_bin_2d(in, met, met->plcl, "PLCL");
8432 read_met_bin_2d(in, met, met->plfc, "PLFC");
8433 read_met_bin_2d(in, met, met->pel, "PEL");
8434 read_met_bin_2d(in, met, met->cape, "CAPE");
8435 read_met_bin_2d(in, met, met->cin, "CIN");
8436 read_met_bin_2d(in, met, met->o3c, "O3C");
8437
8438 /* Read level data... */
8439 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
8440 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
8441 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
8442 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
8443 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
8444 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
8445 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
8446 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
8447 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
8448 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
8449 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
8450 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
8451 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
8452
8453 /* Read final flag... */
8454 int final;
8455 FREAD(&final, int,
8456 1,
8457 in);
8458 if (final != 999)
8459 ERRMSG("Error while reading binary data!");
8460
8461 /* Close file... */
8462 fclose(in);
8463
8464 /* Return success... */
8465 return 1;
8466}
8467
8468/*****************************************************************************/
8469
8471 FILE *in,
8472 const met_t *met,
8473 float var[EX][EY],
8474 const char *varname) {
8475
8476 float *help;
8477
8478 /* Allocate... */
8479 ALLOC(help, float,
8480 EX * EY);
8481
8482 /* Read uncompressed... */
8483 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
8484 FREAD(help, float,
8485 (size_t) (met->nx * met->ny),
8486 in);
8487
8488 /* Copy data... */
8489 for (int ix = 0; ix < met->nx; ix++)
8490 for (int iy = 0; iy < met->ny; iy++)
8491 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
8492
8493 /* Free... */
8494 free(help);
8495}
8496
8497/*****************************************************************************/
8498
8500 FILE *in,
8501 const ctl_t *ctl,
8502 const met_t *met,
8503 float var[EX][EY][EP],
8504 const char *varname,
8505 const float bound_min,
8506 const float bound_max) {
8507
8508 float *help;
8509
8510 /* Allocate... */
8511 ALLOC(help, float,
8512 EX * EY * EP);
8513
8514 /* Read uncompressed data... */
8515 if (ctl->met_type == 1) {
8516 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
8517 FREAD(help, float,
8518 (size_t) (met->nx * met->ny * met->np),
8519 in);
8520 }
8521
8522 /* Read packed data... */
8523 else if (ctl->met_type == 2)
8524 compress_pck(ctl, met, varname, help, 1, NULL, in);
8525
8526 /* Read ZFP data... */
8527 else if (ctl->met_type == 3) {
8528#ifdef ZFP
8529 int precision;
8530 FREAD(&precision, int,
8531 1,
8532 in);
8533
8534 double tolerance;
8535 FREAD(&tolerance, double,
8536 1,
8537 in);
8538
8539 compress_zfp(ctl, met, varname, help, 1, NULL, in);
8540#else
8541 ERRMSG("MPTRAC was compiled without ZFP compression!");
8542#endif
8543 }
8544
8545 /* Read zstd data... */
8546 else if (ctl->met_type == 4) {
8547#ifdef ZSTD
8548 compress_zstd(ctl, met, varname, help, 1, NULL, in);
8549#else
8550 ERRMSG("MPTRAC was compiled without ZSTD compression!");
8551#endif
8552 }
8553
8554 /* Read LZ4 data... */
8555 else if (ctl->met_type == 8) {
8556#ifdef LZ4
8557 compress_lz4(ctl, met, varname, help, 1, NULL, in);
8558#else
8559 ERRMSG("MPTRAC was compiled without LZ4 compression!");
8560#endif
8561 }
8562
8563 /* Read cmultiscale data... */
8564 else if (ctl->met_type == 5) {
8565#ifdef CMS
8566 compress_cms(ctl, met, varname, help, 1, NULL, in);
8567#else
8568 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
8569#endif
8570 }
8571
8572 /* Read SZ3 data... */
8573 else if (ctl->met_type == 7) {
8574#ifdef SZ3
8575 int precision;
8576 FREAD(&precision, int,
8577 1,
8578 in);
8579
8580 double tolerance;
8581 FREAD(&tolerance, double,
8582 1,
8583 in);
8584
8585 compress_sz3(ctl, met, varname, help, 1, NULL, in);
8586#else
8587 ERRMSG("MPTRAC was compiled without sz3 compression!");
8588#endif
8589 }
8590
8591 /* Copy data... */
8592#pragma omp parallel for default(shared) collapse(2)
8593 for (int ix = 0; ix < met->nx; ix++)
8594 for (int iy = 0; iy < met->ny; iy++)
8595 for (int ip = 0; ip < met->np; ip++) {
8596 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
8597 if (var[ix][iy][ip] < bound_min)
8598 var[ix][iy][ip] = bound_min;
8599 else if (var[ix][iy][ip] > bound_max)
8600 var[ix][iy][ip] = bound_max;
8601 }
8602
8603 /* Free... */
8604 free(help);
8605}
8606
8607/*****************************************************************************/
8608
8610 const ctl_t *ctl,
8611 const clim_t *clim,
8612 met_t *met) {
8613
8614 /* Check parameters... */
8615 if (ctl->met_cape != 1)
8616 return;
8617
8618 if (ctl->met_coord_type != 0)
8619 ERRMSG("Only lat/lon grid supported");
8620
8621 /* Set timer... */
8622 SELECT_TIMER("READ_MET_CAPE", "METPROC");
8623 LOG(2, "Calculate CAPE...");
8624
8625 /* Vertical spacing (about 100 m)... */
8626 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
8627
8628 /* Loop over columns... */
8629#pragma omp parallel for default(shared) collapse(2)
8630 for (int ix = 0; ix < met->nx; ix++)
8631 for (int iy = 0; iy < met->ny; iy++) {
8632
8633 /* Get potential temperature and water vapor at lowest 50 hPa... */
8634 int n = 0;
8635 double h2o = 0, t, theta = 0;
8636 double pbot = MIN(met->ps[ix][iy], met->p[0]);
8637 double ptop = pbot - 50.;
8638 for (int ip = 0; ip < met->np; ip++) {
8639 if (met->p[ip] <= pbot) {
8640 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
8641 h2o += met->h2o[ix][iy][ip];
8642 n++;
8643 }
8644 if (met->p[ip] < ptop && n > 0)
8645 break;
8646 }
8647 theta /= n;
8648 h2o /= n;
8649
8650 /* Cannot compute anything if water vapor is missing... */
8651 met->plcl[ix][iy] = NAN;
8652 met->plfc[ix][iy] = NAN;
8653 met->pel[ix][iy] = NAN;
8654 met->cape[ix][iy] = NAN;
8655 met->cin[ix][iy] = NAN;
8656 if (h2o <= 0)
8657 continue;
8658
8659 /* Find lifted condensation level (LCL)... */
8660 ptop = P(20.);
8661 pbot = met->ps[ix][iy];
8662 do {
8663 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
8664 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
8665 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
8666 ptop = met->plcl[ix][iy];
8667 else
8668 pbot = met->plcl[ix][iy];
8669 } while (pbot - ptop > 0.1);
8670
8671 /* Calculate CIN up to LCL... */
8673 double dcape, dz, h2o_env, t_env;
8674 double p = met->ps[ix][iy];
8675 met->cape[ix][iy] = met->cin[ix][iy] = 0;
8676 do {
8677 dz = dz0 * TVIRT(t, h2o);
8678 p /= pfac;
8679 t = theta / pow(1000. / p, 0.286);
8680 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
8681 &t_env, ci, cw, 1);
8682 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
8683 &h2o_env, ci, cw, 0);
8684 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
8685 TVIRT(t_env, h2o_env) * dz;
8686 if (dcape < 0)
8687 met->cin[ix][iy] += fabsf((float) dcape);
8688 } while (p > met->plcl[ix][iy]);
8689
8690 /* Calculate level of free convection (LFC), equilibrium level (EL),
8691 and convective available potential energy (CAPE)... */
8692 dcape = 0;
8693 p = met->plcl[ix][iy];
8694 t = theta / pow(1000. / p, 0.286);
8695 ptop = 0.75 * clim_tropo(clim, met->time,
8696 ctl->met_coord_type ==
8697 0 ? met->lat[iy] : ctl->met_utm_ref_lat);
8698 do {
8699 dz = dz0 * TVIRT(t, h2o);
8700 p /= pfac;
8701 t -= lapse_rate(t, h2o) * dz;
8702 double psat = PSAT(t);
8703 h2o = psat / (p - (1. - EPS) * psat);
8704 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
8705 &t_env, ci, cw, 1);
8706 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
8707 &h2o_env, ci, cw, 0);
8708 double dcape_old = dcape;
8709 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
8710 TVIRT(t_env, h2o_env) * dz;
8711 if (dcape > 0) {
8712 met->cape[ix][iy] += (float) dcape;
8713 if (!isfinite(met->plfc[ix][iy]))
8714 met->plfc[ix][iy] = (float) p;
8715 } else if (dcape_old > 0)
8716 met->pel[ix][iy] = (float) p;
8717 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
8718 met->cin[ix][iy] += fabsf((float) dcape);
8719 } while (p > ptop);
8720
8721 /* Check results... */
8722 if (!isfinite(met->plfc[ix][iy]))
8723 met->cin[ix][iy] = NAN;
8724 }
8725}
8726
8727/*****************************************************************************/
8728
8730 met_t *met) {
8731
8732 /* Set timer... */
8733 SELECT_TIMER("READ_MET_CLOUD", "METPROC");
8734 LOG(2, "Calculate cloud data...");
8735
8736 /* Thresholds for cloud detection... */
8737 const double ccmin = 0.01, cwmin = 1e-6;
8738
8739 /* Loop over columns... */
8740#pragma omp parallel for default(shared) collapse(2)
8741 for (int ix = 0; ix < met->nx; ix++)
8742 for (int iy = 0; iy < met->ny; iy++) {
8743
8744 /* Init... */
8745 met->pct[ix][iy] = NAN;
8746 met->pcb[ix][iy] = NAN;
8747 met->cl[ix][iy] = 0;
8748
8749 /* Loop over pressure levels... */
8750 for (int ip = 0; ip < met->np - 1; ip++) {
8751
8752 /* Check pressure... */
8753 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
8754 continue;
8755
8756 /* Check ice water and liquid water content... */
8757 if (met->cc[ix][iy][ip] > ccmin
8758 && (met->lwc[ix][iy][ip] > cwmin
8759 || met->rwc[ix][iy][ip] > cwmin
8760 || met->iwc[ix][iy][ip] > cwmin
8761 || met->swc[ix][iy][ip] > cwmin)) {
8762
8763 /* Get cloud top pressure ... */
8764 met->pct[ix][iy]
8765 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
8766
8767 /* Get cloud bottom pressure ... */
8768 if (!isfinite(met->pcb[ix][iy]))
8769 met->pcb[ix][iy]
8770 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
8771 }
8772
8773 /* Get cloud water... */
8774 met->cl[ix][iy] += (float)
8775 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
8776 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
8777 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
8778 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
8779 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
8780 }
8781 }
8782}
8783
8784/*****************************************************************************/
8785
8787 const ctl_t *ctl,
8788 met_t *met) {
8789
8790 met_t *help;
8791
8792 /* Check parameters... */
8793 if (ctl->met_detrend <= 0)
8794 return;
8795
8796 if (ctl->met_coord_type != 0)
8797 ERRMSG("Only lat/lon grid supported");
8798
8799 /* Set timer... */
8800 SELECT_TIMER("READ_MET_DETREND", "METPROC");
8801 LOG(2, "Detrend meteo data...");
8802
8803 /* Allocate... */
8804 ALLOC(help, met_t, 1);
8805
8806 /* Calculate standard deviation... */
8807 const double sigma = ctl->met_detrend / 2.355;
8808 const double tssq = 2. * SQR(sigma);
8809
8810 /* Calculate box size in latitude... */
8811 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
8812 sy = MIN(MAX(1, sy), met->ny / 2);
8813
8814 /* Calculate background... */
8815#pragma omp parallel for default(shared) collapse(2)
8816 for (int ix = 0; ix < met->nx; ix++) {
8817 for (int iy = 0; iy < met->ny; iy++) {
8818
8819 /* Calculate Cartesian coordinates... */
8820 double x0[3];
8821 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
8822
8823 /* Calculate box size in longitude... */
8824 int sx =
8825 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
8826 fabs(met->lon[1] - met->lon[0]));
8827 sx = MIN(MAX(1, sx), met->nx / 2);
8828
8829 /* Init... */
8830 float wsum = 0;
8831 for (int ip = 0; ip < met->np; ip++) {
8832 help->t[ix][iy][ip] = 0;
8833 help->u[ix][iy][ip] = 0;
8834 help->v[ix][iy][ip] = 0;
8835 help->w[ix][iy][ip] = 0;
8836 }
8837
8838 /* Loop over neighboring grid points... */
8839 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
8840 int ix3 = ix2;
8841 if (ix3 < 0)
8842 ix3 += met->nx;
8843 else if (ix3 >= met->nx)
8844 ix3 -= met->nx;
8845 for (int iy2 = MAX(iy - sy, 0);
8846 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
8847
8848 /* Calculate Cartesian coordinates... */
8849 double x1[3];
8850 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
8851
8852 /* Calculate weighting factor... */
8853 const float w = (float) exp(-DIST2(x0, x1) / tssq);
8854
8855 /* Add data... */
8856 wsum += w;
8857 for (int ip = 0; ip < met->np; ip++) {
8858 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
8859 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
8860 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
8861 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
8862 }
8863 }
8864 }
8865
8866 /* Normalize... */
8867 for (int ip = 0; ip < met->np; ip++) {
8868 help->t[ix][iy][ip] /= wsum;
8869 help->u[ix][iy][ip] /= wsum;
8870 help->v[ix][iy][ip] /= wsum;
8871 help->w[ix][iy][ip] /= wsum;
8872 }
8873 }
8874 }
8875
8876 /* Subtract background... */
8877#pragma omp parallel for default(shared) collapse(3)
8878 for (int ix = 0; ix < met->nx; ix++)
8879 for (int iy = 0; iy < met->ny; iy++)
8880 for (int ip = 0; ip < met->np; ip++) {
8881 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
8882 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
8883 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
8884 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
8885 }
8886
8887 /* Free... */
8888 free(help);
8889}
8890
8891/*****************************************************************************/
8892
8894 met_t *met) {
8895
8896 /* Set timer... */
8897 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC");
8898 LOG(2, "Extrapolate meteo data...");
8899
8900 /* Loop over columns... */
8901#pragma omp parallel for default(shared) collapse(2)
8902 for (int ix = 0; ix < met->nx; ix++)
8903 for (int iy = 0; iy < met->ny; iy++) {
8904
8905 /* Find lowest valid data point... */
8906 int ip0;
8907 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
8908 if (!isfinite(met->t[ix][iy][ip0])
8909 || !isfinite(met->u[ix][iy][ip0])
8910 || !isfinite(met->v[ix][iy][ip0])
8911 || !isfinite(met->w[ix][iy][ip0]))
8912 break;
8913
8914 /* Extrapolate... */
8915 for (int ip = ip0; ip >= 0; ip--) {
8916 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
8917 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
8918 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
8919 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
8920 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
8921 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
8922 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
8923 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
8924 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
8925 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
8926 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
8927 }
8928 }
8929}
8930
8931/*****************************************************************************/
8932
8934 const ctl_t *ctl,
8935 met_t *met) {
8936
8937 float *help;
8938
8939 double logp[EP];
8940
8941 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
8942
8943 /* Set timer... */
8944 SELECT_TIMER("READ_MET_GEOPOT", "METPROC");
8945 LOG(2, "Calculate geopotential heights...");
8946
8947 /* Allocate... */
8948 ALLOC(help, float,
8949 EX * EY * EP);
8950
8951 /* Calculate log pressure... */
8952#pragma omp parallel for default(shared)
8953 for (int ip = 0; ip < met->np; ip++)
8954 logp[ip] = log(met->p[ip]);
8955
8956 /* Apply hydrostatic equation to calculate geopotential heights... */
8957#pragma omp parallel for default(shared) collapse(2)
8958 for (int ix = 0; ix < met->nx; ix++)
8959 for (int iy = 0; iy < met->ny; iy++) {
8960
8961 /* Get surface height and pressure... */
8962 const double zs = met->zs[ix][iy];
8963 const double lnps = log(met->ps[ix][iy]);
8964
8965 /* Get temperature and water vapor at the surface... */
8966 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
8967 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
8968 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
8969 const double h2os =
8970 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
8971 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
8972
8973 /* Upper part of profile... */
8974 met->z[ix][iy][ip0 + 1]
8975 = (float) (zs +
8976 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
8977 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
8978 for (int ip = ip0 + 2; ip < met->np; ip++)
8979 met->z[ix][iy][ip]
8980 = (float) (met->z[ix][iy][ip - 1] +
8981 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
8982 met->h2o[ix][iy][ip - 1], logp[ip],
8983 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8984
8985 /* Lower part of profile... */
8986 met->z[ix][iy][ip0]
8987 = (float) (zs +
8988 ZDIFF(lnps, ts, h2os, logp[ip0],
8989 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
8990 for (int ip = ip0 - 1; ip >= 0; ip--)
8991 met->z[ix][iy][ip]
8992 = (float) (met->z[ix][iy][ip + 1] +
8993 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
8994 met->h2o[ix][iy][ip + 1], logp[ip],
8995 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8996 }
8997
8998 /* Check control parameters... */
8999 if (dx == 0 || dy == 0)
9000 return;
9001
9002 /* Default smoothing parameters... */
9003 if (dx < 0 || dy < 0) {
9004 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
9005 dx = 3;
9006 dy = 2;
9007 } else {
9008 dx = 6;
9009 dy = 4;
9010 }
9011 }
9012
9013 /* Calculate weights for smoothing... */
9014 float ws[dx + 1][dy + 1];
9015#pragma omp parallel for default(shared) collapse(2)
9016 for (int ix = 0; ix <= dx; ix++)
9017 for (int iy = 0; iy < dy; iy++)
9018 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
9019 * (1.0f - (float) iy / (float) dy);
9020
9021 /* Copy data... */
9022#pragma omp parallel for default(shared) collapse(3)
9023 for (int ix = 0; ix < met->nx; ix++)
9024 for (int iy = 0; iy < met->ny; iy++)
9025 for (int ip = 0; ip < met->np; ip++)
9026 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
9027
9028 /* Horizontal smoothing... */
9029#pragma omp parallel for default(shared) collapse(3)
9030 for (int ip = 0; ip < met->np; ip++)
9031 for (int ix = 0; ix < met->nx; ix++)
9032 for (int iy = 0; iy < met->ny; iy++) {
9033 float res = 0, wsum = 0;
9034 int iy0 = MAX(iy - dy + 1, 0);
9035 int iy1 = MIN(iy + dy - 1, met->ny - 1);
9036 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
9037 int ix3 = ix2;
9038 if (ix3 < 0)
9039 ix3 += met->nx;
9040 else if (ix3 >= met->nx)
9041 ix3 -= met->nx;
9042 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
9043 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
9044 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
9045 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
9046 wsum += w;
9047 }
9048 }
9049 if (wsum > 0)
9050 met->z[ix][iy][ip] = res / wsum;
9051 else
9052 met->z[ix][iy][ip] = NAN;
9053 }
9054
9055 /* Free... */
9056 free(help);
9057}
9058
9059/*****************************************************************************/
9060
9062 const char *filename,
9063 const int ncid,
9064 const ctl_t *ctl,
9065 met_t *met,
9066 dd_t *dd) {
9067
9068 char levname[LEN], tstr[10];
9069
9070 double rtime = 0, r, r2;
9071
9072 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
9073 year, mon, day, hour, min, sec;
9074
9075 size_t dimlen;
9076
9077 /* Set timer... */
9078 SELECT_TIMER("READ_MET_NC_GRID", "INPUT");
9079 LOG(2, "Read meteo grid information...");
9080
9081 /* MPTRAC meteo files... */
9082 if (!ctl->met_clams) {
9083
9084 /* Get time from filename... */
9085 met->time = time_from_filename(filename, 16, 0);
9086
9087 /* Check time information from data file... */
9088 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
9089 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
9090 NC(nc_get_var_double(ncid, varid, &rtime));
9091 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
9092 WARN("Time information in meteo file does not match filename!");
9093 } else
9094 WARN("Time information in meteo file is missing!");
9095 }
9096
9097 /* CLaMS meteo files... */
9098 else {
9099
9100 /* Read time from file... */
9101 NC_GET_DOUBLE("time", &rtime, 0);
9102
9103 /* Get time from filename (considering the century)... */
9104 if (rtime < 0)
9105 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
9106 else
9107 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
9108 year = atoi(tstr);
9109 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
9110 mon = atoi(tstr);
9111 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
9112 day = atoi(tstr);
9113 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
9114 hour = atoi(tstr);
9115 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
9116 }
9117
9118 /* Check time... */
9119 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
9120 || day < 1 || day > 31 || hour < 0 || hour > 23)
9121 ERRMSG("Cannot read time from filename!");
9122 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
9123 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
9124 met->time, year2, mon2, day2, hour2, min2);
9125
9126 /* Get vertical dimension... */
9127 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
9128 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
9129 ERRMSG
9130 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
9131
9132 NC(nc_inq_varndims(ncid, varid, &ndims));
9133 NC(nc_inq_vardimid(ncid, varid, dimids));
9134
9135 if (ndims == 4) {
9136 NC(nc_inq_dim
9137 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
9138 } else if (ndims == 3) {
9139 NC(nc_inq_dim
9140 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
9141 } else
9142 ERRMSG("Cannot determine vertical dimension!")
9143 met->np = (int) dimlen;
9144
9145 LOG(2, "Number of levels: %d", met->np);
9146 if (met->np < 2 || met->np > EP)
9147 ERRMSG("Number of levels out of range!");
9148
9149 if (!ctl->dd) {
9150
9151 /* Get grid dimensions and coordinates... */
9152 if (met->coord_type == 0) {
9153 /* Longitude/latitude grid... */
9154 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
9155 LOG(2, "Number of longitudes: %d", met->nx);
9156
9157 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
9158 LOG(2, "Number of latitudes: %d", met->ny);
9159
9160 NC_GET_DOUBLE("lon", met->lon, 1);
9161 LOG(2, "Longitudes: %g, %g ... %g deg",
9162 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9163 NC_GET_DOUBLE("lat", met->lat, 1);
9164 LOG(2, "Latitudes: %g, %g ... %g deg",
9165 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9166
9167 } else {
9168 /* UTM grid... */
9169 NC_INQ_DIM("x", &met->nx, 2, EX, 1);
9170 LOG(2, "Number of x coordinates: %d", met->nx);
9171
9172 NC_INQ_DIM("y", &met->ny, 2, EY, 1);
9173 LOG(2, "Number of y coordinates: %d", met->ny);
9174
9175 NC_GET_DOUBLE("x", met->lon, 1);
9176 LOG(2, "X coordinates: %g, %g ... %g m",
9177 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9178 NC_GET_DOUBLE("y", met->lat, 1);
9179 LOG(2, "Y coordinates: %g, %g ... %g m",
9180 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9181 }
9182
9183 } else {
9184
9185 if (met->coord_type != 0)
9186 ERRMSG("Domain decomposition is only supported for lat/lon grids!");
9187
9188 /* Use 'naive', i.e. equidistant lat-lon domain decomposition... */
9189 read_met_nc_grid_dd_naive(dd, ctl, met, ncid);
9190
9191 }
9192
9193 /* Read pressure levels... */
9194 if (ctl->met_np <= 0) {
9195 NC_GET_DOUBLE(levname, met->p, 1);
9196 for (int ip = 0; ip < met->np; ip++)
9197 met->p[ip] /= 100.;
9198 LOG(2, "Altitude levels: %g, %g ... %g km",
9199 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
9200 LOG(2, "Pressure levels: %g, %g ... %g hPa",
9201 met->p[0], met->p[1], met->p[met->np - 1]);
9202 }
9203
9204 /* Read hybrid levels... */
9205 if (strcasecmp(levname, "hybrid") == 0)
9206 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
9207
9208 /* Read model level coefficients from file... */
9209 if (ctl->met_vert_coord == 2) {
9210 NC_GET_DOUBLE("hyam", met->hyam, 1);
9211 NC_GET_DOUBLE("hybm", met->hybm, 1);
9212 }
9213
9214 /* Copy model level coefficients from control parameters... */
9215 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
9216 if (ctl->met_nlev <= 0)
9217 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
9218 for (int ip = 0; ip < ctl->met_nlev; ip++) {
9219 met->hyam[ip] = ctl->met_lev_hyam[ip];
9220 met->hybm[ip] = ctl->met_lev_hybm[ip];
9221 }
9222 }
9223
9224 /* Calculate eta levels... */
9225 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
9226 met->eta[k] = met->hyam[k] / 100000.0 + met->hybm[k];
9227 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
9228 ERRMSG("Eta levels must be ascending!");
9229 }
9230
9231 /* Check horizontal grid spacing... */
9232 for (int ix = 2; ix < met->nx; ix++)
9233 if (fabs
9234 (fabs(met->lon[ix] - met->lon[ix - 1]) -
9235 fabs(met->lon[1] - met->lon[0])) > 0.001)
9236 ERRMSG("No regular grid spacing in longitudes!");
9237 for (int iy = 2; iy < met->ny; iy++)
9238 if (fabs
9239 (fabs(met->lat[iy] - met->lat[iy - 1]) -
9240 fabs(met->lat[1] - met->lat[0])) > 0.001) {
9241 WARN("No regular grid spacing in latitudes!");
9242 break;
9243 }
9244}
9245
9246/*****************************************************************************/
9247
9249 const int ncid,
9250 const ctl_t *ctl,
9251 met_t *met,
9252 dd_t *dd) {
9253
9254 /* Set timer... */
9255 SELECT_TIMER("READ_MET_SURFACE", "INPUT");
9256 LOG(2, "Read surface data...");
9257
9258 /* Read surface pressure... */
9259 if (read_met_nc_2d
9260 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
9261 1.0f, 1)) {
9262 for (int ix = 0; ix < met->nx; ix++)
9263 for (int iy = 0; iy < met->ny; iy++)
9264 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
9265 } else
9266 if (!read_met_nc_2d
9267 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
9268 0.01f, 1)) {
9269 WARN("Cannot not read surface pressure data (use lowest level)!");
9270 for (int ix = 0; ix < met->nx; ix++)
9271 for (int iy = 0; iy < met->ny; iy++)
9272 met->ps[ix][iy]
9273 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
9274 }
9275
9276 /* MPTRAC meteo data... */
9277 if (ctl->met_clams == 0) {
9278
9279 /* Read geopotential height at the surface... */
9280 if (!read_met_nc_2d
9281 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
9282 (float) (1. / (1000. * G0)), 1))
9283 if (!read_met_nc_2d
9284 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
9285 (float) (1. / 1000.), 1))
9286 WARN("Cannot read surface geopotential height!");
9287 }
9288
9289 /* CLaMS meteo data... */
9290 else {
9291
9292 /* Read geopotential height at the surface
9293 (use lowermost level of 3-D data field)... */
9294 float *help;
9295 ALLOC(help, float,
9296 EX * EY * EP);
9297 memcpy(help, met->pl, sizeof(met->pl));
9298 if (!read_met_nc_3d
9299 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
9300 (float) (1e-3 / G0)))
9301 ERRMSG("Cannot read geopotential height!");
9302 for (int ix = 0; ix < met->nx; ix++)
9303 for (int iy = 0; iy < met->ny; iy++)
9304 met->zs[ix][iy] = met->pl[ix][iy][0];
9305 memcpy(met->pl, help, sizeof(met->pl));
9306 free(help);
9307 }
9308
9309 /* Read temperature at the surface... */
9310 if (!read_met_nc_2d
9311 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
9312 1))
9313 WARN("Cannot read surface temperature!");
9314
9315 /* Read zonal wind at the surface... */
9316 if (!read_met_nc_2d
9317 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
9318 met->us, 1.0, 1))
9319 WARN("Cannot read surface zonal wind!");
9320
9321 /* Read meridional wind at the surface... */
9322 if (!read_met_nc_2d
9323 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
9324 met->vs, 1.0, 1))
9325 WARN("Cannot read surface meridional wind!");
9326
9327 /* Read eastward turbulent surface stress... */
9328 if (!read_met_nc_2d
9329 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
9330 1.0, 1))
9331 WARN("Cannot read eastward turbulent surface stress!");
9332
9333 /* Read northward turbulent surface stress... */
9334 if (!read_met_nc_2d
9335 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
9336 1.0, 1))
9337 WARN("Cannot read nothward turbulent surface stress!");
9338
9339 /* Read surface sensible heat flux... */
9340 if (!read_met_nc_2d
9341 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
9342 1.0, 1))
9343 WARN("Cannot read surface sensible heat flux!");
9344
9345 /* Read land-sea mask... */
9346 if (!read_met_nc_2d
9347 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
9348 1.0, 1))
9349 WARN("Cannot read land-sea mask!");
9350
9351 /* Read sea surface temperature... */
9352 if (!read_met_nc_2d
9353 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
9354 1.0, 1))
9355 WARN("Cannot read sea surface temperature!");
9356
9357 /* Read PBL... */
9358 if (ctl->met_pbl == 0)
9359 if (!read_met_nc_2d
9360 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
9361 0.01f, 1))
9362 WARN("Cannot read planetary boundary layer pressure!");
9363 if (ctl->met_pbl == 1)
9364 if (!read_met_nc_2d
9365 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
9366 0.001f, 1))
9367 WARN("Cannot read planetary boundary layer height!");
9368
9369 /* Read CAPE... */
9370 if (ctl->met_cape == 0)
9371 if (!read_met_nc_2d
9372 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
9373 met->cape, 1.0, 1))
9374 WARN("Cannot read CAPE!");
9375
9376 /* Read CIN... */
9377 if (ctl->met_cape == 0)
9378 if (!read_met_nc_2d
9379 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
9380 1.0, 1))
9381 WARN("Cannot read convective inhibition!");
9382}
9383
9384/*****************************************************************************/
9385
9387 const int ncid,
9388 const ctl_t *ctl,
9389 met_t *met,
9390 dd_t *dd) {
9391
9392 /* Set timer... */
9393 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT");
9394 LOG(2, "Read level data...");
9395
9396 /* Read temperature... */
9397 if (!read_met_nc_3d
9398 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
9399 ERRMSG("Cannot read temperature!");
9400
9401 /* Read horizontal wind and vertical velocity... */
9402 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
9403 ERRMSG("Cannot read zonal wind!");
9404 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
9405 ERRMSG("Cannot read meridional wind!");
9406 if (!read_met_nc_3d
9407 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
9408 WARN("Cannot read vertical velocity!");
9409
9410 /* Read water vapor... */
9411 if (!ctl->met_relhum) {
9412 if (!read_met_nc_3d
9413 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
9414 (float) (MA / MH2O)))
9415 WARN("Cannot read specific humidity!");
9416 } else {
9417 if (!read_met_nc_3d
9418 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
9419 WARN("Cannot read relative humidity!");
9420#pragma omp parallel for default(shared) collapse(2)
9421 for (int ix = 0; ix < met->nx; ix++)
9422 for (int iy = 0; iy < met->ny; iy++)
9423 for (int ip = 0; ip < met->np; ip++) {
9424 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
9425 met->h2o[ix][iy][ip] =
9426 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
9427 }
9428 }
9429
9430 /* Read ozone... */
9431 if (!read_met_nc_3d
9432 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
9433 (float) (MA / MO3)))
9434 WARN("Cannot read ozone data!");
9435
9436 /* Read cloud data... */
9437 if (!read_met_nc_3d
9438 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
9439 WARN("Cannot read cloud liquid water content!");
9440 if (!read_met_nc_3d
9441 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
9442 WARN("Cannot read cloud rain water content!");
9443 if (!read_met_nc_3d
9444 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
9445 WARN("Cannot read cloud ice water content!");
9446 if (!read_met_nc_3d
9447 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
9448 WARN("Cannot read cloud snow water content!");
9449 if (!read_met_nc_3d
9450 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
9451 WARN("Cannot read cloud cover!");
9452
9453 /* Read zeta and zeta_dot... */
9454 if (ctl->advect_vert_coord == 1) {
9455 if (!read_met_nc_3d
9456 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
9457 WARN("Cannot read ZETA!");
9458 if (!read_met_nc_3d
9459 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
9460 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
9461 WARN("Cannot read ZETA_DOT!");
9462 }
9463
9464 /* Read eta and eta_dot... */
9465 else if (ctl->advect_vert_coord == 3) {
9466#pragma omp parallel for default(shared)
9467 for (int ix = 0; ix < met->nx; ix++)
9468 for (int iy = 0; iy < met->ny; iy++)
9469 for (int ip = 0; ip < met->np; ip++)
9470 met->zetal[ix][iy][ip] =
9471 (float) (met->hyam[ip] / 100000.0 + met->hybm[ip]);
9472 if (!read_met_nc_3d
9473 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
9474 1.0))
9475 WARN("Cannot read eta vertical velocity!");
9476 }
9477
9478 /* Store velocities on model levels... */
9479 if (ctl->met_vert_coord != 0) {
9480#pragma omp parallel for default(shared)
9481 for (int ix = 0; ix < met->nx; ix++)
9482 for (int iy = 0; iy < met->ny; iy++)
9483 for (int ip = 0; ip < met->np; ip++) {
9484 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
9485 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
9486 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
9487 }
9488
9489 /* Save number of model levels... */
9490 met->npl = met->np;
9491 }
9492
9493 /* Get pressure on model levels... */
9494 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
9495
9496 /* Read 3-D pressure field... */
9497 if (ctl->met_vert_coord == 1) {
9498 if (!read_met_nc_3d
9499 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
9500 0.01f))
9501 if (!read_met_nc_3d
9502 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
9503 ERRMSG("Cannot read pressure on model levels!");
9504 }
9505
9506 /* Use a and b coefficients for full levels (at layer midpoints)... */
9507 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
9508
9509 /* Check number of levels... */
9510 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
9511 ERRMSG("Mismatch in number of model levels!");
9512
9513 /* Calculate pressure... */
9514 for (int ix = 0; ix < met->nx; ix++)
9515 for (int iy = 0; iy < met->ny; iy++)
9516 for (int ip = 0; ip < met->np; ip++)
9517 met->pl[ix][iy][ip] =
9518 (float) (met->hyam[ip] / 100. +
9519 met->hybm[ip] * met->ps[ix][iy]);
9520 }
9521
9522 /* Use a and b coefficients for half levels (at layer interfaces)... */
9523 else if (ctl->met_vert_coord == 4) {
9524
9525 /* Check number of levels... */
9526 if (met->np + 1 != ctl->met_nlev)
9527 ERRMSG("Mismatch in number of model levels!");
9528
9529 /* Calculate pressure... */
9530#pragma omp parallel for default(shared) collapse(2)
9531 for (int ix = 0; ix < met->nx; ix++)
9532 for (int iy = 0; iy < met->ny; iy++)
9533 for (int ip = 0; ip < met->np; ip++) {
9534 const double p0 =
9535 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
9536 const double p1 =
9537 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
9538 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
9539 }
9540 }
9541
9542 /* Check ordering of pressure levels... */
9543 for (int ix = 0; ix < met->nx; ix++)
9544 for (int iy = 0; iy < met->ny; iy++)
9545 for (int ip = 1; ip < met->np; ip++)
9546 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
9547 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
9548 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
9549 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
9550 ERRMSG("Pressure profiles are not monotonic!");
9551 }
9552
9553 /* Interpolate from model levels to pressure levels... */
9554 if (ctl->met_np > 0) {
9555
9556 /* Interpolate variables... */
9557 read_met_ml2pl(ctl, met, met->t, "T");
9558 read_met_ml2pl(ctl, met, met->u, "U");
9559 read_met_ml2pl(ctl, met, met->v, "V");
9560 read_met_ml2pl(ctl, met, met->w, "W");
9561 read_met_ml2pl(ctl, met, met->h2o, "H2O");
9562 read_met_ml2pl(ctl, met, met->o3, "O3");
9563 read_met_ml2pl(ctl, met, met->lwc, "LWC");
9564 read_met_ml2pl(ctl, met, met->rwc, "RWC");
9565 read_met_ml2pl(ctl, met, met->iwc, "IWC");
9566 read_met_ml2pl(ctl, met, met->swc, "SWC");
9567 read_met_ml2pl(ctl, met, met->cc, "CC");
9568
9569 /* Set new pressure levels... */
9570 met->np = ctl->met_np;
9571 for (int ip = 0; ip < met->np; ip++)
9572 met->p[ip] = ctl->met_p[ip];
9573 }
9574
9575 /* Check ordering of pressure levels... */
9576 for (int ip = 1; ip < met->np; ip++)
9577 if (met->p[ip - 1] < met->p[ip])
9578 ERRMSG("Pressure levels must be descending!");
9579}
9580
9581/*****************************************************************************/
9582
9584 const int ncid,
9585 const char *varname,
9586 const char *varname2,
9587 const char *varname3,
9588 const char *varname4,
9589 const char *varname5,
9590 const char *varname6,
9591 const ctl_t *ctl,
9592 const met_t *met,
9593 dd_t *dd,
9594 float dest[EX][EY],
9595 const float scl,
9596 const int init) {
9597
9598 char varsel[LEN];
9599
9600 float offset, scalfac;
9601
9602 int varid;
9603
9604 /* Check if variable exists... */
9605 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
9606 sprintf(varsel, "%s", varname);
9607 else if (varname2 != NULL
9608 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
9609 sprintf(varsel, "%s", varname2);
9610 else if (varname3 != NULL
9611 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
9612 sprintf(varsel, "%s", varname3);
9613 else if (varname4 != NULL
9614 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
9615 sprintf(varsel, "%s", varname4);
9616 else if (varname5 != NULL
9617 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
9618 sprintf(varsel, "%s", varname5);
9619 else if (varname6 != NULL
9620 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
9621 sprintf(varsel, "%s", varname6);
9622 else
9623 return 0;
9624
9625 /* Read packed data... */
9626 if (ctl->met_nc_scale && !ctl->dd
9627 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
9628 && nc_get_att_float(ncid, varid, "scale_factor",
9629 &scalfac) == NC_NOERR) {
9630
9631 /* Allocate... */
9632 short *help;
9633 ALLOC(help, short,
9634 EX * EY * EP);
9635
9636 /* Read fill value and missing value... */
9637 short fillval, missval;
9638 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9639 fillval = 0;
9640 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9641 missval = 0;
9642
9643 /* Write info... */
9644 LOG(2, "Read 2-D variable: %s"
9645 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9646 varsel, fillval, missval, scalfac, offset);
9647
9648 /* Read data... */
9649 NC(nc_get_var_short(ncid, varid, help));
9650
9651 /* Check meteo data layout... */
9652 if (ctl->met_convention != 0)
9653 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9654
9655 /* Copy and check data... */
9656 omp_set_dynamic(1);
9657#pragma omp parallel for default(shared)
9658 for (int ix = 0; ix < met->nx; ix++)
9659 for (int iy = 0; iy < met->ny; iy++) {
9660 if (init)
9661 dest[ix][iy] = 0;
9662 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
9663 if ((fillval == 0 || aux != fillval)
9664 && (missval == 0 || aux != missval)
9665 && fabsf(aux * scalfac + offset) < 1e14f)
9666 dest[ix][iy] += scl * (aux * scalfac + offset);
9667 else
9668 dest[ix][iy] = NAN;
9669 }
9670 omp_set_dynamic(0);
9671
9672 /* Free... */
9673 free(help);
9674 }
9675
9676 /* Unpacked data... */
9677 else if (!ctl->dd) {
9678
9679 /* Allocate... */
9680 float *help;
9681 ALLOC(help, float,
9682 EX * EY);
9683
9684 /* Read fill value and missing value... */
9685 float fillval, missval;
9686 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9687 fillval = 0;
9688 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9689 missval = 0;
9690
9691 /* Write info... */
9692 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
9693 varsel, fillval, missval);
9694
9695 /* Read data... */
9696 NC(nc_get_var_float(ncid, varid, help));
9697
9698 /* Check meteo data layout... */
9699 if (ctl->met_convention == 0) {
9700
9701 /* Copy and check data (ordering: lat, lon)... */
9702 omp_set_dynamic(1);
9703#pragma omp parallel for default(shared)
9704 for (int ix = 0; ix < met->nx; ix++)
9705 for (int iy = 0; iy < met->ny; iy++) {
9706 if (init)
9707 dest[ix][iy] = 0;
9708 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
9709 if ((fillval == 0 || aux != fillval)
9710 && (missval == 0 || aux != missval)
9711 && fabsf(aux) < 1e14f)
9712 dest[ix][iy] += scl * aux;
9713 else
9714 dest[ix][iy] = NAN;
9715 }
9716 omp_set_dynamic(0);
9717
9718 } else {
9719
9720 /* Copy and check data (ordering: lon, lat)... */
9721 omp_set_dynamic(1);
9722#pragma omp parallel for default(shared)
9723 for (int iy = 0; iy < met->ny; iy++)
9724 for (int ix = 0; ix < met->nx; ix++) {
9725 if (init)
9726 dest[ix][iy] = 0;
9727 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
9728 if ((fillval == 0 || aux != fillval)
9729 && (missval == 0 || aux != missval)
9730 && fabsf(aux) < 1e14f)
9731 dest[ix][iy] += scl * aux;
9732 else
9733 dest[ix][iy] = NAN;
9734 }
9735 omp_set_dynamic(0);
9736 }
9737
9738 /* Free... */
9739 free(help);
9740 }
9741
9742 /* Domain decomposed data... */
9743 else {
9744
9745 /* Read fill value and missing value... */
9746 float fillval, missval;
9747 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9748 fillval = 0;
9749 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9750 missval = 0;
9751
9752 /* Write info... */
9753 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
9754 varsel, fillval, missval);
9755
9756 /* Define hyperslab... */
9757 float *help;
9758 size_t help_subdomain_start[3];
9759 size_t help_subdomain_count[3];
9760
9761 help_subdomain_start[0] = 0;
9762 if (ctl->met_convention == 0) {
9763 help_subdomain_start[1] = dd->subdomain_start[2];
9764 help_subdomain_start[2] = dd->subdomain_start[3];
9765 } else {
9766 help_subdomain_start[1] = dd->subdomain_start[3];
9767 help_subdomain_start[2] = dd->subdomain_start[2];
9768 }
9769
9770 help_subdomain_count[0] = 1;
9771 if (ctl->met_convention == 0) {
9772 help_subdomain_count[1] = dd->subdomain_count[2]; //y
9773 help_subdomain_count[2] = dd->subdomain_count[3]; //x
9774 } else {
9775 help_subdomain_count[1] = dd->subdomain_count[3]; //x
9776 help_subdomain_count[2] = dd->subdomain_count[2]; //y
9777 }
9778
9779 ALLOC(help, float,
9780 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
9781
9782 /* Read data... */
9783#ifdef DD
9784 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
9785#endif
9786 NC(nc_get_vara_float
9787 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
9788
9789 /* Read halos at boundaries... */
9790 size_t help_halo_bnd_start[3];
9791 size_t help_halo_bnd_count[3];
9792
9793 help_halo_bnd_start[0] = 0;
9794 if (ctl->met_convention == 0) {
9795 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
9796 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
9797 } else {
9798 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
9799 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
9800 }
9801
9802 help_halo_bnd_count[0] = 1;
9803 if (ctl->met_convention == 0) {
9804 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
9805 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
9806 } else {
9807 help_halo_bnd_count[1] = dd->halo_bnd_count[3]; //x
9808 help_halo_bnd_count[2] = dd->halo_bnd_count[2]; //y
9809 }
9810
9811 float *help_halo;
9812 ALLOC(help_halo, float,
9813 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
9814
9815#ifdef DD
9816 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
9817#endif
9818 NC(nc_get_vara_float
9819 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
9820
9821 /* Check meteo data layout... */
9822 if (ctl->met_convention == 0) {
9823
9824 /* Copy and check data (ordering: lat, lon)... */
9825 omp_set_dynamic(1);
9826#pragma omp parallel for default(shared)
9827 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
9828 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
9829 if (init == 1)
9830 dest[ix + dd->halo_offset_start][iy] = 0;
9831 const float aux =
9832 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
9833 if ((fillval == 0 || aux != fillval)
9834 && (missval == 0 || aux != missval)
9835 && fabsf(aux) < 1e14f) {
9836 dest[ix + dd->halo_offset_start][iy] += scl * aux;
9837 } else
9838 dest[ix + dd->halo_offset_start][iy] = NAN;
9839 }
9840
9841#pragma omp parallel for default(shared)
9842 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
9843 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
9844 if (init == 1)
9845 dest[ix + dd->halo_offset_end][iy] = 0;
9846 const float aux =
9847 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
9848 if ((fillval == 0 || aux != fillval)
9849 && (missval == 0 || aux != missval)
9850 && fabsf(aux) < 1e14f)
9851 dest[ix + dd->halo_offset_end][iy] += scl * aux;
9852 else {
9853 dest[ix + dd->halo_offset_end][iy] = NAN;
9854 }
9855 }
9856 omp_set_dynamic(0);
9857
9858 } else {
9859
9860 /* Copy and check data (ordering: lon, lat)... */
9861 omp_set_dynamic(1);
9862#pragma omp parallel for default(shared)
9863 for (int ix = 0; ix < (int) help_subdomain_count[1]; ix++)
9864 for (int iy = 0; iy < (int) help_subdomain_count[2]; iy++) {
9865 if (init == 1)
9866 dest[ix + dd->halo_offset_start][iy] = 0;
9867 const float aux =
9868 help[ARRAY_2D(ix, iy, (int) help_subdomain_count[1])];
9869 if ((fillval == 0 || aux != fillval)
9870 && (missval == 0 || aux != missval)
9871 && fabsf(aux) < 1e14f)
9872 dest[ix + dd->halo_offset_start][iy] += scl * aux;
9873 else
9874 dest[ix + dd->halo_offset_start][iy] = NAN;
9875 }
9876
9877#pragma omp parallel for default(shared)
9878 for (int ix = 0; ix < (int) help_halo_bnd_count[1]; ix++)
9879 for (int iy = 0; iy < (int) help_halo_bnd_count[2]; iy++) {
9880 if (init == 1)
9881 dest[ix + dd->halo_offset_end][iy] = 0;
9882 const float aux =
9883 help_halo[ARRAY_2D(ix, iy, (int) help_halo_bnd_count[1])];
9884 if ((fillval == 0 || aux != fillval)
9885 && (missval == 0 || aux != missval)
9886 && fabsf(aux) < 1e14f)
9887 dest[ix + dd->halo_offset_end][iy] += scl * aux;
9888 else
9889 dest[ix + dd->halo_offset_end][iy] = NAN;
9890 }
9891 omp_set_dynamic(0);
9892 }
9893
9894 /* Free... */
9895 free(help);
9896 free(help_halo);
9897 }
9898
9899 /* Return... */
9900 return 1;
9901}
9902
9903/*****************************************************************************/
9904
9906 const int ncid,
9907 const char *varname,
9908 const char *varname2,
9909 const char *varname3,
9910 const char *varname4,
9911 const ctl_t *ctl,
9912 const met_t *met,
9913 dd_t *dd,
9914 float dest[EX][EY][EP],
9915 const float scl) {
9916
9917 char varsel[LEN];
9918
9919 float offset, scalfac;
9920
9921 int varid;
9922
9923 /* Check if variable exists... */
9924 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
9925 sprintf(varsel, "%s", varname);
9926 else if (varname2 != NULL
9927 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
9928 sprintf(varsel, "%s", varname2);
9929 else if (varname3 != NULL
9930 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
9931 sprintf(varsel, "%s", varname3);
9932 else if (varname4 != NULL
9933 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
9934 sprintf(varsel, "%s", varname4);
9935 else
9936 return 0;
9937
9938 /* Read packed data... */
9939 if (ctl->met_nc_scale && !ctl->dd
9940 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
9941 && nc_get_att_float(ncid, varid, "scale_factor",
9942 &scalfac) == NC_NOERR) {
9943
9944 /* Allocate... */
9945 short *help;
9946 ALLOC(help, short,
9947 EX * EY * EP);
9948
9949 /* Read fill value and missing value... */
9950 short fillval, missval;
9951 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9952 fillval = 0;
9953 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9954 missval = 0;
9955
9956 /* Write info... */
9957 LOG(2, "Read 3-D variable: %s "
9958 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9959 varsel, fillval, missval, scalfac, offset);
9960
9961 /* Read data... */
9962 NC(nc_get_var_short(ncid, varid, help));
9963
9964 /* Check meteo data layout... */
9965 if (ctl->met_convention != 0)
9966 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9967
9968 /* Copy and check data... */
9969 omp_set_dynamic(1);
9970#pragma omp parallel for default(shared)
9971 for (int ix = 0; ix < met->nx; ix++)
9972 for (int iy = 0; iy < met->ny; iy++)
9973 for (int ip = 0; ip < met->np; ip++) {
9974 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9975 if ((fillval == 0 || aux != fillval)
9976 && (missval == 0 || aux != missval)
9977 && fabsf(aux * scalfac + offset) < 1e14f)
9978 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
9979 else
9980 dest[ix][iy][ip] = NAN;
9981 }
9982 omp_set_dynamic(0);
9983
9984 /* Free... */
9985 free(help);
9986 }
9987
9988 /* Unpacked data... */
9989 else if (!ctl->dd) {
9990
9991 /* Allocate... */
9992 float *help;
9993 ALLOC(help, float,
9994 EX * EY * EP);
9995
9996 /* Read fill value and missing value... */
9997 float fillval, missval;
9998 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9999 fillval = 0;
10000 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10001 missval = 0;
10002
10003 /* Write info... */
10004 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
10005 varsel, fillval, missval);
10006
10007 /* Read data... */
10008 NC(nc_get_var_float(ncid, varid, help));
10009
10010 /* Check meteo data layout... */
10011 if (ctl->met_convention == 0) {
10012
10013 /* Copy and check data (ordering: lev, lat, lon)... */
10014 omp_set_dynamic(1);
10015#pragma omp parallel for default(shared)
10016 for (int ix = 0; ix < met->nx; ix++)
10017 for (int iy = 0; iy < met->ny; iy++)
10018 for (int ip = 0; ip < met->np; ip++) {
10019 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
10020 if ((fillval == 0 || aux != fillval)
10021 && (missval == 0 || aux != missval)
10022 && fabsf(aux) < 1e14f)
10023 dest[ix][iy][ip] = scl * aux;
10024 else
10025 dest[ix][iy][ip] = NAN;
10026 }
10027 omp_set_dynamic(0);
10028
10029 } else {
10030
10031 /* Copy and check data (ordering: lon, lat, lev)... */
10032 omp_set_dynamic(1);
10033#pragma omp parallel for default(shared)
10034 for (int ip = 0; ip < met->np; ip++)
10035 for (int iy = 0; iy < met->ny; iy++)
10036 for (int ix = 0; ix < met->nx; ix++) {
10037 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
10038 if ((fillval == 0 || aux != fillval)
10039 && (missval == 0 || aux != missval)
10040 && fabsf(aux) < 1e14f)
10041 dest[ix][iy][ip] = scl * aux;
10042 else
10043 dest[ix][iy][ip] = NAN;
10044 }
10045 omp_set_dynamic(0);
10046 }
10047
10048 /* Free... */
10049 free(help);
10050 }
10051
10052 /* Domain decomposed data... */
10053 else {
10054
10055 /* Read fill value and missing value... */
10056 float fillval, missval;
10057 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
10058 fillval = 0;
10059 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
10060 missval = 0;
10061
10062 /* Write info... */
10063 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
10064 varsel, fillval, missval);
10065
10066 /* Define hyperslab... */
10067 size_t help_subdomain_start[4];
10068 size_t help_subdomain_count[4];
10069 size_t help_halo_bnd_start[4];
10070 size_t help_halo_bnd_count[4];
10071
10072 if (ctl->met_convention == 0) {
10073 for (int i = 0; i < 4; i++) {
10074 help_subdomain_start[i] = dd->subdomain_start[i];
10075 help_subdomain_count[i] = dd->subdomain_count[i];
10076 help_halo_bnd_start[i] = dd->halo_bnd_start[i];
10077 help_halo_bnd_count[i] = dd->halo_bnd_count[i];
10078 }
10079 } else {
10080 help_subdomain_start[0] = dd->subdomain_start[0];
10081 help_subdomain_start[1] = dd->subdomain_start[3];
10082 help_subdomain_start[2] = dd->subdomain_start[2];
10083 help_subdomain_start[3] = dd->subdomain_start[1];
10084
10085 help_subdomain_count[0] = dd->subdomain_count[0];
10086 help_subdomain_count[1] = dd->subdomain_count[3];
10087 help_subdomain_count[2] = dd->subdomain_count[2];
10088 help_subdomain_count[3] = dd->subdomain_count[1];
10089
10090 help_halo_bnd_start[0] = dd->halo_bnd_start[0];
10091 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
10092 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
10093 help_halo_bnd_start[3] = dd->halo_bnd_start[1];
10094
10095 help_halo_bnd_count[0] = dd->halo_bnd_count[0];
10096 help_halo_bnd_count[1] = dd->halo_bnd_count[3];
10097 help_halo_bnd_count[2] = dd->halo_bnd_count[2];
10098 help_halo_bnd_count[3] = dd->halo_bnd_count[1];
10099 }
10100
10101 /* Allocate... */
10102 float *help;
10103 ALLOC(help, float,
10104 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
10105 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
10106
10107 /* Use default NetCDF parallel I/O behavior */
10108#ifdef DD
10109 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
10110#endif
10111 NC(nc_get_vara_float
10112 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
10113
10114 /* Read halos separately at boundaries... */
10115 float *help_halo;
10116 ALLOC(help_halo, float,
10117 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
10118 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
10119
10120 /* Halo read also uses independent access */
10121#ifdef DD
10122 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
10123#endif
10124 NC(nc_get_vara_float(ncid,
10125 varid,
10126 help_halo_bnd_start, help_halo_bnd_count,
10127 help_halo));
10128
10129 /* Check meteo data layout... */
10130 if (ctl->met_convention == 0) {
10131
10132 /* Copy and check data (ordering: lev, lat, lon)... */
10133 omp_set_dynamic(1);
10134#pragma omp parallel for default(shared)
10135 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
10136 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10137 for (int ip = 0; ip < met->np; ip++) {
10138 const float aux =
10139 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
10140 (int) dd->subdomain_count[3])];
10141 if ((fillval == 0 || aux != fillval)
10142 && (missval == 0 || aux != missval)
10143 && fabsf(aux) < 1e14f)
10144 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10145 else
10146 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10147 }
10148
10149#pragma omp parallel for default(shared)
10150 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
10151 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10152 for (int ip = 0; ip < met->np; ip++) {
10153 const float aux =
10154 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
10155 (int) dd->halo_bnd_count[3])];
10156 if ((fillval == 0 || aux != fillval)
10157 && (missval == 0 || aux != missval)
10158 && fabsf(aux) < 1e14f)
10159 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10160 else
10161 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10162 }
10163 omp_set_dynamic(0);
10164
10165 } else {
10166
10167 /* Copy and check data (ordering: lon, lat, lev)... */
10168 omp_set_dynamic(1);
10169#pragma omp parallel for default(shared)
10170 for (int ip = 0; ip < met->np; ip++)
10171 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10172 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
10173 const float aux =
10174 help[ARRAY_3D
10175 (ix, iy, (int) dd->subdomain_count[2], ip, met->np)];
10176 if ((fillval == 0 || aux != fillval)
10177 && (missval == 0 || aux != missval)
10178 && fabsf(aux) < 1e14f)
10179 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
10180 else
10181 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
10182 }
10183
10184#pragma omp parallel for default(shared)
10185 for (int ip = 0; ip < met->np; ip++)
10186 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
10187 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
10188 const float aux =
10189 help_halo[ARRAY_3D(ix, iy, (int) dd->halo_bnd_count[2], ip,
10190 met->np)];
10191 if ((fillval == 0 || aux != fillval)
10192 && (missval == 0 || aux != missval)
10193 && fabsf(aux) < 1e14f)
10194 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
10195 else
10196 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
10197 }
10198 omp_set_dynamic(0);
10199 }
10200
10201 /* Free... */
10202 free(help);
10203 free(help_halo);
10204 }
10205
10206 /* Return... */
10207 return 1;
10208}
10209
10210/*****************************************************************************/
10211
10212#ifdef ECCODES
10213int read_met_grib(
10214 const char *filename,
10215 const ctl_t *ctl,
10216 met_t *met) {
10217
10218 /* Set filenames... */
10219 size_t filename_len = strlen(filename) + 1;
10220 char sf_filename[filename_len];
10221 char ml_filename[filename_len];
10222 strcpy(sf_filename, filename);
10223 strcpy(ml_filename, filename);
10224 get_met_replace(ml_filename, "XX", "ml");
10225 get_met_replace(sf_filename, "XX", "sf");
10226
10227 /* Open files... */
10228 FILE *ml_file = fopen(ml_filename, "rb");
10229 FILE *sf_file = fopen(sf_filename, "rb");
10230 if (ml_file == NULL || sf_file == NULL) {
10231 if (ml_file != NULL) {
10232 fclose(ml_file);
10233 WARN("Cannot open file: %s", sf_filename);
10234 }
10235 if (sf_file != NULL) {
10236 fclose(sf_file);
10237 WARN("Cannot open file: %s", ml_filename);
10238 }
10239 return 0;
10240 }
10241
10242 /* Get handles for model level data... */
10243 int ml_num_messages = 0, err = 0;
10244 ECC(codes_count_in_file(0, ml_file, &ml_num_messages));
10245 codes_handle **ml_handles =
10246 (codes_handle **) malloc(sizeof(codes_handle *) *
10247 (size_t) ml_num_messages);
10248 for (int i = 0; i < ml_num_messages; i++) {
10249 codes_handle *h = NULL;
10250 if ((h = codes_grib_handle_new_from_file(0, ml_file, &err)) != NULL)
10251 ml_handles[i] = h;
10252 }
10253
10254 /* Get handles for surface data... */
10255 int sf_num_messages = 0;
10256 ECC(codes_count_in_file(0, sf_file, &sf_num_messages));
10257 codes_handle **sf_handles =
10258 (codes_handle **) malloc(sizeof(codes_handle *) *
10259 (size_t) sf_num_messages);
10260 for (int i = 0; i < sf_num_messages; i++) {
10261 codes_handle *h = NULL;
10262 if ((h = codes_grib_handle_new_from_file(0, sf_file, &err)) != NULL)
10263 sf_handles[i] = h;
10264 }
10265
10266 /* Close files... */
10267 fclose(ml_file);
10268 fclose(sf_file);
10269
10270 /* Read grid data... */
10271 read_met_grib_grid(ml_handles, ml_num_messages, met);
10272
10273 /* Read surface data... */
10274 read_met_grib_surface(sf_handles, sf_num_messages, ctl, met);
10275 for (int i = 0; i < sf_num_messages; i++)
10276 codes_handle_delete(sf_handles[i]);
10277 free(sf_handles);
10278
10279 /* Compute 3D pressure field... */
10280 size_t value_count = 0;
10281 ECC(codes_get_size(ml_handles[0], "pv", &value_count));
10282 if (value_count % 2 != 0)
10283 ERRMSG("Unexpected pv array length!");
10284 size_t nlevels = value_count / 2 - 1; /* number of full model levels */
10285 double *values;
10286 ALLOC(values, double,
10287 value_count);
10288 ECC(codes_get_double_array(ml_handles[0], "pv", values, &value_count));
10289 double *a_vals = values;
10290 double *b_vals = values + nlevels;
10291 if (met->npl > (int) nlevels)
10292 ERRMSG("met->npl exceeds number of pressure levels in GRIB!");
10293 for (int nx = 0; nx < met->nx; nx++)
10294 for (int ny = 0; ny < met->ny; ny++)
10295 for (int level = 0; level <= met->npl; level++) {
10296 const float p1 = (float) (a_vals[level] * 0.01f +
10297 met->ps[nx][ny] * b_vals[level]);
10298 const float p2 = (float) (a_vals[level + 1] * 0.01f +
10299 met->ps[nx][ny] * b_vals[level + 1]);
10300 met->pl[nx][ny][level] = 0.5f * (p1 + p2);
10301 }
10302 free(values);
10303
10304 /* Read model level data... */
10305 read_met_grib_levels(ml_handles, ml_num_messages, ctl, met);
10306 for (int i = 0; i < ml_num_messages; i++)
10307 codes_handle_delete(ml_handles[i]);
10308 free(ml_handles);
10309
10310 /* Return success... */
10311 return 1;
10312}
10313#endif
10314
10315/*****************************************************************************/
10316
10317#ifdef ECCODES
10319 codes_handle **handles,
10320 int count_handles,
10321 met_t *met) {
10322
10323 /* Set timer... */
10324 SELECT_TIMER("READ_MET_GRIB_GRID", "INPUT");
10325 LOG(2, "Read meteo grid information...");
10326
10327 /* Read date and time... */
10328 char datestr[LEN], timestr[LEN];
10329 size_t s_date = sizeof(datestr);
10330 ECC(codes_get_string(handles[0], "dataDate", datestr, &s_date));
10331 size_t s_time = sizeof(timestr);
10332 ECC(codes_get_string(handles[0], "dataTime", timestr, &s_time));
10333 int year, month, day, hour;
10334 if (sscanf(datestr, "%4d%2d%2d", &year, &month, &day) != 3)
10335 ERRMSG("Failed to parse dataDate: %s", datestr);
10336 if (sscanf(timestr, "%2d", &hour) != 1)
10337 ERRMSG("Failed to parse dataTime: %s", timestr);
10338 time2jsec(year, month, day, hour, 0, 0, 0, &(met->time));
10339 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)", met->time, year, month,
10340 day, hour, 0);
10341
10342 /* Read grid information... */
10343 long count_lat = 0, count_lon = 0;
10344 ECC(codes_get_long(handles[0], "Nj", &count_lat));
10345 ECC(codes_get_long(handles[0], "Ni", &count_lon));
10346 met->ny = (int) count_lat;
10347 met->nx = (int) count_lon;
10348
10349 /* Check grid dimensions... */
10350 LOG(2, "Number of longitudes: %d", met->nx);
10351 if (met->nx < 2 || met->nx > EX)
10352 ERRMSG("Number of longitudes out of range!");
10353 LOG(2, "Number of latitudes: %d", met->ny);
10354 if (met->ny < 2 || met->ny > EY)
10355 ERRMSG("Number of latitudes out of range!");
10356
10357 double first_lon, last_lon, first_lat, last_lat, inc_lon, inc_lat;
10358 ECC(codes_get_double
10359 (handles[0], "longitudeOfFirstGridPointInDegrees", &first_lon));
10360 ECC(codes_get_double
10361 (handles[0], "latitudeOfFirstGridPointInDegrees", &first_lat));
10362 ECC(codes_get_double
10363 (handles[0], "longitudeOfLastGridPointInDegrees", &last_lon));
10364 ECC(codes_get_double
10365 (handles[0], "latitudeOfLastGridPointInDegrees", &last_lat));
10366 ECC(codes_get_double(handles[0], "iDirectionIncrementInDegrees", &inc_lon));
10367 ECC(codes_get_double(handles[0], "jDirectionIncrementInDegrees", &inc_lat));
10368
10369 long jscanpos, iscanneg;
10370 ECC(codes_get_long(handles[0], "iScansNegatively", &iscanneg));
10371 ECC(codes_get_long(handles[0], "jScansPositively", &jscanpos));
10372
10373 /* Compute longitude-latitude grid... */
10374 int counter = 0;
10375 if (iscanneg == 0)
10376 for (double i = first_lon; i <= last_lon + 1e-6; i += inc_lon) {
10377 met->lon[counter] = i;
10378 counter++;
10379 } else
10380 for (double i = first_lon; i > last_lon - 1e-6; i -= inc_lon) {
10381 met->lon[counter] = i;
10382 counter++;
10383 }
10384
10385 counter = 0;
10386 if (jscanpos == 0)
10387 for (double i = first_lat; i > last_lat - 1e-6; i -= inc_lat) {
10388 met->lat[counter] = i;
10389 counter++;
10390 } else
10391 for (double i = first_lat; i <= last_lat + 1e-6; i += inc_lat) {
10392 met->lat[counter] = i;
10393 counter++;
10394 }
10395
10396 /* Write info... */
10397 LOG(2, "Longitudes: %g, %g ... %g deg",
10398 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
10399 LOG(2, "Latitudes: %g, %g ... %g deg",
10400 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
10401
10402 /* Read vertical levels... */
10403 int max_level = 0;
10404 for (int i = 0; i < count_handles; i++) {
10405 long level;
10406 ECC(codes_get_long(handles[i], "level", &level));
10407 if (level > max_level)
10408 max_level = (int) level;
10409 }
10410 met->npl = max_level;
10411
10412 /* Check number of levels... */
10413 LOG(2, "Number of levels: %d", met->npl);
10414 if (met->npl < 2 || met->npl > EP)
10415 ERRMSG("Number of levels out of range!");
10416}
10417#endif
10418
10419/*****************************************************************************/
10420
10421#ifdef ECCODES
10423 codes_handle **handles,
10424 const int num_messages,
10425 const ctl_t *ctl,
10426 met_t *met) {
10427
10428 /* Set timer... */
10429 SELECT_TIMER("READ_MET_GRIB_LEVELS", "INPUT");
10430 LOG(2, "Read level data...");
10431
10432 /* Init... */
10433 int t_flag = 0, u_flag = 0, v_flag = 0, w_flag = 0, o3_flag = 0, h2o_flag =
10434 0, lwc_flag = 0, rwc_flag = 0, iwc_flag = 0, swc_flag = 0, cc_flag = 0;
10435
10436 /* Iterate over all messages... */
10437 for (int i = 0; i < num_messages; i++) {
10438
10439 size_t max_size = LEN;
10440 char short_name[max_size];
10441 size_t value_count;
10442 double *values;
10443
10444 /* Get the current level */
10445 long current_level;
10446 ECC(codes_get_long(handles[i], "level", &current_level));
10447 current_level -= 1;
10448
10449 /* Retrieve data from current message */
10450 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
10451 ECC(codes_get_size(handles[i], "values", &value_count));
10452 ALLOC(values, double,
10453 value_count);
10454 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
10455
10456 /* Read temperature... */
10457 ECC_READ_3D("t", current_level, met->t, 1.0, t_flag);
10458
10459 /* Read horizontal wind and vertical velocity... */
10460 ECC_READ_3D("u", current_level, met->u, 1.0, u_flag);
10461 ECC_READ_3D("v", current_level, met->v, 1.0, v_flag);
10462 ECC_READ_3D("w", current_level, met->w, 0.01f, w_flag);
10463
10464 /* Read water vapor and ozone... */
10465 ECC_READ_3D("q", current_level, met->h2o, (float) (MA / MH2O), h2o_flag);
10466 ECC_READ_3D("o3", current_level, met->o3, (float) (MA / MO3), o3_flag);
10467
10468 /* Read cloud data... */
10469 ECC_READ_3D("clwc", current_level, met->lwc, 1.0, lwc_flag);
10470 ECC_READ_3D("crwc", current_level, met->rwc, 1.0, rwc_flag);
10471 ECC_READ_3D("ciwc", current_level, met->iwc, 1.0, iwc_flag);
10472 ECC_READ_3D("cswc", current_level, met->swc, 1.0, swc_flag);
10473 ECC_READ_3D("cc", current_level, met->cc, 1.0, cc_flag);
10474
10475 /*Free allocated array */
10476 free(values);
10477 }
10478
10479 /* Check whether data were found... */
10480 if (t_flag != met->npl)
10481 ERRMSG("Cannot read temperature!");
10482 if (u_flag != met->npl)
10483 ERRMSG("Cannot read zonal wind!");
10484 if (v_flag != met->npl)
10485 ERRMSG("Cannot read meridional wind!");
10486 if (w_flag != met->npl)
10487 WARN("Cannot read vertical velocity!");
10488 if (h2o_flag != met->npl)
10489 WARN("Cannot read specific humidity!");
10490 if (o3_flag != met->npl)
10491 WARN("Cannot read ozone data!");
10492 if (lwc_flag != met->npl)
10493 WARN("Cannot read cloud liquid water content!");
10494 if (rwc_flag != met->npl)
10495 WARN("Cannot read cloud rain water content!");
10496 if (iwc_flag != met->npl)
10497 WARN("Cannot read cloud ice water content!");
10498 if (swc_flag != met->npl)
10499 WARN("Cannot read cloud snow water content!");
10500 if (cc_flag != met->npl)
10501 WARN("Cannot read cloud cover!");
10502
10503 /* Check ordering of pressure levels... */
10504 for (int ix = 0; ix < met->nx; ix++)
10505 for (int iy = 0; iy < met->ny; iy++)
10506 for (int ip = 1; ip < met->np; ip++)
10507 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
10508 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
10509 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
10510 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip])) {
10511 LOG(1, "%f %f %f %f", met->pl[ix][iy][0], met->pl[ix][iy][1],
10512 met->pl[ix][iy][ip - 1], met->pl[ix][iy][ip]);
10513 ERRMSG("Pressure profiles are not monotonic!");
10514 }
10515
10516 /* Interpolate from model levels to pressure levels... */
10517 if (ctl->met_np > 0) {
10518 met->np = ctl->met_np;
10519
10520 /* Interpolate variables... */
10521 read_met_ml2pl(ctl, met, met->t, "T");
10522 read_met_ml2pl(ctl, met, met->u, "U");
10523 read_met_ml2pl(ctl, met, met->v, "V");
10524 read_met_ml2pl(ctl, met, met->w, "W");
10525 read_met_ml2pl(ctl, met, met->h2o, "H2O");
10526 read_met_ml2pl(ctl, met, met->o3, "O3");
10527 read_met_ml2pl(ctl, met, met->lwc, "LWC");
10528 read_met_ml2pl(ctl, met, met->rwc, "RWC");
10529 read_met_ml2pl(ctl, met, met->iwc, "IWC");
10530 read_met_ml2pl(ctl, met, met->swc, "SWC");
10531 read_met_ml2pl(ctl, met, met->cc, "CC");
10532
10533 /* Set new pressure levels... */
10534 for (int ip = 0; ip < met->np; ip++)
10535 met->p[ip] = ctl->met_p[ip];
10536 }
10537
10538 /* Check ordering of pressure levels... */
10539 for (int ip = 1; ip < met->np; ip++)
10540 if (met->p[ip - 1] < met->p[ip])
10541 ERRMSG("Pressure levels must be descending!");
10542}
10543#endif
10544
10545/*****************************************************************************/
10546
10547#ifdef ECCODES
10549 codes_handle **handles,
10550 const int num_messages,
10551 const ctl_t *ctl,
10552 met_t *met) {
10553
10554 /* Set timer... */
10555 SELECT_TIMER("READ_MET_GRIB_SURFACE", "INPUT");
10556 LOG(2, "Read surface data...");
10557
10558 /* Init... */
10559 int sp_flag = 0, z_flag = 0, t_flag = 0, u_flag = 0, v_flag = 0, ess_flag =
10560 0, nss_flag = 0, shf_flag = 0, lsm_flag = 0, sst_flag = 0, cape_flag = 0,
10561 cin_flag = 0, pbl_flag = 0;
10562
10563 /* Iterate over all messages... */
10564 for (int i = 0; i < num_messages; i++) {
10565
10566 size_t max_size = LEN, value_count;
10567
10568 char short_name[max_size];
10569
10570 /* Store values with shortname... */
10571 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
10572 ECC(codes_get_size(handles[i], "values", &value_count));
10573 double *values = (double *) malloc(value_count * sizeof(double));
10574 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
10575
10576 /*Read surface pressure... */
10577 ECC_READ_2D("sp", met->ps, 0.01f, sp_flag);
10578
10579 /*Read geopotential height at the surface... */
10580 ECC_READ_2D("z", met->zs, (float) (1. / (1000. * G0)), z_flag);
10581
10582 /* Read temperature at the surface... */
10583 ECC_READ_2D("2t", met->ts, 1.0f, t_flag);
10584
10585 /* Read zonal wind at the surface... */
10586 ECC_READ_2D("10u", met->us, 1.0f, u_flag);
10587
10588 /* Read meridional wind at the surface... */
10589 ECC_READ_2D("10v", met->vs, 1.0f, v_flag);
10590
10591 /* Read eastward turbulent surface stress... */
10592 ECC_READ_2D("iews", met->ess, 1.0f, ess_flag);
10593
10594 /* Read northward turbulent surface stress... */
10595 ECC_READ_2D("inss", met->nss, 1.0f, nss_flag);
10596
10597 /* Read surface sensible heat flux... */
10598 ECC_READ_2D("ishf", met->shf, 1.0f, shf_flag);
10599
10600 /* Read land-sea mask... */
10601 ECC_READ_2D("lsm", met->lsm, 1.0f, lsm_flag);
10602
10603 /* Read sea surface temperature... */
10604 ECC_READ_2D("sst", met->sst, 1.0f, sst_flag);
10605 if (ctl->met_cape == 0) {
10606
10607 /* Read CAPE... */
10608 ECC_READ_2D("cape", met->cape, 1.0f, cape_flag);
10609
10610 /* Read CIN... */
10611 ECC_READ_2D("cin", met->cin, 1.0f, cin_flag);
10612 }
10613
10614 /* Read PBL... */
10615 if (ctl->met_pbl == 1)
10616 ECC_READ_2D("blh", met->pbl, 0.001f, pbl_flag);
10617 }
10618
10619 /* Check whether data have been read... */
10620 if (sp_flag == 0)
10621 WARN("Cannot read surface pressure data!");
10622 if (z_flag == 0)
10623 WARN("Cannot read surface geopotential height!");
10624 if (t_flag == 0)
10625 WARN("Cannot read surface temperature!");
10626 if (u_flag == 0)
10627 WARN("Cannot read surface zonal wind!");
10628 if (v_flag == 0)
10629 WARN("Cannot read surface meridional wind!");
10630 if (ess_flag == 0)
10631 WARN("Cannot read eastward turbulent surface stress!");
10632 if (nss_flag == 0)
10633 WARN("Cannot read northward turbulent surface stress!");
10634 if (shf_flag == 0)
10635 WARN("Cannot read surface sensible heat flux!");
10636 if (lsm_flag == 0)
10637 WARN("Cannot read land-sea mask!");
10638 if (sst_flag == 0)
10639 WARN("Cannot read sea surface temperature!");
10640 if (ctl->met_cape == 0) {
10641 if (cape_flag == 0)
10642 WARN("Cannot read CAPE!");
10643 if (cin_flag == 0)
10644 WARN("Cannot read convective inhibition!");
10645 }
10646 if (ctl->met_pbl == 1 && pbl_flag == 0)
10647 WARN("Cannot read planetary boundary layer height!");
10648}
10649#endif
10650
10651/*****************************************************************************/
10652
10654 const ctl_t *ctl,
10655 const met_t *met,
10656 float var[EX][EY][EP],
10657 const char *varname) {
10658
10659 double aux[EP], p[EP];
10660
10661 /* Set timer... */
10662 SELECT_TIMER("READ_MET_ML2PL", "METPROC");
10663 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
10664
10665 /* Loop over columns... */
10666#pragma omp parallel for default(shared) private(aux,p) collapse(2)
10667 for (int ix = 0; ix < met->nx; ix++)
10668 for (int iy = 0; iy < met->ny; iy++) {
10669
10670 /* Copy pressure profile... */
10671 for (int ip = 0; ip < met->np; ip++)
10672 p[ip] = met->pl[ix][iy][ip];
10673
10674 /* Interpolate... */
10675 for (int ip = 0; ip < ctl->met_np; ip++) {
10676 double pt = ctl->met_p[ip];
10677 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
10678 pt = p[0];
10679 else if ((pt > p[met->np - 1] && p[1] > p[0])
10680 || (pt < p[met->np - 1] && p[1] < p[0]))
10681 pt = p[met->np - 1];
10682 const int ip2 = locate_irr(p, met->np, pt);
10683 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
10684 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
10685 }
10686
10687 /* Copy data... */
10688 for (int ip = 0; ip < ctl->met_np; ip++)
10689 var[ix][iy][ip] = (float) aux[ip];
10690 }
10691}
10692
10693/*****************************************************************************/
10694
10696 const ctl_t *ctl,
10697 met_t *met) {
10698
10699 /* Check parameters... */
10700 if (ctl->advect_vert_coord != 1)
10701 return;
10702
10703 /* Set timer... */
10704 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC");
10705 LOG(2, "Make zeta profiles monotone...");
10706
10707 /* Create monotone zeta profiles... */
10708#pragma omp parallel for default(shared) collapse(2)
10709 for (int i = 0; i < met->nx; i++)
10710 for (int j = 0; j < met->ny; j++) {
10711 int k = 1;
10712
10713 while (k < met->npl) { /* Check if there is an inversion at level k... */
10714 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
10715 /* Find the upper level k+l over the inversion... */
10716 int l = 0;
10717 do {
10718 l++;
10719 }
10720 while ((met->zetal[i][j][k - 1] >=
10721 met->zetal[i][j][k + l]) & (k + l < met->npl));
10722
10723 /* Interpolate linear between the top and bottom
10724 of the inversion... */
10725 float s =
10726 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
10727 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
10728
10729 for (int m = k; m < k + l; m++) {
10730 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
10731 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
10732 }
10733
10734 /* Search for more inversions above the last inversion ... */
10735 k = k + l;
10736 } else {
10737 k++;
10738 }
10739 }
10740 }
10741
10742 /* Create monotone pressure profiles... */
10743#pragma omp parallel for default(shared) collapse(2)
10744 for (int i = 0; i < met->nx; i++)
10745 for (int j = 0; j < met->ny; j++) {
10746 int k = 1;
10747
10748 while (k < met->npl) { /* Check if there is an inversion at level k... */
10749 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
10750
10751 /* Find the upper level k+l over the inversion... */
10752 int l = 0;
10753 do {
10754 l++;
10755 }
10756 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
10757 met->npl));
10758
10759 /* Interpolate linear between the top and bottom
10760 of the inversion... */
10761 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
10762 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
10763
10764 for (int m = k; m < k + l; m++) {
10765 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
10766 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
10767 }
10768
10769 /* Search for more inversions above the last inversion ... */
10770 k += l;
10771 } else {
10772 k++;
10773 }
10774 }
10775 }
10776}
10777
10778/*****************************************************************************/
10779
10781 const char *filename,
10782 const ctl_t *ctl,
10783 met_t *met,
10784 dd_t *dd) {
10785
10786 int ncid;
10787
10788 /* Open file... */
10789#ifdef DD
10790 if (ctl->dd) {
10791 NC(nc_open_par
10792 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
10793 &ncid))
10794 }
10795#else
10796 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
10797 WARN("Cannot open file!");
10798 return 0;
10799 }
10800#endif
10801
10802 /* Set coordinate system of meteo data... */
10803 met->coord_type = ctl->met_coord_type;
10804
10805 /* Read coordinates of meteo data... */
10806 read_met_nc_grid(filename, ncid, ctl, met, dd);
10807
10808 /* Read surface data... */
10809 read_met_nc_surface(ncid, ctl, met, dd);
10810
10811 /* Read meteo data on vertical levels... */
10812 read_met_nc_levels(ncid, ctl, met, dd);
10813
10814 /* Close file... */
10815 NC(nc_close(ncid));
10816
10817 /* Return success... */
10818 return 1;
10819}
10820
10821/*****************************************************************************/
10822
10824 dd_t *dd,
10825 const ctl_t *ctl,
10826 met_t *met,
10827 const int ncid) {
10828
10829 int varid;
10830
10831 /* Get the MPI information... */
10832 int rank = 0, size = 1;
10833#ifdef MPI
10834 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
10835 MPI_Comm_size(MPI_COMM_WORLD, &size);
10836#endif
10837
10838 /* Get grid dimensions... */
10839 NC_INQ_DIM("lon", &dd->nx_glob, 0, 0, 0);
10840 NC_INQ_DIM("lat", &dd->ny_glob, 0, 0, 0);
10841
10842 LOG(2, "Number of longitudes: %d", dd->nx_glob);
10843 LOG(2, "Number of latitudes: %d", dd->ny_glob);
10844
10845 /* Check grid... */
10846 if (dd->nx_glob > DD_EX_GLOB || dd->ny_glob > DD_EY_GLOB)
10847 ERRMSG("Global grid is too large!");
10848
10849 if (ctl->dd_subdomains_zonal > dd->nx_glob)
10850 ERRMSG("Too many zonal subdomains for global x grid!");
10851
10852 if (ctl->dd_subdomains_meridional > dd->ny_glob)
10853 ERRMSG("Too many meridional subdomains for global y grid!");
10854
10855 /* Read global longitudes and latitudes... */
10856 NC_GET_DOUBLE("lon", dd->lon_glob, 1);
10857 NC_GET_DOUBLE("lat", dd->lat_glob, 1);
10858
10859 LOG(2, "Longitudes: %g, %g ... %g deg",
10860 dd->lon_glob[0], dd->lon_glob[1], dd->lon_glob[dd->nx_glob - 1]);
10861 LOG(2, "Latitudes: %g, %g ... %g deg",
10862 dd->lat_glob[0], dd->lat_glob[1], dd->lat_glob[dd->ny_glob - 1]);
10863
10864 /* Rank coordinates in DD layout... */
10865 const int zonal_rank = rank / ctl->dd_subdomains_meridional;
10866 const int merid_rank = rank % ctl->dd_subdomains_meridional;
10867
10868 /* Check for edge cases... */
10869 const int left = (zonal_rank == 0);
10870 const int right = (zonal_rank == ctl->dd_subdomains_zonal - 1);
10871 const int top = (merid_rank == 0);
10872 const int bottom = (merid_rank == ctl->dd_subdomains_meridional - 1);
10873
10874 /* Core owned block (without halos)... */
10875 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
10876 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
10877
10878 const int ix0 = zonal_rank * nx_block;
10879 const int iy0 = merid_rank * ny_block;
10880
10881 int nx_core = nx_block;
10882 int ny_core = ny_block;
10883
10884 if (right)
10885 nx_core += dd->nx_glob - ctl->dd_subdomains_zonal * nx_block;
10886 if (bottom)
10887 ny_core += dd->ny_glob - ctl->dd_subdomains_meridional * ny_block;
10888
10889 /* Store core met size first... */
10890 met->nx = nx_core;
10891 met->ny = ny_core;
10892
10893 /* Set hyperslab for core subdomain... */
10894 dd->subdomain_start[0] = 0;
10895 dd->subdomain_start[1] = 0;
10896 dd->subdomain_start[2] = (size_t) iy0;
10897 dd->subdomain_start[3] = (size_t) ix0;
10898
10899 dd->subdomain_count[0] = 1;
10900 dd->subdomain_count[1] = (size_t) met->np;
10901 dd->subdomain_count[2] = (size_t) ny_core;
10902 dd->subdomain_count[3] = (size_t) nx_core;
10903
10904 /* Add inner halos to read window... */
10905 if (!left && !right) {
10906 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
10907 dd->subdomain_count[3] += (size_t) (2 * ctl->dd_halos_size);
10908 } else if (left ^ right) {
10909 dd->subdomain_count[3] += (size_t) ctl->dd_halos_size;
10910 if (!left)
10911 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
10912 }
10913
10914 if (!top && !bottom) {
10915 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
10916 dd->subdomain_count[2] += (size_t) (2 * ctl->dd_halos_size);
10917 } else if (top ^ bottom) {
10918 dd->subdomain_count[2] += (size_t) ctl->dd_halos_size;
10919 if (!top)
10920 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
10921 }
10922
10923 /* Set boundary halo hyperslabs... */
10924 double lon_shift = 0.0;
10925
10926 if (left ^ right) {
10927 dd->halo_bnd_start[0] = 0;
10928 dd->halo_bnd_start[1] = 0;
10929 dd->halo_bnd_start[2] = dd->subdomain_start[2];
10930 dd->halo_bnd_start[3] =
10931 (size_t) (left ? (dd->nx_glob - ctl->dd_halos_size) : 0);
10932
10933 dd->halo_bnd_count[0] = 1;
10934 dd->halo_bnd_count[1] = (size_t) met->np;
10935 dd->halo_bnd_count[2] =
10936 (size_t) met->ny +
10937 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
10938 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
10939
10940 dd->halo_offset_start = left ? (int) dd->halo_bnd_count[3] : 0;
10941 dd->halo_offset_end = left ? 0 : (int) dd->subdomain_count[3];
10942 lon_shift = left ? -360.0 : 360.0;
10943 } else {
10944 dd->halo_bnd_start[0] = 0;
10945 dd->halo_bnd_start[1] = 0;
10946 dd->halo_bnd_start[2] = 0;
10947 dd->halo_bnd_start[3] = 0;
10948
10949 dd->halo_bnd_count[0] = 0;
10950 dd->halo_bnd_count[1] = 0;
10951 dd->halo_bnd_count[2] = 0;
10952 dd->halo_bnd_count[3] = 0;
10953
10954 dd->halo_offset_start = 0;
10955 dd->halo_offset_end = 0;
10956 }
10957
10958 /* Focus on subdomain latitudes... */
10959 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10960 met->lat[iy] = dd->lat_glob[(int) dd->subdomain_start[2] + iy];
10961
10962 /* Focus on subdomain longitudes... */
10963 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
10964 met->lon[ix + dd->halo_offset_start] =
10965 dd->lon_glob[(int) dd->subdomain_start[3] + ix];
10966
10967 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
10968 met->lon[ix + dd->halo_offset_end] =
10969 dd->lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
10970
10971 /* Reset halo-extended grid dimensions... */
10972 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
10973 met->ny = (int) dd->subdomain_count[2];
10974
10975 LOG(2, "Define subdomain properties.");
10976 LOG(2, "MPI information: Rank %d, Size %d", rank, size);
10977 LOG(2, "Edge position: l=%d,r=%d,t=%d,b=%d", left, right, top, bottom);
10978 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d",
10979 met->nx, met->ny, met->np);
10980 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
10981 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
10982 (int) dd->halo_bnd_count[1]);
10983 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
10984 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
10985 (int) dd->subdomain_count[1]);
10986 LOG(2, "Subdomain start: nx %ld ny %ld np %ld",
10987 dd->subdomain_start[3], dd->subdomain_start[2], dd->subdomain_start[1]);
10988 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld",
10989 dd->halo_bnd_start[3], dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
10990 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
10991 LOG(2, "%d Subdomain longitudes: %g, %g ... %g deg",
10992 rank, met->lon[0], met->lon[1], met->lon[met->nx - 1]);
10993 LOG(2, "%d Subdomain latitudes: %g, %g ... %g deg",
10994 rank, met->lat[0], met->lat[1], met->lat[met->ny - 1]);
10995}
10996
10997/*****************************************************************************/
10998
11000 const ctl_t *ctl,
11001 met_t *met) {
11002
11003 /* Set timer... */
11004 SELECT_TIMER("READ_MET_PBL", "METPROC");
11005 LOG(2, "Calculate planetary boundary layer...");
11006
11007 /* Convert PBL height from meteo file to pressure... */
11008 if (ctl->met_pbl == 1) {
11009
11010 /* Loop over grid points... */
11011#pragma omp parallel for default(shared) collapse(2)
11012 for (int ix = 0; ix < met->nx; ix++)
11013 for (int iy = 0; iy < met->ny; iy++) {
11014
11015 /* Get pressure at top of PBL... */
11016 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
11017 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
11018 met->pbl[ix][iy] =
11019 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
11020 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
11021 }
11022 }
11023
11024 /* Determine PBL based on Richardson number... */
11025 else if (ctl->met_pbl == 2) {
11026
11027 /* Parameters used to estimate the height of the PBL
11028 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
11029 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
11030
11031 /* Loop over grid points... */
11032#pragma omp parallel for default(shared) collapse(2)
11033 for (int ix = 0; ix < met->nx; ix++)
11034 for (int iy = 0; iy < met->ny; iy++) {
11035
11036 /* Set bottom level of PBL... */
11037 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
11038
11039 /* Find lowest level near the bottom... */
11040 int ip;
11041 for (ip = 1; ip < met->np; ip++)
11042 if (met->p[ip] < pbl_bot)
11043 break;
11044
11045 /* Get near surface data... */
11046 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
11047 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
11048 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
11049
11050 /* Init... */
11051 double rib_old = 0;
11052
11053 /* Loop over levels... */
11054 for (; ip < met->np; ip++) {
11055
11056 /* Get squared horizontal wind speed... */
11057 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
11058 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
11059 vh2 = MAX(vh2, SQR(umin));
11060
11061 /* Calculate bulk Richardson number... */
11062 const double rib =
11063 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
11064 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
11065 met->h2o[ix][iy][ip]) - tvs) / vh2;
11066
11067 /* Check for critical value... */
11068 if (rib >= rib_crit) {
11069 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
11070 rib, met->p[ip], rib_crit));
11071 if (met->pbl[ix][iy] > pbl_bot)
11072 met->pbl[ix][iy] = (float) pbl_bot;
11073 break;
11074 }
11075
11076 /* Save Richardson number... */
11077 rib_old = rib;
11078 }
11079 }
11080 }
11081
11082 /* Determine PBL based on potential temperature... */
11083 if (ctl->met_pbl == 3) {
11084
11085 /* Parameters used to estimate the height of the PBL
11086 (following HYSPLIT model)... */
11087 const double dtheta = 2.0, zmin = 0.1;
11088
11089 /* Loop over grid points... */
11090#pragma omp parallel for default(shared) collapse(2)
11091 for (int ix = 0; ix < met->nx; ix++)
11092 for (int iy = 0; iy < met->ny; iy++) {
11093
11094 /* Potential temperature at the surface... */
11095 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
11096
11097 /* Find topmost level where theta exceeds surface value by 2 K... */
11098 int ip;
11099 for (ip = met->np - 2; ip > 0; ip--)
11100 if (met->p[ip] >= 300.)
11101 if (met->p[ip] > met->ps[ix][iy]
11102 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
11103 break;
11104
11105 /* Interpolate... */
11106 met->pbl[ix][iy]
11107 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
11108 met->p[ip + 1],
11109 THETA(met->p[ip], met->t[ix][iy][ip]),
11110 met->p[ip], theta0 + dtheta));
11111
11112 /* Check minimum value... */
11113 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
11114 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
11115 met->pbl[ix][iy] = (float) pbl_min;
11116 }
11117 }
11118
11119 /* Loop over grid points... */
11120#pragma omp parallel for default(shared) collapse(2)
11121 for (int ix = 0; ix < met->nx; ix++)
11122 for (int iy = 0; iy < met->ny; iy++) {
11123
11124 /* Check minimum value... */
11125 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
11126 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
11127
11128 /* Check maximum value... */
11129 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
11130 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
11131 }
11132}
11133
11134/*****************************************************************************/
11135
11137 met_t *met) {
11138
11139 /* Set timer... */
11140 SELECT_TIMER("READ_MET_PERIODIC", "METPROC");
11141 LOG(2, "Apply periodic boundary conditions...");
11142
11143 /* Check longitudes... */
11144 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
11145 + met->lon[1] - met->lon[0] - 360) < 0.01))
11146 return;
11147
11148 /* Increase longitude counter... */
11149 if ((++met->nx) >= EX)
11150 ERRMSG("Cannot create periodic boundary conditions!");
11151
11152 /* Set longitude... */
11153 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
11154
11155 /* Loop over latitudes and pressure levels... */
11156#pragma omp parallel for default(shared)
11157 for (int iy = 0; iy < met->ny; iy++) {
11158 met->ps[met->nx - 1][iy] = met->ps[0][iy];
11159 met->zs[met->nx - 1][iy] = met->zs[0][iy];
11160 met->ts[met->nx - 1][iy] = met->ts[0][iy];
11161 met->us[met->nx - 1][iy] = met->us[0][iy];
11162 met->vs[met->nx - 1][iy] = met->vs[0][iy];
11163 met->ess[met->nx - 1][iy] = met->ess[0][iy];
11164 met->nss[met->nx - 1][iy] = met->nss[0][iy];
11165 met->shf[met->nx - 1][iy] = met->shf[0][iy];
11166 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
11167 met->sst[met->nx - 1][iy] = met->sst[0][iy];
11168 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
11169 met->cape[met->nx - 1][iy] = met->cape[0][iy];
11170 met->cin[met->nx - 1][iy] = met->cin[0][iy];
11171 for (int ip = 0; ip < met->np; ip++) {
11172 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
11173 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
11174 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
11175 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
11176 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
11177 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
11178 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
11179 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
11180 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
11181 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
11182 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
11183 }
11184 for (int ip = 0; ip < met->npl; ip++) {
11185 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
11186 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
11187 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
11188 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
11189 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
11190 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
11191 }
11192 }
11193}
11194
11195/*****************************************************************************/
11196
11198 met_t *met) {
11199
11200 /* Set timer... */
11201 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC");
11202 LOG(2, "Apply fix for polar winds...");
11203
11204 if (met->coord_type != 0)
11205 return;
11206
11207 /* Check latitudes... */
11208 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
11209 return;
11210
11211 /* Loop over hemispheres... */
11212 for (int ihem = 0; ihem < 2; ihem++) {
11213
11214 /* Set latitude indices... */
11215 int i89 = 1, i90 = 0, sign = 1;
11216 if (ihem == 1) {
11217 i89 = met->ny - 2;
11218 i90 = met->ny - 1;
11219 }
11220 if (met->lat[i90] < 0)
11221 sign = -1;
11222
11223 /* Look-up table of cosinus and sinus... */
11224 double clon[EX], slon[EX];
11225#pragma omp parallel for default(shared)
11226 for (int ix = 0; ix < met->nx; ix++) {
11227 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
11228 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
11229 }
11230
11231 /* Loop over levels... */
11232#pragma omp parallel for default(shared)
11233 for (int ip = 0; ip < met->np; ip++) {
11234
11235 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
11236 double vel89x = 0, vel89y = 0;
11237 for (int ix = 0; ix < met->nx; ix++) {
11238 vel89x +=
11239 (met->u[ix][i89][ip] * clon[ix] -
11240 met->v[ix][i89][ip] * slon[ix]) / met->nx;
11241 vel89y +=
11242 (met->u[ix][i89][ip] * slon[ix] +
11243 met->v[ix][i89][ip] * clon[ix]) / met->nx;
11244 }
11245
11246 /* Replace 90 degree winds by 89 degree mean... */
11247 for (int ix = 0; ix < met->nx; ix++) {
11248 met->u[ix][i90][ip]
11249 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
11250 met->v[ix][i90][ip]
11251 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
11252 }
11253 }
11254 }
11255}
11256
11257/*****************************************************************************/
11258
11260 met_t *met) {
11261
11262 double pows[EP];
11263
11264 /* Set timer... */
11265 SELECT_TIMER("READ_MET_PV", "METPROC");
11266 LOG(2, "Calculate potential vorticity...");
11267
11268 /* Set powers... */
11269#pragma omp parallel for default(shared)
11270 for (int ip = 0; ip < met->np; ip++)
11271 pows[ip] = pow(1000. / met->p[ip], 0.286);
11272
11273 /* Loop over grid points... */
11274#pragma omp parallel for default(shared)
11275 for (int ix = 0; ix < met->nx; ix++) {
11276
11277 /* Set indices... */
11278 const int ix0 = MAX(ix - 1, 0);
11279 const int ix1 = MIN(ix + 1, met->nx - 1);
11280
11281 /* Loop over grid points... */
11282 for (int iy = 0; iy < met->ny; iy++) {
11283
11284 /* Set indices... */
11285 const int iy0 = MAX(iy - 1, 0);
11286 const int iy1 = MIN(iy + 1, met->ny - 1);
11287
11288 /* Set auxiliary variables... */
11289 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
11290 double dx, dy, c0, c1, cr, vort;
11291
11292 // Calculate potential vorticity..
11293 if (met->coord_type == 0) { // coords are lat/lon
11294 dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
11295 dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
11296 c0 = cos(DEG2RAD(met->lat[iy0]));
11297 c1 = cos(DEG2RAD(met->lat[iy1]));
11298 cr = cos(DEG2RAD(latr));
11299 vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
11300 } else { // coords are in meters
11301 dx = met->lon[ix1] - met->lon[ix0];
11302 dy = met->lat[iy1] - met->lat[iy0];
11303
11304 c0 = 1.0;
11305 c1 = 1.0;
11306 cr = 1.0;
11307
11308 vort = 2 * 7.2921e-5 * sin(latr / (RE * 1000));
11309 }
11310
11311 /* Loop over grid points... */
11312 for (int ip = 0; ip < met->np; ip++) {
11313
11314 /* Get gradients in longitude... */
11315 const double dtdx
11316 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
11317 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
11318
11319 /* Get gradients in latitude... */
11320 const double dtdy
11321 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
11322 const double dudy
11323 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
11324
11325 /* Set indices... */
11326 const int ip0 = MAX(ip - 1, 0);
11327 const int ip1 = MIN(ip + 1, met->np - 1);
11328
11329 /* Get gradients in pressure... */
11330 double dtdp, dudp, dvdp;
11331 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
11332 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
11333 if (ip != ip0 && ip != ip1) {
11334 double denom = dp0 * dp1 * (dp0 + dp1);
11335 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
11336 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
11337 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
11338 / denom;
11339 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
11340 - dp1 * dp1 * met->u[ix][iy][ip0]
11341 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
11342 / denom;
11343 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
11344 - dp1 * dp1 * met->v[ix][iy][ip0]
11345 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
11346 / denom;
11347 } else {
11348 const double denom = dp0 + dp1;
11349 dtdp =
11350 (met->t[ix][iy][ip1] * pows[ip1] -
11351 met->t[ix][iy][ip0] * pows[ip0]) / denom;
11352 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
11353 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
11354 }
11355
11356 /* Calculate PV... */
11357 met->pv[ix][iy][ip] = (float)
11358 (1e6 * G0 *
11359 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
11360 }
11361 }
11362 }
11363
11364 /* Fix for polar regions... */
11365#pragma omp parallel for default(shared)
11366 for (int ix = 0; ix < met->nx; ix++)
11367 for (int ip = 0; ip < met->np; ip++) {
11368 met->pv[ix][0][ip]
11369 = met->pv[ix][1][ip]
11370 = met->pv[ix][2][ip];
11371 met->pv[ix][met->ny - 1][ip]
11372 = met->pv[ix][met->ny - 2][ip]
11373 = met->pv[ix][met->ny - 3][ip];
11374 }
11375}
11376
11377/*****************************************************************************/
11378
11380 met_t *met) {
11381
11382 /* Set timer... */
11383 SELECT_TIMER("READ_MET_OZONE", "METPROC");
11384 LOG(2, "Calculate total column ozone...");
11385
11386 /* Loop over columns... */
11387#pragma omp parallel for default(shared) collapse(2)
11388 for (int ix = 0; ix < met->nx; ix++)
11389 for (int iy = 0; iy < met->ny; iy++) {
11390
11391 /* Integrate... */
11392 double cd = 0;
11393 for (int ip = 1; ip < met->np; ip++)
11394 if (met->p[ip - 1] <= met->ps[ix][iy]) {
11395 const double vmr =
11396 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
11397 const double dp = met->p[ip - 1] - met->p[ip];
11398 cd += vmr * MO3 / MA * dp * 1e2 / G0;
11399 }
11400
11401 /* Convert to Dobson units... */
11402 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
11403 }
11404}
11405
11406/*****************************************************************************/
11407
11409 const ctl_t *ctl,
11410 met_t *met) {
11411
11412 met_t *help;
11413
11414 /* Check parameters... */
11415 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
11416 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
11417 return;
11418
11419 /* Set timer... */
11420 SELECT_TIMER("READ_MET_SAMPLE", "METPROC");
11421 LOG(2, "Downsampling of meteo data...");
11422
11423 /* Allocate... */
11424 ALLOC(help, met_t, 1);
11425
11426 /* Copy data... */
11427 help->nx = met->nx;
11428 help->ny = met->ny;
11429 help->np = met->np;
11430 memcpy(help->lon, met->lon, sizeof(met->lon));
11431 memcpy(help->lat, met->lat, sizeof(met->lat));
11432 memcpy(help->p, met->p, sizeof(met->p));
11433
11434 /* Smoothing... */
11435 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
11436 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
11437 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
11438 help->ps[ix][iy] = 0;
11439 help->zs[ix][iy] = 0;
11440 help->ts[ix][iy] = 0;
11441 help->us[ix][iy] = 0;
11442 help->vs[ix][iy] = 0;
11443 help->ess[ix][iy] = 0;
11444 help->nss[ix][iy] = 0;
11445 help->shf[ix][iy] = 0;
11446 help->lsm[ix][iy] = 0;
11447 help->sst[ix][iy] = 0;
11448 help->pbl[ix][iy] = 0;
11449 help->cape[ix][iy] = 0;
11450 help->cin[ix][iy] = 0;
11451 help->t[ix][iy][ip] = 0;
11452 help->u[ix][iy][ip] = 0;
11453 help->v[ix][iy][ip] = 0;
11454 help->w[ix][iy][ip] = 0;
11455 help->h2o[ix][iy][ip] = 0;
11456 help->o3[ix][iy][ip] = 0;
11457 help->lwc[ix][iy][ip] = 0;
11458 help->rwc[ix][iy][ip] = 0;
11459 help->iwc[ix][iy][ip] = 0;
11460 help->swc[ix][iy][ip] = 0;
11461 help->cc[ix][iy][ip] = 0;
11462 float wsum = 0;
11463 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
11464 ix2++) {
11465 int ix3 = ix2;
11466 if (ix3 < 0)
11467 ix3 += met->nx;
11468 else if (ix3 >= met->nx)
11469 ix3 -= met->nx;
11470
11471 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
11472 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
11473 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
11474 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
11475 const float w =
11476 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
11477 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
11478 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
11479 help->ps[ix][iy] += w * met->ps[ix3][iy2];
11480 help->zs[ix][iy] += w * met->zs[ix3][iy2];
11481 help->ts[ix][iy] += w * met->ts[ix3][iy2];
11482 help->us[ix][iy] += w * met->us[ix3][iy2];
11483 help->vs[ix][iy] += w * met->vs[ix3][iy2];
11484 help->ess[ix][iy] += w * met->ess[ix3][iy2];
11485 help->nss[ix][iy] += w * met->nss[ix3][iy2];
11486 help->shf[ix][iy] += w * met->shf[ix3][iy2];
11487 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
11488 help->sst[ix][iy] += w * met->sst[ix3][iy2];
11489 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
11490 help->cape[ix][iy] += w * met->cape[ix3][iy2];
11491 help->cin[ix][iy] += w * met->cin[ix3][iy2];
11492 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
11493 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
11494 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
11495 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
11496 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
11497 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
11498 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
11499 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
11500 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
11501 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
11502 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
11503 wsum += w;
11504 }
11505 }
11506 help->ps[ix][iy] /= wsum;
11507 help->zs[ix][iy] /= wsum;
11508 help->ts[ix][iy] /= wsum;
11509 help->us[ix][iy] /= wsum;
11510 help->vs[ix][iy] /= wsum;
11511 help->ess[ix][iy] /= wsum;
11512 help->nss[ix][iy] /= wsum;
11513 help->shf[ix][iy] /= wsum;
11514 help->lsm[ix][iy] /= wsum;
11515 help->sst[ix][iy] /= wsum;
11516 help->pbl[ix][iy] /= wsum;
11517 help->cape[ix][iy] /= wsum;
11518 help->cin[ix][iy] /= wsum;
11519 help->t[ix][iy][ip] /= wsum;
11520 help->u[ix][iy][ip] /= wsum;
11521 help->v[ix][iy][ip] /= wsum;
11522 help->w[ix][iy][ip] /= wsum;
11523 help->h2o[ix][iy][ip] /= wsum;
11524 help->o3[ix][iy][ip] /= wsum;
11525 help->lwc[ix][iy][ip] /= wsum;
11526 help->rwc[ix][iy][ip] /= wsum;
11527 help->iwc[ix][iy][ip] /= wsum;
11528 help->swc[ix][iy][ip] /= wsum;
11529 help->cc[ix][iy][ip] /= wsum;
11530 }
11531 }
11532 }
11533
11534 /* Downsampling... */
11535 met->nx = 0;
11536 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
11537 met->lon[met->nx] = help->lon[ix];
11538 met->ny = 0;
11539 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
11540 met->lat[met->ny] = help->lat[iy];
11541 met->ps[met->nx][met->ny] = help->ps[ix][iy];
11542 met->zs[met->nx][met->ny] = help->zs[ix][iy];
11543 met->ts[met->nx][met->ny] = help->ts[ix][iy];
11544 met->us[met->nx][met->ny] = help->us[ix][iy];
11545 met->vs[met->nx][met->ny] = help->vs[ix][iy];
11546 met->ess[met->nx][met->ny] = help->ess[ix][iy];
11547 met->nss[met->nx][met->ny] = help->nss[ix][iy];
11548 met->shf[met->nx][met->ny] = help->shf[ix][iy];
11549 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
11550 met->sst[met->nx][met->ny] = help->sst[ix][iy];
11551 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
11552 met->cape[met->nx][met->ny] = help->cape[ix][iy];
11553 met->cin[met->nx][met->ny] = help->cin[ix][iy];
11554 met->np = 0;
11555 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
11556 met->p[met->np] = help->p[ip];
11557 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
11558 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
11559 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
11560 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
11561 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
11562 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
11563 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
11564 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
11565 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
11566 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
11567 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
11568 met->np++;
11569 }
11570 met->ny++;
11571 }
11572 met->nx++;
11573 }
11574
11575 /* Free... */
11576 free(help);
11577}
11578
11579/*****************************************************************************/
11580
11582 const ctl_t *ctl,
11583 const clim_t *clim,
11584 met_t *met) {
11585
11586 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
11587 th2[200], z[EP], z2[200];
11588
11589 /* Set timer... */
11590 SELECT_TIMER("READ_MET_TROPO", "METPROC");
11591 LOG(2, "Calculate tropopause...");
11592
11593 /* Get altitude and pressure profiles... */
11594#pragma omp parallel for default(shared)
11595 for (int iz = 0; iz < met->np; iz++)
11596 z[iz] = Z(met->p[iz]);
11597#pragma omp parallel for default(shared)
11598 for (int iz = 0; iz <= 190; iz++) {
11599 z2[iz] = 4.5 + 0.1 * iz;
11600 p2[iz] = P(z2[iz]);
11601 }
11602
11603 /* Do not calculate tropopause... */
11604 if (ctl->met_tropo == 0)
11605#pragma omp parallel for default(shared) collapse(2)
11606 for (int ix = 0; ix < met->nx; ix++)
11607 for (int iy = 0; iy < met->ny; iy++)
11608 met->pt[ix][iy] = NAN;
11609
11610 /* Use tropopause climatology... */
11611 else if (ctl->met_tropo == 1) {
11612 if (met->coord_type != 0)
11613 ERRMSG("Only lat/lon grid supported");
11614#pragma omp parallel for default(shared) collapse(2)
11615 for (int ix = 0; ix < met->nx; ix++)
11616 for (int iy = 0; iy < met->ny; iy++)
11617 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
11618 }
11619
11620 /* Use cold point... */
11621 else if (ctl->met_tropo == 2) {
11622
11623 /* Loop over grid points... */
11624#pragma omp parallel for default(shared) private(t,t2) collapse(2)
11625 for (int ix = 0; ix < met->nx; ix++)
11626 for (int iy = 0; iy < met->ny; iy++) {
11627
11628 /* Interpolate temperature profile... */
11629 for (int iz = 0; iz < met->np; iz++)
11630 t[iz] = met->t[ix][iy][iz];
11631 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
11632
11633 /* Find minimum... */
11634 int iz = (int) gsl_stats_min_index(t2, 1, 171);
11635 if (iz > 0 && iz < 170)
11636 met->pt[ix][iy] = (float) p2[iz];
11637 else
11638 met->pt[ix][iy] = NAN;
11639 }
11640 }
11641
11642 /* Use WMO definition... */
11643 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
11644
11645 /* Loop over grid points... */
11646#pragma omp parallel for default(shared) private(t,t2) collapse(2)
11647 for (int ix = 0; ix < met->nx; ix++)
11648 for (int iy = 0; iy < met->ny; iy++) {
11649
11650 /* Interpolate temperature profile... */
11651 int iz;
11652 for (iz = 0; iz < met->np; iz++)
11653 t[iz] = met->t[ix][iy][iz];
11654 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
11655
11656 /* Find 1st tropopause... */
11657 met->pt[ix][iy] = NAN;
11658 for (iz = 0; iz <= 170; iz++) {
11659 int found = 1;
11660 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
11661 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
11662 found = 0;
11663 break;
11664 }
11665 if (found) {
11666 if (iz > 0 && iz < 170)
11667 met->pt[ix][iy] = (float) p2[iz];
11668 break;
11669 }
11670 }
11671
11672 /* Find 2nd tropopause... */
11673 if (ctl->met_tropo == 4) {
11674 met->pt[ix][iy] = NAN;
11675 for (; iz <= 170; iz++) {
11676 int found = 1;
11677 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
11678 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
11679 found = 0;
11680 break;
11681 }
11682 if (found)
11683 break;
11684 }
11685 for (; iz <= 170; iz++) {
11686 int found = 1;
11687 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
11688 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
11689 found = 0;
11690 break;
11691 }
11692 if (found) {
11693 if (iz > 0 && iz < 170)
11694 met->pt[ix][iy] = (float) p2[iz];
11695 break;
11696 }
11697 }
11698 }
11699 }
11700 }
11701
11702 /* Use dynamical tropopause... */
11703 else if (ctl->met_tropo == 5) {
11704
11705 /* Loop over grid points... */
11706#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
11707 for (int ix = 0; ix < met->nx; ix++)
11708 for (int iy = 0; iy < met->ny; iy++) {
11709
11710 /* Interpolate potential vorticity profile... */
11711 for (int iz = 0; iz < met->np; iz++)
11712 pv[iz] = met->pv[ix][iy][iz];
11713 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
11714
11715 /* Interpolate potential temperature profile... */
11716 for (int iz = 0; iz < met->np; iz++)
11717 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
11718 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
11719
11720 /* Find dynamical tropopause... */
11721 met->pt[ix][iy] = NAN;
11722 for (int iz = 0; iz <= 170; iz++)
11723 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
11724 || th2[iz] >= ctl->met_tropo_theta) {
11725 if (iz > 0 && iz < 170)
11726 met->pt[ix][iy] = (float) p2[iz];
11727 break;
11728 }
11729 }
11730 }
11731
11732 else
11733 ERRMSG("Cannot calculate tropopause!");
11734
11735 /* Interpolate temperature, geopotential height, and water vapor... */
11736#pragma omp parallel for default(shared) collapse(2)
11737 for (int ix = 0; ix < met->nx; ix++)
11738 for (int iy = 0; iy < met->ny; iy++) {
11739 double h2ot, tt, zt;
11741 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
11742 met->lat[iy], &tt, ci, cw, 1);
11743 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
11744 met->lat[iy], &zt, ci, cw, 0);
11745 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
11746 met->lat[iy], &h2ot, ci, cw, 0);
11747 met->tt[ix][iy] = (float) tt;
11748 met->zt[ix][iy] = (float) zt;
11749 met->h2ot[ix][iy] = (float) h2ot;
11750 }
11751}
11752
11753/*****************************************************************************/
11754
11756 const char *filename,
11757 const ctl_t *ctl,
11758 double *rt,
11759 double *rz,
11760 double *rlon,
11761 double *rlat,
11762 double *robs,
11763 int *nobs) {
11764
11765 /* Write info... */
11766 LOG(1, "Read observation data: %s", filename);
11767
11768 /* Read data... */
11769 if (ctl->obs_type == 0)
11770 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
11771 else if (ctl->obs_type == 1)
11772 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
11773 else
11774 ERRMSG("Set OBS_TYPE to 0 or 1!");
11775
11776 /* Check time... */
11777 for (int i = 1; i < *nobs; i++)
11778 if (rt[i] < rt[i - 1])
11779 ERRMSG("Time must be ascending!");
11780
11781 /* Write info... */
11782 int n = *nobs;
11783 double mini, maxi;
11784 LOG(2, "Number of observations: %d", *nobs);
11785 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
11786 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
11787 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
11788 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
11789 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
11790 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
11791 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
11792 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
11793 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
11794 LOG(2, "Observation range: %g ... %g", mini, maxi);
11795}
11796
11797/*****************************************************************************/
11798
11800 const char *filename,
11801 double *rt,
11802 double *rz,
11803 double *rlon,
11804 double *rlat,
11805 double *robs,
11806 int *nobs) {
11807
11808 /* Open observation data file... */
11809 FILE *in;
11810 if (!(in = fopen(filename, "r")))
11811 ERRMSG("Cannot open file!");
11812
11813 /* Read observations... */
11814 char line[LEN];
11815 while (fgets(line, LEN, in))
11816 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
11817 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
11818 if ((++(*nobs)) >= NOBS)
11819 ERRMSG("Too many observations!");
11820
11821 /* Close observation data file... */
11822 fclose(in);
11823}
11824
11825/*****************************************************************************/
11826
11828 const char *filename,
11829 double *rt,
11830 double *rz,
11831 double *rlon,
11832 double *rlat,
11833 double *robs,
11834 int *nobs) {
11835
11836 int ncid, varid;
11837
11838 /* Open netCDF file... */
11839 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
11840 ERRMSG("Cannot open file!");
11841
11842 /* Read the observations from the NetCDF file... */
11843 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
11844 NC_GET_DOUBLE("time", rt, 1);
11845 NC_GET_DOUBLE("alt", rz, 1);
11846 NC_GET_DOUBLE("lon", rlon, 1);
11847 NC_GET_DOUBLE("lat", rlat, 1);
11848 NC_GET_DOUBLE("obs", robs, 1);
11849
11850 /* Close file... */
11851 NC(nc_close(ncid));
11852}
11853
11854/*****************************************************************************/
11855
11857 const char *filename,
11858 int argc,
11859 char *argv[],
11860 const char *varname,
11861 const int arridx,
11862 const char *defvalue,
11863 char *value) {
11864
11865 FILE *in = NULL;
11866
11867 char fullname1[LEN], fullname2[LEN], rval[LEN];
11868
11869 int contain = 0, i;
11870
11871 /* Open file... */
11872 if (filename[strlen(filename) - 1] != '-')
11873 if (!(in = fopen(filename, "r")))
11874 ERRMSG("Cannot open file!");
11875
11876 /* Set full variable name... */
11877 if (arridx >= 0) {
11878 sprintf(fullname1, "%s[%d]", varname, arridx);
11879 sprintf(fullname2, "%s[*]", varname);
11880 } else {
11881 sprintf(fullname1, "%s", varname);
11882 sprintf(fullname2, "%s", varname);
11883 }
11884
11885 /* Read data... */
11886 if (in != NULL) {
11887 char dummy[LEN], line[LEN], rvarname[LEN];
11888 while (fgets(line, LEN, in)) {
11889 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
11890 if (strcasecmp(rvarname, fullname1) == 0 ||
11891 strcasecmp(rvarname, fullname2) == 0) {
11892 contain = 1;
11893 break;
11894 }
11895 }
11896 }
11897 for (i = 1; i < argc - 1; i++)
11898 if (strcasecmp(argv[i], fullname1) == 0 ||
11899 strcasecmp(argv[i], fullname2) == 0) {
11900 sprintf(rval, "%s", argv[i + 1]);
11901 contain = 1;
11902 break;
11903 }
11904
11905 /* Close file... */
11906 if (in != NULL)
11907 fclose(in);
11908
11909 /* Check for missing variables... */
11910 if (!contain) {
11911 if (strlen(defvalue) > 0)
11912 sprintf(rval, "%s", defvalue);
11913 else
11914 ERRMSG("Missing variable %s!\n", fullname1);
11915 }
11916
11917 /* Write info... */
11918 LOG(1, "%s = %s", fullname1, rval);
11919
11920 /* Return values... */
11921 if (value != NULL)
11922 sprintf(value, "%s", rval);
11923 return atof(rval);
11924}
11925
11926/*****************************************************************************/
11927
11928double sedi(
11929 const double p,
11930 const double T,
11931 const double rp,
11932 const double rhop) {
11933
11934 /* Convert particle radius from microns to m... */
11935 const double rp_help = rp * 1e-6;
11936
11937 /* Density of dry air [kg / m^3]... */
11938 const double rho = RHO(p, T);
11939
11940 /* Dynamic viscosity of air [kg / (m s)]... */
11941 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
11942
11943 /* Thermal velocity of an air molecule [m / s]... */
11944 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
11945
11946 /* Mean free path of an air molecule [m]... */
11947 const double lambda = 2. * eta / (rho * v);
11948
11949 /* Knudsen number for air (dimensionless)... */
11950 const double K = lambda / rp_help;
11951
11952 /* Cunningham slip-flow correction (dimensionless)... */
11953 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
11954
11955 /* Sedimentation velocity [m / s]... */
11956 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
11957}
11958
11959/*****************************************************************************/
11960
11962 const double *x,
11963 const double *y,
11964 const int n,
11965 const double *x2,
11966 double *y2,
11967 const int n2,
11968 const int method) {
11969
11970 /* Cubic spline interpolation... */
11971 if (method == 1) {
11972
11973 /* Allocate... */
11974 gsl_interp_accel *acc = gsl_interp_accel_alloc();
11975 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
11976
11977 /* Interpolate profile... */
11978 gsl_spline_init(s, x, y, (size_t) n);
11979 for (int i = 0; i < n2; i++)
11980 if (x2[i] <= x[0])
11981 y2[i] = y[0];
11982 else if (x2[i] >= x[n - 1])
11983 y2[i] = y[n - 1];
11984 else
11985 y2[i] = gsl_spline_eval(s, x2[i], acc);
11986
11987 /* Free... */
11988 gsl_spline_free(s);
11989 gsl_interp_accel_free(acc);
11990 }
11991
11992 /* Linear interpolation... */
11993 else {
11994 for (int i = 0; i < n2; i++)
11995 if (x2[i] <= x[0])
11996 y2[i] = y[0];
11997 else if (x2[i] >= x[n - 1])
11998 y2[i] = y[n - 1];
11999 else {
12000 const int idx = locate_irr(x, n, x2[i]);
12001 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
12002 }
12003 }
12004}
12005
12006/*****************************************************************************/
12007
12009 const float *data,
12010 const int n) {
12011
12012 if (n <= 0)
12013 return 0;
12014
12015 float mean = 0, var = 0;
12016
12017 for (int i = 0; i < n; ++i) {
12018 mean += data[i];
12019 var += SQR(data[i]);
12020 }
12021
12022 var = var / (float) n - SQR(mean / (float) n);
12023
12024 return (var > 0 ? sqrtf(var) : 0);
12025}
12026
12027/*****************************************************************************/
12028
12030 const int year,
12031 const int mon,
12032 const int day,
12033 const int hour,
12034 const int min,
12035 const int sec,
12036 const double remain,
12037 double *jsec) {
12038
12039 struct tm t0, t1;
12040
12041 t0.tm_year = 100;
12042 t0.tm_mon = 0;
12043 t0.tm_mday = 1;
12044 t0.tm_hour = 0;
12045 t0.tm_min = 0;
12046 t0.tm_sec = 0;
12047
12048 t1.tm_year = year - 1900;
12049 t1.tm_mon = mon - 1;
12050 t1.tm_mday = day;
12051 t1.tm_hour = hour;
12052 t1.tm_min = min;
12053 t1.tm_sec = sec;
12054
12055 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
12056}
12057
12058/*****************************************************************************/
12059
12061 const char *name,
12062 const char *group,
12063 const int output) {
12064
12065 static char names[NTIMER][100], groups[NTIMER][100];
12066
12067 static double rt_name[NTIMER], rt_group[NTIMER],
12068 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
12069
12070 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
12071
12072 /* Get time... */
12073 t1 = omp_get_wtime();
12074 dt = t1 - t0;
12075
12076 /* Add elapsed time to current timers... */
12077 if (iname >= 0) {
12078 rt_name[iname] += dt;
12079 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
12080 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
12081 ct_name[iname]++;
12082 }
12083 if (igroup >= 0)
12084 rt_group[igroup] += t1 - t0;
12085
12086 /* Report timers... */
12087 if (output) {
12088 for (int i = 0; i < nname; i++)
12089 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
12090 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
12091 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
12092 for (int i = 0; i < ngroup; i++)
12093 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
12094 double total = 0.0;
12095 for (int i = 0; i < nname; i++)
12096 total += rt_name[i];
12097 LOG(1, "TIMER_TOTAL = %.3f s", total);
12098 }
12099
12100 /* Identify IDs of next timer... */
12101 for (iname = 0; iname < nname; iname++)
12102 if (strcasecmp(name, names[iname]) == 0)
12103 break;
12104 for (igroup = 0; igroup < ngroup; igroup++)
12105 if (strcasecmp(group, groups[igroup]) == 0)
12106 break;
12107
12108 /* Check whether this is a new timer... */
12109 if (iname >= nname) {
12110 sprintf(names[iname], "%s", name);
12111 if ((++nname) >= NTIMER)
12112 ERRMSG("Too many timers!");
12113 }
12114
12115 /* Check whether this is a new group... */
12116 if (igroup >= ngroup) {
12117 sprintf(groups[igroup], "%s", group);
12118 if ((++ngroup) >= NTIMER)
12119 ERRMSG("Too many groups!");
12120 }
12121
12122 /* Save starting time... */
12123 t0 = t1;
12124}
12125
12126/*****************************************************************************/
12127
12129 const char *filename,
12130 const int offset,
12131 const int with_seconds) {
12132
12133 char tstr[10];
12134
12135 double t;
12136
12137 /* Get time from filename... */
12138 int len = (int) strlen(filename);
12139 sprintf(tstr, "%.4s", &filename[len - offset]);
12140 int year = atoi(tstr);
12141 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
12142 int mon = atoi(tstr);
12143 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
12144 int day = atoi(tstr);
12145 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
12146 int hour = atoi(tstr);
12147 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
12148 int min = atoi(tstr);
12149
12150 int sec = 0;
12151 if (with_seconds) {
12152 sprintf(tstr, "%.2s", &filename[len - offset + 17]);
12153 sec = atoi(tstr);
12154 }
12155
12156 /* Check time... */
12157 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
12158 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
12159 ERRMSG("Cannot read time from filename!");
12160
12161 /* Convert time to Julian seconds... */
12162 time2jsec(year, mon, day, hour, min, sec, 0.0, &t);
12163
12164 /* Return time... */
12165 return t;
12166}
12167
12168/*****************************************************************************/
12169
12171 const ctl_t *ctl,
12172 const clim_t *clim,
12173 const atm_t *atm,
12174 const int ip) {
12175
12176 /* Get tropopause pressure... */
12177 const double pt = clim_tropo(clim, atm->time[ip],
12178 ctl->met_coord_type ==
12179 0 ? atm->lat[ip] : ctl->met_utm_ref_lat);
12180
12181 /* Get pressure range... */
12182 const double p1 = pt * 0.866877899;
12183 const double p0 = pt / 0.866877899;
12184
12185 /* Get weighting factor... */
12186 if (atm->p[ip] > p0)
12187 return 1;
12188 else if (atm->p[ip] < p1)
12189 return 0;
12190 else
12191 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
12192}
12193
12194/*****************************************************************************/
12195
12197 const char *filename,
12198 const ctl_t *ctl,
12199 const atm_t *atm,
12200 const double t) {
12201
12202 FILE *out;
12203
12204 /* Set time interval for output... */
12205 const double t0 = t - 0.5 * ctl->dt_mod;
12206 const double t1 = t + 0.5 * ctl->dt_mod;
12207
12208 /* Check if gnuplot output is requested... */
12209 if (ctl->atm_gpfile[0] != '-') {
12210
12211 /* Create gnuplot pipe... */
12212 if (!(out = popen("gnuplot", "w")))
12213 ERRMSG("Cannot create pipe to gnuplot!");
12214
12215 /* Set plot filename... */
12216 fprintf(out, "set out \"%s.png\"\n", filename);
12217
12218 /* Set time string... */
12219 double r;
12220 int year, mon, day, hour, min, sec;
12221 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12222 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12223 year, mon, day, hour, min);
12224
12225 /* Dump gnuplot file to pipe... */
12226 FILE *in;
12227 if (!(in = fopen(ctl->atm_gpfile, "r")))
12228 ERRMSG("Cannot open file!");
12229 char line[LEN];
12230 while (fgets(line, LEN, in))
12231 fprintf(out, "%s", line);
12232 fclose(in);
12233 }
12234
12235 else {
12236
12237 /* Create file... */
12238 if (!(out = fopen(filename, "w")))
12239 ERRMSG("Cannot create file!");
12240 }
12241
12242 /* Write header... */
12243
12244 if (ctl->met_coord_type == 0) {
12245 fprintf(out,
12246 "# $1 = time [s]\n"
12247 "# $2 = altitude [km]\n"
12248 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12249 } else {
12250 fprintf(out,
12251 "# $1 = time [s]\n"
12252 "# $2 = altitude [km]\n" "# $3 = x [m]\n" "# $4 = y [m]\n");
12253 }
12254
12255 for (int iq = 0; iq < ctl->nq; iq++)
12256 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
12257 ctl->qnt_unit[iq]);
12258 fprintf(out, "\n");
12259
12260 /* Write data... */
12261 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
12262
12263 /* Check time... */
12264 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12265 continue;
12266
12267 /* Write output... */
12268 if (ctl->met_coord_type == 0) {
12269 fprintf(out, "%.2f %g %g %g",
12270 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]
12271 );
12272 } else {
12273 fprintf(out, "%.2f %g %.2f %.2f",
12274 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]
12275 );
12276 }
12277
12278 for (int iq = 0; iq < ctl->nq; iq++) {
12279 fprintf(out, " ");
12280 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
12281 fprintf(out, ctl->qnt_format[iq], NAN);
12282 else
12283 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
12284 }
12285 fprintf(out, "\n");
12286 }
12287
12288 /* Close file... */
12289 fclose(out);
12290}
12291
12292/*****************************************************************************/
12293
12295 const char *filename,
12296 const ctl_t *ctl,
12297 const atm_t *atm) {
12298
12299 FILE *out;
12300
12301 /* Create file... */
12302 if (!(out = fopen(filename, "w")))
12303 ERRMSG("Cannot create file!");
12304
12305 /* Write version of binary data... */
12306 int version = 100;
12307 FWRITE(&version, int,
12308 1,
12309 out);
12310
12311 /* Write data... */
12312 FWRITE(&atm->np, int,
12313 1,
12314 out);
12315 FWRITE(atm->time, double,
12316 (size_t) atm->np,
12317 out);
12318 FWRITE(atm->p, double,
12319 (size_t) atm->np,
12320 out);
12321 FWRITE(atm->lon, double,
12322 (size_t) atm->np,
12323 out);
12324 FWRITE(atm->lat, double,
12325 (size_t) atm->np,
12326 out);
12327 for (int iq = 0; iq < ctl->nq; iq++)
12328 FWRITE(atm->q[iq], double,
12329 (size_t) atm->np,
12330 out);
12331
12332 /* Write final flag... */
12333 int final = 999;
12334 FWRITE(&final, int,
12335 1,
12336 out);
12337
12338 /* Close file... */
12339 fclose(out);
12340}
12341
12342/*****************************************************************************/
12343
12345 const char *filename,
12346 const ctl_t *ctl,
12347 const atm_t *atm) {
12348
12349 if (ctl->met_coord_type != 0)
12350 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
12351
12352 int tid, pid, ncid, varid;
12353 size_t start[2], count[2];
12354
12355 /* Create file... */
12356 NC(nc_create(filename, NC_NETCDF4, &ncid));
12357
12358 /* Define dimensions... */
12359 NC(nc_def_dim(ncid, "time", 1, &tid));
12360 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
12361
12362 /* Define variables and their attributes... */
12363 int dim_ids[2] = { tid, pid };
12364 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
12365 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12366 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
12367 ctl->atm_nc_level, 0);
12368 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
12369 ctl->atm_nc_level, 0);
12370 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
12371 ctl->atm_nc_level, 0);
12372 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
12373 for (int iq = 0; iq < ctl->nq; iq++)
12374 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
12375 ctl->qnt_name[iq], ctl->qnt_unit[iq],
12376 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12377
12378 /* Define global attributes... */
12379 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
12380 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
12381
12382 /* End definitions... */
12383 NC(nc_enddef(ncid));
12384
12385 /* Write data... */
12386 NC_PUT_DOUBLE("time", atm->time, 0);
12387 NC_PUT_DOUBLE("LAT", atm->lat, 0);
12388 NC_PUT_DOUBLE("LON", atm->lon, 0);
12389 NC_PUT_DOUBLE("PRESS", atm->p, 0);
12390 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
12391 for (int iq = 0; iq < ctl->nq; iq++)
12392 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
12393
12394 /* Close file... */
12395 NC(nc_close(ncid));
12396}
12397
12398/*****************************************************************************/
12399
12401 const char *dirname,
12402 const ctl_t *ctl,
12403 const atm_t *atm,
12404 const double t) {
12405
12406 if (ctl->met_coord_type != 0)
12407 ERRMSG("CLaMS atmospheric files support only lat/lon grids");
12408
12409 /* Global Counter... */
12410 static size_t out_cnt = 0;
12411
12412 double r, r_start, r_stop;
12413 int year, mon, day, hour, min, sec;
12414 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
12415 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
12416 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
12417
12418 int ncid, varid, tid, pid, cid;
12419 int dim_ids[2];
12420
12421 /* time, nparc */
12422 size_t start[2];
12423 size_t count[2];
12424
12425 /* Determine start and stop times of calculation... */
12426 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12427 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
12428 &min_start, &sec_start, &r_start);
12429 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
12430 &min_stop, &sec_stop, &r_stop);
12431
12432 sprintf(filename_out,
12433 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
12434 year_start % 100, mon_start, day_start, hour_start,
12435 year_stop % 100, mon_stop, day_stop, hour_stop);
12436 LOG(1, "Write traj file: %s", filename_out);
12437
12438 /* Define hyperslap for the traj_file... */
12439 start[0] = out_cnt;
12440 start[1] = 0;
12441 count[0] = 1;
12442 count[1] = (size_t) atm->np;
12443
12444 /* Create the file at the first timestep... */
12445 if (out_cnt == 0) {
12446
12447 /* Create file... */
12448 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
12449
12450 /* Define dimensions... */
12451 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
12452 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
12453 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
12454 dim_ids[0] = tid;
12455 dim_ids[1] = pid;
12456
12457 /* Define variables and their attributes... */
12458 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
12459 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12460 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
12461 ctl->atm_nc_level, 0);
12462 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
12463 ctl->atm_nc_level, 0);
12464 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
12465 ctl->atm_nc_level, 0);
12466 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
12467 ctl->atm_nc_level, 0);
12468 for (int iq = 0; iq < ctl->nq; iq++)
12469 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
12470 ctl->qnt_name[iq], ctl->qnt_unit[iq],
12471 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12472
12473 /* Define global attributes... */
12474 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
12475 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
12476
12477 /* End definitions... */
12478 NC(nc_enddef(ncid));
12479 NC(nc_close(ncid));
12480 }
12481
12482 /* Increment global counter to change hyperslap... */
12483 out_cnt++;
12484
12485 /* Open file... */
12486 NC(nc_open(filename_out, NC_WRITE, &ncid));
12487
12488 /* Write data... */
12489 NC_PUT_DOUBLE("time", atm->time, 1);
12490 NC_PUT_DOUBLE("LAT", atm->lat, 1);
12491 NC_PUT_DOUBLE("LON", atm->lon, 1);
12492 NC_PUT_DOUBLE("PRESS", atm->p, 1);
12493 if (ctl->advect_vert_coord == 1) {
12494 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
12495 } else if (ctl->qnt_zeta >= 0) {
12496 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
12497 }
12498 for (int iq = 0; iq < ctl->nq; iq++)
12499 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
12500
12501 /* Close file... */
12502 NC(nc_close(ncid));
12503
12504 /* At the last time step create the init_fix_YYYYMMDDHH file... */
12505 if ((year == year_stop) && (mon == mon_stop)
12506 && (day == day_stop) && (hour == hour_stop)) {
12507
12508 /* Set filename... */
12509 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
12510 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
12511 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
12512 LOG(1, "Write init file: %s", filename_init);
12513
12514 /* Create file... */
12515 NC(nc_create(filename_init, NC_NETCDF4, &ncid));
12516
12517 /* Define dimensions... */
12518 NC(nc_def_dim(ncid, "time", 1, &tid));
12519 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
12520 dim_ids[0] = tid;
12521 dim_ids[1] = pid;
12522
12523 /* Define variables and their attributes... */
12524 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
12525 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12526 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
12527 ctl->atm_nc_level, 0);
12528 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
12529 ctl->atm_nc_level, 0);
12530 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
12531 ctl->atm_nc_level, 0);
12532 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
12533 for (int iq = 0; iq < ctl->nq; iq++)
12534 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
12535 ctl->qnt_name[iq], ctl->qnt_unit[iq],
12536 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12537
12538 /* Define global attributes... */
12539 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
12540 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
12541
12542 /* End definitions... */
12543 NC(nc_enddef(ncid));
12544
12545 /* Write data... */
12546 NC_PUT_DOUBLE("time", atm->time, 0);
12547 NC_PUT_DOUBLE("LAT", atm->lat, 0);
12548 NC_PUT_DOUBLE("LON", atm->lon, 0);
12549 NC_PUT_DOUBLE("PRESS", atm->p, 0);
12550 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
12551 for (int iq = 0; iq < ctl->nq; iq++)
12552 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
12553
12554 /* Close file... */
12555 NC(nc_close(ncid));
12556 }
12557}
12558
12559/*****************************************************************************/
12560
12562 const char *filename,
12563 const ctl_t *ctl,
12564 const atm_t *atm) {
12565
12566 int ncid, obsid, varid;
12567
12568 size_t start[2], count[2];
12569
12570 /* Create file... */
12571 NC(nc_create(filename, NC_NETCDF4, &ncid));
12572
12573 /* Define dimensions... */
12574 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
12575
12576 /* Define variables and their attributes... */
12577 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
12578 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
12579 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
12580 ctl->atm_nc_level, 0);
12581 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
12582 ctl->atm_nc_level, 0);
12583 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
12584 ctl->atm_nc_level, 0);
12585 for (int iq = 0; iq < ctl->nq; iq++)
12586 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
12587 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
12588 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
12589
12590 /* Define global attributes... */
12591 NC_PUT_ATT_GLOBAL("featureType", "point");
12592
12593 /* End definitions... */
12594 NC(nc_enddef(ncid));
12595
12596 /* Write data... */
12597 NC_PUT_DOUBLE("time", atm->time, 0);
12598 NC_PUT_DOUBLE("press", atm->p, 0);
12599 NC_PUT_DOUBLE("lon", atm->lon, 0);
12600 NC_PUT_DOUBLE("lat", atm->lat, 0);
12601 for (int iq = 0; iq < ctl->nq; iq++)
12602 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
12603
12604 /* Close file... */
12605 NC(nc_close(ncid));
12606}
12607
12608/*****************************************************************************/
12609
12611 const char *filename,
12612 const ctl_t *ctl,
12613 const atm_t *atm,
12614 const double t) {
12615
12616 if (ctl->met_coord_type != 0)
12617 ERRMSG("Only lat/lon grid supported");
12618
12619 static FILE *out;
12620
12621 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
12622 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
12623
12624 static int *obscount, nobs, nk;
12625
12626 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
12627
12628 const int ensemble = (ctl->nens > 0);
12629
12630 /* Set timer */
12631 SELECT_TIMER("WRITE_CSI", "OUTPUT");
12632
12633 /* Check quantities... */
12634 if (ctl->qnt_m < 0)
12635 ERRMSG("Need quantity mass!");
12636 if (ensemble) {
12637 if (ctl->qnt_ens < 0)
12638 ERRMSG("Missing ensemble IDs!");
12639 if (ctl->nens > NENS)
12640 ERRMSG("Too many ensembles!");
12641 }
12642
12643 /* Init... */
12644 if (t == ctl->t_start) {
12645
12646 /* Allocate.. */
12647 ALLOC(area, double,
12648 ctl->csi_ny);
12649 ALLOC(rt, double,
12650 NOBS);
12651 ALLOC(rz, double,
12652 NOBS);
12653 ALLOC(rlon, double,
12654 NOBS);
12655 ALLOC(rlat, double,
12656 NOBS);
12657 ALLOC(robs, double,
12658 NOBS);
12659
12660 /* Read observation data... */
12661 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12662
12663 /* Read kernel data... */
12664 if (ctl->csi_kernel[0] != '-')
12665 read_kernel(ctl->csi_kernel, kz, kw, &nk);
12666
12667 /* Create new file... */
12668 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
12669 if (!(out = fopen(filename, "w")))
12670 ERRMSG("Cannot create file!");
12671
12672 /* Write header... */
12673 fprintf(out,
12674 "# $1 = time [s]\n"
12675 "# $2 = ensemble ID\n"
12676 "# $3 = number of hits (cx)\n"
12677 "# $4 = number of misses (cy)\n"
12678 "# $5 = number of false alarms (cz)\n"
12679 "# $6 = number of observations (cx + cy)\n"
12680 "# $7 = number of forecasts (cx + cz)\n"
12681 "# $8 = bias (%%)\n"
12682 "# $9 = POD (%%)\n"
12683 "# $10 = FAR (%%)\n"
12684 "# $11 = CSI (%%)\n"
12685 "# $12 = hits by random chance\n"
12686 "# $13 = ETS (%%)\n"
12687 "# $14 = Pearson R\n"
12688 "# $15 = Spearman R\n"
12689 "# $16 = mean error [kg/m²]\n"
12690 "# $17 = RMSE [kg/m²]\n"
12691 "# $18 = MAE [kg/m²]\n"
12692 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
12693
12694 /* Set grid box size... */
12695 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
12696 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
12697 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
12698
12699 /* Set horizontal coordinates... */
12700 for (int iy = 0; iy < ctl->csi_ny; iy++) {
12701 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
12702 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
12703 }
12704 }
12705
12706 /* Set time interval... */
12707 const double t0 = t - 0.5 * ctl->dt_mod;
12708 const double t1 = t + 0.5 * ctl->dt_mod;
12709
12710 /* Allocate... */
12711 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
12712 ALLOC(modmean, double,
12713 (ensemble ? ctl->nens : 1) * grid_size);
12714 ALLOC(obsmean, double,
12715 grid_size);
12716 ALLOC(obscount, int,
12717 grid_size);
12718 ALLOC(obsstd, double,
12719 grid_size);
12720
12721 /* Init... */
12722 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
12723 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
12724
12725 /* Loop over observations... */
12726 for (int i = 0; i < nobs; i++) {
12727 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
12728 continue;
12729
12730 /* Calculate indices... */
12731 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
12732 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
12733 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
12734 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
12735 || iz >= ctl->csi_nz)
12736 continue;
12737
12738 /* Get mean observation index... */
12739 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
12740 obsmean[idx] += robs[i];
12741 obsstd[idx] += SQR(robs[i]);
12742 obscount[idx]++;
12743 }
12744
12745 /* Analyze model data... */
12746 for (int ip = 0; ip < atm->np; ip++) {
12747
12748 /* Check time... */
12749 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12750 continue;
12751
12752 /* Get ensemble ID... */
12753 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
12754 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
12755 ERRMSG("Ensemble ID out of range!");
12756
12757 /* Get indices... */
12758 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
12759 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
12760 const int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
12761 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
12762 || iz >= ctl->csi_nz)
12763 continue;
12764
12765 /* Get total mass in grid cell... */
12766 const int idx =
12767 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
12768 modmean[idx] +=
12769 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
12770 }
12771 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
12772 /* Analyze all grid cells... */
12773 for (int ix = 0; ix < ctl->csi_nx; ix++)
12774 for (int iy = 0; iy < ctl->csi_ny; iy++)
12775 for (int iz = 0; iz < ctl->csi_nz; iz++) {
12776
12777 /* Calculate mean observation index... */
12778 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
12779 if (e == 0)
12780 if (obscount[idx]) {
12781 obsmean[idx] /= obscount[idx];
12782 obsstd[idx] =
12783 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
12784 }
12785
12786 /* Calculate model mean per ensemble... */
12787 const int midx = e * grid_size + idx;
12788 if (modmean[midx] > 0)
12789 modmean[midx] /= (1e6 * area[iy]);
12790
12791 /* Check number of observations... */
12792 if (obscount[idx]) {
12793
12794 /* Calculate CSI... */
12795 ct[e]++;
12796 if (obsmean[idx] >= ctl->csi_obsmin
12797 && modmean[midx] >= ctl->csi_modmin)
12798 cx[e]++;
12799 else if (obsmean[idx] >= ctl->csi_obsmin)
12800 cy[e]++;
12801 else if (modmean[midx] >= ctl->csi_modmin)
12802 cz[e]++;
12803
12804 /* Save data for other verification statistics... */
12805 if (obsmean[idx] >= ctl->csi_obsmin
12806 || modmean[midx] >= ctl->csi_modmin) {
12807 x[n[e]] = modmean[midx];
12808 y[n[e]] = obsmean[idx];
12809 if (modmean[midx] >= ctl->csi_modmin)
12810 obsstdn[n[e]] = obsstd[idx];
12811 if ((++n[e]) >= NCSI)
12812 ERRMSG("Too many points for statistics!");
12813 }
12814 }
12815 }
12816 /* Write output... */
12817 if (fmod(t, ctl->csi_dt_out) == 0) {
12818
12819 if (n[e] == 0)
12820 continue;
12821
12822 /* Calculate verification statistics
12823 (https://www.cawcr.gov.au/projects/verification/) ... */
12824 static double work[2 * NCSI], work2[2 * NCSI];
12825 const int n_obs = cx[e] + cy[e];
12826 const int n_for = cx[e] + cz[e];
12827 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
12828 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
12829 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
12830 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
12831 const double csi =
12832 (cx[e] + cy[e] + cz[e] >
12833 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
12834 const double ets =
12835 (cx[e] + cy[e] + cz[e] - cx_rd >
12836 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
12837 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
12838 const double rho_s =
12839 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
12840 for (int i = 0; i < n[e]; i++) {
12841 work[i] = x[i] - y[i];
12842 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
12843 }
12844 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
12845 const double rmse =
12846 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
12847 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
12848 const double loglikelihood =
12849 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
12850
12851 /* Write... */
12852 fprintf(out,
12853 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
12854 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
12855 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
12856 loglikelihood, n[e]);
12857
12858 /* Set counters to zero... */
12859 for (int i = 0; i < n[e]; i++)
12860 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
12861 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
12862 }
12863 }
12864 /* Free... */
12865 free(modmean);
12866 free(obsmean);
12867 free(obscount);
12868 free(obsstd);
12869
12870 /* Finalize... */
12871 if (t == ctl->t_stop) {
12872
12873 /* Close output file... */
12874 fclose(out);
12875
12876 /* Free... */
12877 free(area);
12878 free(rt);
12879 free(rz);
12880 free(rlon);
12881 free(rlat);
12882 free(robs);
12883 }
12884}
12885
12886/*****************************************************************************/
12887
12889 const char *filename,
12890 const ctl_t *ctl,
12891 const atm_t *atm,
12892 const double t) {
12893
12894 if (ctl->met_coord_type != 0)
12895 ERRMSG("Only lat/lon grid supported");
12896
12897 static FILE *out;
12898
12899 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
12900 x[3], zm[NENS];
12901
12902 static int n[NENS];
12903
12904 /* Set timer... */
12905 SELECT_TIMER("WRITE_ENS", "OUTPUT");
12906
12907 /* Check quantities... */
12908 if (ctl->qnt_ens < 0)
12909 ERRMSG("Missing ensemble IDs!");
12910
12911 /* Set time interval... */
12912 const double t0 = t - 0.5 * ctl->dt_mod;
12913 const double t1 = t + 0.5 * ctl->dt_mod;
12914
12915 /* Init... */
12916 for (int i = 0; i < NENS; i++) {
12917 for (int iq = 0; iq < ctl->nq; iq++)
12918 qm[iq][i] = qs[iq][i] = 0;
12919 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
12920 n[i] = 0;
12921 }
12922
12923 /* Loop over air parcels... */
12924 for (int ip = 0; ip < atm->np; ip++) {
12925
12926 /* Check time... */
12927 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12928 continue;
12929
12930 /* Check ensemble ID... */
12931 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
12932 ERRMSG("Ensemble ID is out of range!");
12933
12934 /* Get means... */
12935 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
12936 for (int iq = 0; iq < ctl->nq; iq++) {
12937 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
12938 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
12939 }
12940 xm[ctl->qnt_ens][0] += x[0];
12941 xm[ctl->qnt_ens][1] += x[1];
12942 xm[ctl->qnt_ens][2] += x[2];
12943 zm[ctl->qnt_ens] += Z(atm->p[ip]);
12944 n[ctl->qnt_ens]++;
12945 }
12946
12947 /* Create file... */
12948 LOG(1, "Write ensemble data: %s", filename);
12949 if (!(out = fopen(filename, "w")))
12950 ERRMSG("Cannot create file!");
12951
12952 /* Write header... */
12953 fprintf(out,
12954 "# $1 = time [s]\n"
12955 "# $2 = altitude [km]\n"
12956 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12957 for (int iq = 0; iq < ctl->nq; iq++)
12958 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
12959 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12960 for (int iq = 0; iq < ctl->nq; iq++)
12961 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
12962 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12963 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
12964
12965 /* Write data... */
12966 for (int i = 0; i < NENS; i++)
12967 if (n[i] > 0) {
12968 cart2geo(xm[i], &dummy, &lon, &lat);
12969 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
12970 for (int iq = 0; iq < ctl->nq; iq++) {
12971 fprintf(out, " ");
12972 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
12973 }
12974 for (int iq = 0; iq < ctl->nq; iq++) {
12975 fprintf(out, " ");
12976 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
12977 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
12978 }
12979 fprintf(out, " %d\n", n[i]);
12980 }
12981
12982 /* Close file... */
12983 fclose(out);
12984}
12985
12986/*****************************************************************************/
12987
12989 const char *filename,
12990 const ctl_t *ctl,
12991 met_t *met0,
12992 met_t *met1,
12993 const atm_t *atm,
12994 const double t) {
12995
12996 if (ctl->met_coord_type != 0)
12997 ERRMSG("Only lat/lon grid supported");
12998
12999 static double kz[EP], kw[EP];
13000
13001 static int nk;
13002
13003 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
13004
13005 int *ixs, *iys, *izs, *np;
13006
13007 /* Set timer... */
13008 SELECT_TIMER("WRITE_GRID", "OUTPUT");
13009
13010 /* Write info... */
13011 LOG(1, "Write grid data: %s", filename);
13012
13013 /* Init... */
13014 if (t == ctl->t_start) {
13015
13016 /* Read kernel data... */
13017 if (ctl->grid_kernel[0] != '-')
13018 read_kernel(ctl->grid_kernel, kz, kw, &nk);
13019 }
13020
13021 /* Allocate... */
13022 ALLOC(cd, double,
13023 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13024 for (int iq = 0; iq < ctl->nq; iq++) {
13025 ALLOC(mean[iq], double,
13026 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13027 ALLOC(sigma[iq], double,
13028 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13029 }
13030 ALLOC(vmr_impl, double,
13031 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13032 ALLOC(z, double,
13033 ctl->grid_nz);
13034 ALLOC(lon, double,
13035 ctl->grid_nx);
13036 ALLOC(lat, double,
13037 ctl->grid_ny);
13038 ALLOC(area, double,
13039 ctl->grid_ny);
13040 ALLOC(press, double,
13041 ctl->grid_nz);
13042 ALLOC(np, int,
13043 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13044 ALLOC(ixs, int,
13045 atm->np);
13046 ALLOC(iys, int,
13047 atm->np);
13048 ALLOC(izs, int,
13049 atm->np);
13050
13051 /* Set grid box size... */
13052 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
13053 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
13054 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
13055
13056 /* Set vertical coordinates... */
13057#pragma omp parallel for default(shared)
13058 for (int iz = 0; iz < ctl->grid_nz; iz++) {
13059 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
13060 press[iz] = P(z[iz]);
13061 }
13062
13063 /* Set horizontal coordinates... */
13064 for (int ix = 0; ix < ctl->grid_nx; ix++)
13065 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
13066#pragma omp parallel for default(shared)
13067 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13068 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
13069 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
13070 }
13071
13072 /* Set time interval for output... */
13073 const double t0 = t - 0.5 * ctl->dt_mod;
13074 const double t1 = t + 0.5 * ctl->dt_mod;
13075
13076 /* Get grid box indices... */
13077#pragma omp parallel for default(shared)
13078 for (int ip = 0; ip < atm->np; ip++) {
13079 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
13080 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
13081 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
13082 if (atm->time[ip] < t0 || atm->time[ip] > t1
13083 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
13084 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
13085 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
13086 izs[ip] = -1;
13087 }
13088
13089 /* Average data... */
13090 for (int ip = 0; ip < atm->np; ip++)
13091 if (izs[ip] >= 0) {
13092 const int idx =
13093 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
13094 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
13095 np[idx]++;
13096 for (int iq = 0; iq < ctl->nq; iq++) {
13097 mean[iq][idx] += kernel * atm->q[iq][ip];
13098 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
13099 }
13100 }
13101
13102 /* Calculate column density and volume mixing ratio... */
13103#pragma omp parallel for default(shared)
13104 for (int ix = 0; ix < ctl->grid_nx; ix++)
13105 for (int iy = 0; iy < ctl->grid_ny; iy++)
13106 for (int iz = 0; iz < ctl->grid_nz; iz++) {
13107
13108 /* Get grid index... */
13109 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
13110
13111 /* Calculate column density... */
13112 cd[idx] = NAN;
13113 if (ctl->qnt_m >= 0)
13114 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
13115
13116 /* Calculate volume mixing ratio (implicit)... */
13117 vmr_impl[idx] = NAN;
13118 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
13119 && met1 != NULL) {
13120 vmr_impl[idx] = 0;
13121 if (mean[ctl->qnt_m][idx] > 0) {
13122
13123 /* Get temperature... */
13124 double temp;
13126 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
13127 lon[ix], lat[iy], &temp, ci, cw, 1);
13128
13129 /* Calculate volume mixing ratio... */
13130 vmr_impl[idx] =
13131 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
13132 }
13133 }
13134
13135 /* Calculate mean... */
13136 if (np[idx] > 0)
13137 for (int iq = 0; iq < ctl->nq; iq++) {
13138 mean[iq][idx] /= np[idx];
13139 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
13140 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
13141 } else
13142 for (int iq = 0; iq < ctl->nq; iq++) {
13143 mean[iq][idx] = NAN;
13144 sigma[iq][idx] = NAN;
13145 }
13146 }
13147
13148 /* Write ASCII data... */
13149 if (ctl->grid_type == 0)
13150 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
13151 t, z, lon, lat, area, dz, np);
13152
13153 /* Write netCDF data... */
13154 else if (ctl->grid_type == 1)
13155 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
13156 t, z, lon, lat, area, dz, np);
13157
13158 /* Error message... */
13159 else
13160 ERRMSG("Grid data format GRID_TYPE unknown!");
13161
13162 /* Free... */
13163 free(cd);
13164 for (int iq = 0; iq < ctl->nq; iq++) {
13165 free(mean[iq]);
13166 free(sigma[iq]);
13167 }
13168 free(vmr_impl);
13169 free(z);
13170 free(lon);
13171 free(lat);
13172 free(area);
13173 free(press);
13174 free(np);
13175 free(ixs);
13176 free(iys);
13177 free(izs);
13178}
13179
13180/*****************************************************************************/
13181
13183 const char *filename,
13184 const ctl_t *ctl,
13185 const double *cd,
13186 double *mean[NQ],
13187 double *sigma[NQ],
13188 const double *vmr_impl,
13189 const double t,
13190 const double *z,
13191 const double *lon,
13192 const double *lat,
13193 const double *area,
13194 const double dz,
13195 const int *np) {
13196
13197 FILE *out;
13198
13199 /* Check if gnuplot output is requested... */
13200 if (ctl->grid_gpfile[0] != '-') {
13201
13202 /* Create gnuplot pipe... */
13203 if (!(out = popen("gnuplot", "w")))
13204 ERRMSG("Cannot create pipe to gnuplot!");
13205
13206 /* Set plot filename... */
13207 fprintf(out, "set out \"%s.png\"\n", filename);
13208
13209 /* Set time string... */
13210 double r;
13211 int year, mon, day, hour, min, sec;
13212 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
13213 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
13214 year, mon, day, hour, min);
13215
13216 /* Dump gnuplot file to pipe... */
13217 FILE *in;
13218 char line[LEN];
13219 if (!(in = fopen(ctl->grid_gpfile, "r")))
13220 ERRMSG("Cannot open file!");
13221 while (fgets(line, LEN, in))
13222 fprintf(out, "%s", line);
13223 fclose(in);
13224 }
13225
13226 else {
13227
13228 /* Create file... */
13229 if (!(out = fopen(filename, "w")))
13230 ERRMSG("Cannot create file!");
13231 }
13232
13233 /* Write header... */
13234 fprintf(out,
13235 "# $1 = time [s]\n"
13236 "# $2 = altitude [km]\n"
13237 "# $3 = longitude [deg]\n"
13238 "# $4 = latitude [deg]\n"
13239 "# $5 = surface area [km^2]\n"
13240 "# $6 = layer depth [km]\n"
13241 "# $7 = column density (implicit) [kg/m^2]\n"
13242 "# $8 = volume mixing ratio (implicit) [ppv]\n"
13243 "# $9 = number of particles [1]\n");
13244 for (int iq = 0; iq < ctl->nq; iq++)
13245 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
13246 ctl->qnt_unit[iq]);
13247 if (ctl->grid_stddev)
13248 for (int iq = 0; iq < ctl->nq; iq++)
13249 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
13250 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13251 fprintf(out, "\n");
13252
13253 /* Write data... */
13254 for (int ix = 0; ix < ctl->grid_nx; ix++) {
13255 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
13256 fprintf(out, "\n");
13257 for (int iy = 0; iy < ctl->grid_ny; iy++) {
13258 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
13259 fprintf(out, "\n");
13260 for (int iz = 0; iz < ctl->grid_nz; iz++) {
13261 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
13262 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
13263 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
13264 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
13265 for (int iq = 0; iq < ctl->nq; iq++) {
13266 fprintf(out, " ");
13267 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
13268 }
13269 if (ctl->grid_stddev)
13270 for (int iq = 0; iq < ctl->nq; iq++) {
13271 fprintf(out, " ");
13272 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
13273 }
13274 fprintf(out, "\n");
13275 }
13276 }
13277 }
13278 }
13279
13280 /* Close file... */
13281 fclose(out);
13282}
13283
13284/*****************************************************************************/
13285
13287 const char *filename,
13288 const ctl_t *ctl,
13289 const double *cd,
13290 double *mean[NQ],
13291 double *sigma[NQ],
13292 const double *vmr_impl,
13293 const double t,
13294 const double *z,
13295 const double *lon,
13296 const double *lat,
13297 const double *area,
13298 const double dz,
13299 const int *np) {
13300
13301 char longname[2 * LEN], varname[2 * LEN];
13302
13303 double *help;
13304
13305 int *help2, ncid, dimid[10], varid;
13306
13307 size_t start[2], count[2];
13308
13309 /* Allocate... */
13310 ALLOC(help, double,
13311 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13312 ALLOC(help2, int,
13313 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
13314
13315 /* Create file... */
13316 NC(nc_create(filename, NC_NETCDF4, &ncid));
13317
13318 /* Define dimensions... */
13319 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
13320 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
13321 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
13322 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
13323 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
13324
13325 /* Define variables and their attributes... */
13326 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
13327 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
13328 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
13329 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
13330 0);
13331 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
13332 0);
13333 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
13334 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
13335
13336 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
13337 ctl->grid_nc_level, 0);
13338 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
13339 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
13340 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
13341 for (int iq = 0; iq < ctl->nq; iq++) {
13342 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
13343 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
13344 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
13345 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
13346 if (ctl->grid_stddev) {
13347 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
13348 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
13349 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
13350 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
13351 }
13352 }
13353 /* End definitions... */
13354 NC(nc_enddef(ncid));
13355
13356 /* Write data... */
13357 NC_PUT_DOUBLE("time", &t, 0);
13358 NC_PUT_DOUBLE("lon", lon, 0);
13359 NC_PUT_DOUBLE("lat", lat, 0);
13360 NC_PUT_DOUBLE("z", z, 0);
13361 NC_PUT_DOUBLE("area", area, 0);
13362 NC_PUT_DOUBLE("dz", &dz, 0);
13363
13364 for (int ix = 0; ix < ctl->grid_nx; ix++)
13365 for (int iy = 0; iy < ctl->grid_ny; iy++)
13366 for (int iz = 0; iz < ctl->grid_nz; iz++)
13367 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13368 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13369 NC_PUT_DOUBLE("cd", help, 0);
13370
13371 for (int ix = 0; ix < ctl->grid_nx; ix++)
13372 for (int iy = 0; iy < ctl->grid_ny; iy++)
13373 for (int iz = 0; iz < ctl->grid_nz; iz++)
13374 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13375 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13376 NC_PUT_DOUBLE("vmr_impl", help, 0);
13377
13378 for (int ix = 0; ix < ctl->grid_nx; ix++)
13379 for (int iy = 0; iy < ctl->grid_ny; iy++)
13380 for (int iz = 0; iz < ctl->grid_nz; iz++)
13381 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13382 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13383 NC_PUT_INT("np", help2, 0);
13384
13385 for (int iq = 0; iq < ctl->nq; iq++) {
13386 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
13387 for (int ix = 0; ix < ctl->grid_nx; ix++)
13388 for (int iy = 0; iy < ctl->grid_ny; iy++)
13389 for (int iz = 0; iz < ctl->grid_nz; iz++)
13390 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13391 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13392 NC_PUT_DOUBLE(varname, help, 0);
13393 }
13394
13395 if (ctl->grid_stddev)
13396 for (int iq = 0; iq < ctl->nq; iq++) {
13397 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
13398 for (int ix = 0; ix < ctl->grid_nx; ix++)
13399 for (int iy = 0; iy < ctl->grid_ny; iy++)
13400 for (int iz = 0; iz < ctl->grid_nz; iz++)
13401 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
13402 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
13403 NC_PUT_DOUBLE(varname, help, 0);
13404 }
13405
13406 /* Close file... */
13407 NC(nc_close(ncid));
13408
13409 /* Free... */
13410 free(help);
13411 free(help2);
13412}
13413
13414/*****************************************************************************/
13415
13417 const char *filename,
13418 const ctl_t *ctl,
13419 met_t *met) {
13420
13421 /* Create file... */
13422 FILE *out, *level_log = NULL;
13423 if (!(out = fopen(filename, "w")))
13424 ERRMSG("Cannot create file!");
13425 if (strcmp(ctl->met_comp_logfile, "-") != 0) {
13426 /* Open diagnostics file... */
13427 if (!(level_log = fopen(ctl->met_comp_logfile, "w")))
13428 ERRMSG("Cannot create compression log file!");
13429 compress_log_header(level_log);
13430 LOG(1, "Write compression diagnostics: %s", ctl->met_comp_logfile);
13431 }
13432
13433 /* Write type of binary data... */
13434 FWRITE(&ctl->met_type, int,
13435 1,
13436 out);
13437
13438 /* Write version of binary data... */
13439 int version = 104;
13440 FWRITE(&version, int,
13441 1,
13442 out);
13443
13444 /* Write grid data... */
13445 FWRITE(&met->time, double,
13446 1,
13447 out);
13448 FWRITE(&met->nx, int,
13449 1,
13450 out);
13451 FWRITE(&met->ny, int,
13452 1,
13453 out);
13454 FWRITE(&met->np, int,
13455 1,
13456 out);
13457 FWRITE(met->lon, double,
13458 (size_t) met->nx,
13459 out);
13460 FWRITE(met->lat, double,
13461 (size_t) met->ny,
13462 out);
13463 FWRITE(met->p, double,
13464 (size_t) met->np,
13465 out);
13466
13467 /* Write surface data... */
13468 write_met_bin_2d(out, met, met->ps, "PS");
13469 write_met_bin_2d(out, met, met->ts, "TS");
13470 write_met_bin_2d(out, met, met->zs, "ZS");
13471 write_met_bin_2d(out, met, met->us, "US");
13472 write_met_bin_2d(out, met, met->vs, "VS");
13473 write_met_bin_2d(out, met, met->ess, "ESS");
13474 write_met_bin_2d(out, met, met->nss, "NSS");
13475 write_met_bin_2d(out, met, met->shf, "SHF");
13476 write_met_bin_2d(out, met, met->lsm, "LSM");
13477 write_met_bin_2d(out, met, met->sst, "SST");
13478 write_met_bin_2d(out, met, met->pbl, "PBL");
13479 write_met_bin_2d(out, met, met->pt, "PT");
13480 write_met_bin_2d(out, met, met->tt, "TT");
13481 write_met_bin_2d(out, met, met->zt, "ZT");
13482 write_met_bin_2d(out, met, met->h2ot, "H2OT");
13483 write_met_bin_2d(out, met, met->pct, "PCT");
13484 write_met_bin_2d(out, met, met->pcb, "PCB");
13485 write_met_bin_2d(out, met, met->cl, "CL");
13486 write_met_bin_2d(out, met, met->plcl, "PLCL");
13487 write_met_bin_2d(out, met, met->plfc, "PLFC");
13488 write_met_bin_2d(out, met, met->pel, "PEL");
13489 write_met_bin_2d(out, met, met->cape, "CAPE");
13490 write_met_bin_2d(out, met, met->cin, "CIN");
13491 write_met_bin_2d(out, met, met->o3c, "O3C");
13492
13493 /* Write level data... */
13494 write_met_bin_3d(out, ctl, met, met->z, "Z", 0, level_log);
13495 write_met_bin_3d(out, ctl, met, met->t, "T", 1, level_log);
13496 write_met_bin_3d(out, ctl, met, met->u, "U", 2, level_log);
13497 write_met_bin_3d(out, ctl, met, met->v, "V", 3, level_log);
13498 write_met_bin_3d(out, ctl, met, met->w, "W", 4, level_log);
13499 write_met_bin_3d(out, ctl, met, met->pv, "PV", 5, level_log);
13500 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", 6, level_log);
13501 write_met_bin_3d(out, ctl, met, met->o3, "O3", 7, level_log);
13502 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", 8, level_log);
13503 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", 9, level_log);
13504 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", 10, level_log);
13505 write_met_bin_3d(out, ctl, met, met->swc, "SWC", 11, level_log);
13506 write_met_bin_3d(out, ctl, met, met->cc, "CC", 12, level_log);
13507 if (METVAR != 13)
13508 ERRMSG("Number of meteo variables doesn't match!");
13509
13510 /* Write final flag... */
13511 int final = 999;
13512 FWRITE(&final, int,
13513 1,
13514 out);
13515
13516 /* Close file... */
13517 if (level_log)
13518 fclose(level_log);
13519 fclose(out);
13520}
13521
13522/*****************************************************************************/
13523
13525 FILE *out,
13526 met_t *met,
13527 float var[EX][EY],
13528 const char *varname) {
13529
13530 float *help;
13531
13532 /* Allocate... */
13533 ALLOC(help, float,
13534 EX * EY);
13535
13536 /* Copy data... */
13537 for (int ix = 0; ix < met->nx; ix++)
13538 for (int iy = 0; iy < met->ny; iy++)
13539 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
13540
13541 /* Write uncompressed data... */
13542 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
13543 FWRITE(help, float,
13544 (size_t) (met->nx * met->ny),
13545 out);
13546
13547 /* Free... */
13548 free(help);
13549}
13550
13551/*****************************************************************************/
13552
13554 FILE *out,
13555 const ctl_t *ctl,
13556 met_t *met,
13557 float var[EX][EY][EP],
13558 const char *varname,
13559 const int metvar,
13560 FILE *level_log) {
13561
13562 float *help;
13563
13564 /* Allocate... */
13565 ALLOC(help, float,
13566 EX * EY * EP);
13567
13568 /* Copy data... */
13569#pragma omp parallel for default(shared) collapse(2)
13570 for (int ix = 0; ix < met->nx; ix++)
13571 for (int iy = 0; iy < met->ny; iy++)
13572 for (int ip = 0; ip < met->np; ip++)
13573 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
13574
13575 /* Write uncompressed data... */
13576 if (ctl->met_type == 1) {
13577 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
13578 FWRITE(help, float,
13579 (size_t) (met->nx * met->ny * met->np),
13580 out);
13581 }
13582
13583 /* Write packed data... */
13584 else if (ctl->met_type == 2)
13585 compress_pck(ctl, met, varname, help, 0, level_log, out);
13586
13587 /* Write ZFP data... */
13588#ifdef ZFP
13589 else if (ctl->met_type == 3) {
13590 FWRITE(&ctl->met_zfp_prec[metvar], int,
13591 1,
13592 out);
13593 FWRITE(&ctl->met_zfp_tol[metvar], double,
13594 1,
13595 out);
13596 compress_zfp(ctl, met, varname, help, 0, level_log, out);
13597 }
13598#endif
13599
13600 /* Write zstd data... */
13601#ifdef ZSTD
13602 else if (ctl->met_type == 4)
13603 compress_zstd(ctl, met, varname, help, 0, level_log, out);
13604#endif
13605
13606 /* Write LZ4 data... */
13607#ifdef LZ4
13608 else if (ctl->met_type == 8)
13609 compress_lz4(ctl, met, varname, help, 0, level_log, out);
13610#endif
13611
13612 /* Write cmultiscale data... */
13613#ifdef CMS
13614 else if (ctl->met_type == 5) {
13615 compress_cms(ctl, met, varname, help, 0, level_log, out);
13616 }
13617#endif
13618
13619 /* Write SZ3 data... */
13620#ifdef SZ3
13621 else if (ctl->met_type == 7) {
13622 FWRITE(&ctl->met_sz3_prec[metvar], int,
13623 1,
13624 out);
13625 FWRITE(&ctl->met_sz3_tol[metvar], double,
13626 1,
13627 out);
13628 compress_sz3(ctl, met, varname, help, 0, level_log, out);
13629 }
13630#endif
13631
13632 /* Unknown method... */
13633 else {
13634 ERRMSG("MET_TYPE not supported!");
13635
13636 /* This will never execute, hack to avoid compilation error... */
13637 LOG(3, "%d", metvar);
13638 }
13639
13640 /* Free... */
13641 free(help);
13642}
13643
13644/*****************************************************************************/
13645
13647 const char *filename,
13648 const ctl_t *ctl,
13649 met_t *met) {
13650
13651 /* Create file... */
13652 int ncid, varid;
13653 size_t start[4], count[4];
13654 NC(nc_create(filename, NC_NETCDF4, &ncid));
13655
13656 /* Define dimensions... */
13657 int tid, lonid, latid, levid;
13658 NC(nc_def_dim(ncid, "time", 1, &tid));
13659
13660 if (met->coord_type == 0) {
13661 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
13662 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
13663 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0,
13664 0);
13665 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0,
13666 0);
13667 } else {
13668 NC(nc_def_dim(ncid, "x", (size_t) met->nx, &lonid));
13669 NC(nc_def_dim(ncid, "y", (size_t) met->ny, &latid));
13670 NC_DEF_VAR("x", NC_DOUBLE, 1, &lonid, "x", "easting", 0, 0);
13671 NC_DEF_VAR("y", NC_DOUBLE, 1, &latid, "y", "northing", 0, 0);
13672 }
13673
13674 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
13675
13676 /* Define grid... */
13677 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
13678 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
13679 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
13680
13681 /* Define surface variables... */
13682 int dimid2[2] = { latid, lonid };
13683 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
13684 ctl->met_nc_level, 0);
13685 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
13686 ctl->met_nc_level, 0);
13687 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
13688 ctl->met_nc_level, 0);
13689 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
13690 "m s**-1", ctl->met_nc_level, 0);
13691 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
13692 "m s**-1", ctl->met_nc_level, 0);
13693 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
13694 "Instantaneous eastward turbulent surface stress", "N m**-2",
13695 ctl->met_nc_level, 0);
13696 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
13697 "Instantaneous northward turbulent surface stress", "N m**-2",
13698 ctl->met_nc_level, 0);
13699 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
13700 "Instantaneous surface sensible heat flux", "W m**-2",
13701 ctl->met_nc_level, 0);
13702 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
13703 ctl->met_nc_level, 0);
13704 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
13705 ctl->met_nc_level, 0);
13706 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
13707 ctl->met_nc_level, 0);
13708 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
13709 ctl->met_nc_level, 0);
13710 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
13711 ctl->met_nc_level, 0);
13712 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
13713 ctl->met_nc_level, 0);
13714 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
13715 ctl->met_nc_level, 0);
13716 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
13717 ctl->met_nc_level, 0);
13718 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
13719 ctl->met_nc_level, 0);
13720 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water",
13721 "kg m**2", ctl->met_nc_level, 0);
13722 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
13723 "Pressure at lifted condensation level (LCL)", "Pa",
13724 ctl->met_nc_level, 0);
13725 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
13726 "Pressure at level of free convection (LFC)", "Pa",
13727 ctl->met_nc_level, 0);
13728 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2,
13729 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
13730 0);
13731 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
13732 "Convective available potential energy", "J kg**-1",
13733 ctl->met_nc_level, 0);
13734 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition",
13735 "J kg**-1", ctl->met_nc_level, 0);
13736 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
13737 ctl->met_nc_level, 0);
13738
13739 /* Define level data... */
13740 int dimid3[3] = { levid, latid, lonid };
13741 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
13742 ctl->met_nc_level, ctl->met_nc_quant);
13743 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
13744 ctl->met_nc_level, ctl->met_nc_quant);
13745 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
13746 ctl->met_nc_level, ctl->met_nc_quant);
13747 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
13748 ctl->met_nc_level, ctl->met_nc_quant);
13749 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
13750 ctl->met_nc_level, ctl->met_nc_quant);
13751 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
13752 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
13753 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
13754 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
13755 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
13756 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
13757 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
13758 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
13759 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
13760 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
13761 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
13762 ctl->met_nc_level, ctl->met_nc_quant);
13763
13764 /* End definitions... */
13765 NC(nc_enddef(ncid));
13766
13767 /* Write grid data... */
13768 NC_PUT_DOUBLE("time", &met->time, 0);
13769
13770 if (met->coord_type == 0) {
13771 NC_PUT_DOUBLE("lon", met->lon, 0);
13772 NC_PUT_DOUBLE("lat", met->lat, 0);
13773 } else {
13774 NC_PUT_DOUBLE("x", met->lon, 0);
13775 NC_PUT_DOUBLE("y", met->lat, 0);
13776 }
13777
13778 double phelp[EP];
13779 for (int ip = 0; ip < met->np; ip++)
13780 phelp[ip] = 100. * met->p[ip];
13781 NC_PUT_DOUBLE("lev", phelp, 0);
13782
13783 /* Write surface data... */
13784 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
13785 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
13786 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
13787 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
13788 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
13789 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
13790 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
13791 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
13792 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
13793 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
13794 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
13795 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
13796 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
13797 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
13798 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
13799 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
13800 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
13801 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
13802 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
13803 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
13804 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
13805 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
13806 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
13807 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
13808
13809 /* Write level data... */
13810 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
13811 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
13812 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
13813 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
13814 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
13815 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
13816 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
13817 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
13818 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
13819 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
13820 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
13821
13822 /* Close file... */
13823 NC(nc_close(ncid));
13824}
13825
13826/*****************************************************************************/
13827
13829 const int ncid,
13830 const char *varname,
13831 met_t *met,
13832 float var[EX][EY],
13833 const float scl) {
13834
13835 int varid;
13836 size_t start[4], count[4];
13837
13838 /* Allocate... */
13839 float *help;
13840 ALLOC(help, float,
13841 EX * EY);
13842
13843 /* Copy data... */
13844 for (int ix = 0; ix < met->nx; ix++)
13845 for (int iy = 0; iy < met->ny; iy++)
13846 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
13847
13848 /* Write data... */
13849 LOG(2, "Write 2-D variable: %s (netCDF)", varname);
13850 NC_PUT_FLOAT(varname, help, 0);
13851
13852 /* Free... */
13853 free(help);
13854}
13855
13856/*****************************************************************************/
13857
13859 const int ncid,
13860 const char *varname,
13861 met_t *met,
13862 float var[EX][EY][EP],
13863 const float scl) {
13864
13865 int varid;
13866 size_t start[4], count[4];
13867
13868 /* Allocate... */
13869 float *help;
13870 ALLOC(help, float,
13871 EX * EY * EP);
13872
13873 /* Copy data... */
13874 for (int ix = 0; ix < met->nx; ix++)
13875 for (int iy = 0; iy < met->ny; iy++)
13876 for (int ip = 0; ip < met->np; ip++)
13877 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
13878
13879 /* Write data... */
13880 LOG(2, "Write 3-D variable: %s (netCDF)", varname);
13881 NC_PUT_FLOAT(varname, help, 0);
13882
13883 /* Free... */
13884 free(help);
13885}
13886
13887/*****************************************************************************/
13888
13890 const char *filename,
13891 const ctl_t *ctl,
13892 met_t *met0,
13893 met_t *met1,
13894 const atm_t *atm,
13895 const double t) {
13896
13897 if (ctl->met_coord_type != 0)
13898 ERRMSG("Only lat/lon grid supported");
13899
13900 static FILE *out;
13901
13902 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
13903 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
13904
13905 static int nobs, *obscount, ip, okay;
13906
13907 /* Set timer... */
13908 SELECT_TIMER("WRITE_PROF", "OUTPUT");
13909
13910 /* Init... */
13911 if (t == ctl->t_start) {
13912
13913 /* Check quantity index for mass... */
13914 if (ctl->qnt_m < 0)
13915 ERRMSG("Need quantity mass!");
13916
13917 /* Check molar mass... */
13918 if (ctl->molmass <= 0)
13919 ERRMSG("Specify molar mass!");
13920
13921 /* Allocate... */
13922 ALLOC(lon, double,
13923 ctl->prof_nx);
13924 ALLOC(lat, double,
13925 ctl->prof_ny);
13926 ALLOC(area, double,
13927 ctl->prof_ny);
13928 ALLOC(z, double,
13929 ctl->prof_nz);
13930 ALLOC(press, double,
13931 ctl->prof_nz);
13932 ALLOC(rt, double,
13933 NOBS);
13934 ALLOC(rz, double,
13935 NOBS);
13936 ALLOC(rlon, double,
13937 NOBS);
13938 ALLOC(rlat, double,
13939 NOBS);
13940 ALLOC(robs, double,
13941 NOBS);
13942
13943 /* Read observation data... */
13944 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13945
13946 /* Create new output file... */
13947 LOG(1, "Write profile data: %s", filename);
13948 if (!(out = fopen(filename, "w")))
13949 ERRMSG("Cannot create file!");
13950
13951 /* Write header... */
13952 fprintf(out,
13953 "# $1 = time [s]\n"
13954 "# $2 = altitude [km]\n"
13955 "# $3 = longitude [deg]\n"
13956 "# $4 = latitude [deg]\n"
13957 "# $5 = pressure [hPa]\n"
13958 "# $6 = temperature [K]\n"
13959 "# $7 = volume mixing ratio [ppv]\n"
13960 "# $8 = H2O volume mixing ratio [ppv]\n"
13961 "# $9 = O3 volume mixing ratio [ppv]\n"
13962 "# $10 = observed BT index [K]\n"
13963 "# $11 = number of observations\n");
13964
13965 /* Set grid box size... */
13966 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
13967 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
13968 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
13969
13970 /* Set vertical coordinates... */
13971 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13972 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
13973 press[iz] = P(z[iz]);
13974 }
13975
13976 /* Set horizontal coordinates... */
13977 for (int ix = 0; ix < ctl->prof_nx; ix++)
13978 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
13979 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13980 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
13981 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
13982 }
13983 }
13984
13985 /* Set time interval... */
13986 const double t0 = t - 0.5 * ctl->dt_mod;
13987 const double t1 = t + 0.5 * ctl->dt_mod;
13988
13989 /* Allocate... */
13990 ALLOC(mass, double,
13991 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
13992 ALLOC(obsmean, double,
13993 ctl->prof_nx * ctl->prof_ny);
13994 ALLOC(obscount, int,
13995 ctl->prof_nx * ctl->prof_ny);
13996
13997 /* Loop over observations... */
13998 for (int i = 0; i < nobs; i++) {
13999
14000 /* Check time... */
14001 if (rt[i] < t0)
14002 continue;
14003 else if (rt[i] >= t1)
14004 break;
14005
14006 /* Check observation data... */
14007 if (!isfinite(robs[i]))
14008 continue;
14009
14010 /* Calculate indices... */
14011 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
14012 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
14013
14014 /* Check indices... */
14015 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
14016 continue;
14017
14018 /* Get mean observation index... */
14019 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
14020 obsmean[idx] += robs[i];
14021 obscount[idx]++;
14022 }
14023
14024 /* Analyze model data... */
14025 for (ip = 0; ip < atm->np; ip++) {
14026
14027 /* Check time... */
14028 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14029 continue;
14030
14031 /* Get indices... */
14032 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
14033 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
14034 const int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
14035
14036 /* Check indices... */
14037 if (ix < 0 || ix >= ctl->prof_nx ||
14038 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
14039 continue;
14040
14041 /* Get total mass in grid cell... */
14042 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14043 mass[idx] += atm->q[ctl->qnt_m][ip];
14044 }
14045
14046 /* Extract profiles... */
14047 for (int ix = 0; ix < ctl->prof_nx; ix++)
14048 for (int iy = 0; iy < ctl->prof_ny; iy++) {
14049 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
14050 if (obscount[idx2] > 0) {
14051
14052 /* Check profile... */
14053 okay = 0;
14054 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14055 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14056 if (mass[idx3] > 0) {
14057 okay = 1;
14058 break;
14059 }
14060 }
14061 if (!okay)
14062 continue;
14063
14064 /* Write output... */
14065 fprintf(out, "\n");
14066
14067 /* Loop over altitudes... */
14068 for (int iz = 0; iz < ctl->prof_nz; iz++) {
14069
14070 /* Get temperature, water vapor, and ozone... */
14072 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
14073 lon[ix], lat[iy], &temp, ci, cw, 1);
14074 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
14075 lon[ix], lat[iy], &h2o, ci, cw, 0);
14076 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
14077 lon[ix], lat[iy], &o3, ci, cw, 0);
14078
14079 /* Calculate volume mixing ratio... */
14080 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
14081 vmr = MA / ctl->molmass * mass[idx3]
14082 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
14083
14084 /* Write output... */
14085 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
14086 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
14087 obsmean[idx2] / obscount[idx2], obscount[idx2]);
14088 }
14089 }
14090 }
14091
14092 /* Free... */
14093 free(mass);
14094 free(obsmean);
14095 free(obscount);
14096
14097 /* Finalize... */
14098 if (t == ctl->t_stop) {
14099
14100 /* Close output file... */
14101 fclose(out);
14102
14103 /* Free... */
14104 free(lon);
14105 free(lat);
14106 free(area);
14107 free(z);
14108 free(press);
14109 free(rt);
14110 free(rz);
14111 free(rlon);
14112 free(rlat);
14113 free(robs);
14114 }
14115}
14116
14117/*****************************************************************************/
14118
14120 const char *filename,
14121 const ctl_t *ctl,
14122 met_t *met0,
14123 met_t *met1,
14124 const atm_t *atm,
14125 const double t) {
14126
14127 if (ctl->met_coord_type != 0)
14128 ERRMSG("Only lat/lon grid supported");
14129
14130 static FILE *out;
14131
14132 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
14133 kw[EP];
14134
14135 static int nobs, nk;
14136
14137 /* Set timer... */
14138 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT");
14139
14140 /* Init... */
14141 if (t == ctl->t_start) {
14142
14143 /* Allocate... */
14144 ALLOC(rt, double,
14145 NOBS);
14146 ALLOC(rz, double,
14147 NOBS);
14148 ALLOC(rlon, double,
14149 NOBS);
14150 ALLOC(rlat, double,
14151 NOBS);
14152 ALLOC(robs, double,
14153 NOBS);
14154
14155 /* Read observation data... */
14156 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
14157
14158 /* Read kernel data... */
14159 if (ctl->sample_kernel[0] != '-')
14160 read_kernel(ctl->sample_kernel, kz, kw, &nk);
14161
14162 /* Create output file... */
14163 LOG(1, "Write sample data: %s", filename);
14164 if (!(out = fopen(filename, "w")))
14165 ERRMSG("Cannot create file!");
14166
14167 /* Write header... */
14168 fprintf(out,
14169 "# $1 = time [s]\n"
14170 "# $2 = altitude [km]\n"
14171 "# $3 = longitude [deg]\n"
14172 "# $4 = latitude [deg]\n"
14173 "# $5 = surface area [km^2]\n"
14174 "# $6 = layer depth [km]\n"
14175 "# $7 = number of particles [1]\n"
14176 "# $8 = column density [kg/m^2]\n"
14177 "# $9 = volume mixing ratio [ppv]\n"
14178 "# $10 = observed BT index [K]\n\n");
14179
14180 /* Set latitude range, squared radius, and area... */
14181 dlat = DY2DEG(ctl->sample_dx);
14182 rmax2 = SQR(ctl->sample_dx);
14183 area = M_PI * rmax2;
14184 }
14185
14186 /* Set time interval for output... */
14187 const double t0 = t - 0.5 * ctl->dt_mod;
14188 const double t1 = t + 0.5 * ctl->dt_mod;
14189
14190 /* Loop over observations... */
14191 for (int i = 0; i < nobs; i++) {
14192
14193 /* Check time... */
14194 if (rt[i] < t0)
14195 continue;
14196 else if (rt[i] >= t1)
14197 break;
14198
14199 /* Calculate Cartesian coordinates... */
14200 double x0[3];
14201 geo2cart(0, rlon[i], rlat[i], x0);
14202
14203 /* Set pressure range... */
14204 const double rp = P(rz[i]);
14205 const double ptop = P(rz[i] + ctl->sample_dz);
14206 const double pbot = P(rz[i] - ctl->sample_dz);
14207
14208 /* Init... */
14209 double mass = 0;
14210 int np = 0;
14211
14212 /* Loop over air parcels... */
14213 //#pragma omp parallel for default(shared) reduction(+:mass,np)
14214 for (int ip = 0; ip < atm->np; ip++) {
14215
14216 /* Check time... */
14217 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14218 continue;
14219
14220 /* Check latitude... */
14221 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
14222 continue;
14223
14224 /* Check horizontal distance... */
14225 double x1[3];
14226 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
14227 if (DIST2(x0, x1) > rmax2)
14228 continue;
14229
14230 /* Check pressure... */
14231 if (ctl->sample_dz > 0)
14232 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
14233 continue;
14234
14235 /* Add mass... */
14236 if (ctl->qnt_m >= 0)
14237 mass +=
14238 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
14239 np++;
14240 }
14241
14242 /* Calculate column density... */
14243 const double cd = mass / (1e6 * area);
14244
14245 /* Calculate volume mixing ratio... */
14246 double vmr = 0;
14247 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
14248 if (mass > 0) {
14249
14250 /* Get temperature... */
14251 double temp;
14253 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
14254 rlon[i], rlat[i], &temp, ci, cw, 1);
14255
14256 /* Calculate volume mixing ratio... */
14257 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
14258 }
14259 } else
14260 vmr = NAN;
14261
14262 /* Write output... */
14263 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
14264 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
14265 }
14266
14267 /* Finalize...... */
14268 if (t == ctl->t_stop) {
14269
14270 /* Close output file... */
14271 fclose(out);
14272
14273 /* Free... */
14274 free(rt);
14275 free(rz);
14276 free(rlon);
14277 free(rlat);
14278 free(robs);
14279 }
14280}
14281
14282/*****************************************************************************/
14283
14285 const char *filename,
14286 const ctl_t *ctl,
14287 atm_t *atm,
14288 const double t) {
14289
14290 if (ctl->met_coord_type != 0)
14291 ERRMSG("Only lat/lon grid supported");
14292
14293 static FILE *out;
14294
14295 static double rmax2, x0[3], x1[3];
14296
14297 /* Set timer... */
14298 SELECT_TIMER("WRITE_STATION", "OUTPUT");
14299
14300 /* Init... */
14301 if (t == ctl->t_start) {
14302
14303 /* Write info... */
14304 LOG(1, "Write station data: %s", filename);
14305
14306 /* Create new file... */
14307 if (!(out = fopen(filename, "w")))
14308 ERRMSG("Cannot create file!");
14309
14310 /* Write header... */
14311 fprintf(out,
14312 "# $1 = time [s]\n"
14313 "# $2 = altitude [km]\n"
14314 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
14315 for (int iq = 0; iq < ctl->nq; iq++)
14316 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
14317 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
14318 fprintf(out, "\n");
14319
14320 /* Set geolocation and search radius... */
14321 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
14322 rmax2 = SQR(ctl->stat_r);
14323 }
14324
14325 /* Set time interval for output... */
14326 const double t0 = t - 0.5 * ctl->dt_mod;
14327 const double t1 = t + 0.5 * ctl->dt_mod;
14328
14329 /* Loop over air parcels... */
14330 for (int ip = 0; ip < atm->np; ip++) {
14331
14332 /* Check time... */
14333 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14334 continue;
14335
14336 /* Check time range for station output... */
14337 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
14338 continue;
14339
14340 /* Check station flag... */
14341 if (ctl->qnt_stat >= 0)
14342 if ((int) atm->q[ctl->qnt_stat][ip])
14343 continue;
14344
14345 /* Get Cartesian coordinates... */
14346 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
14347
14348 /* Check horizontal distance... */
14349 if (DIST2(x0, x1) > rmax2)
14350 continue;
14351
14352 /* Set station flag... */
14353 if (ctl->qnt_stat >= 0)
14354 atm->q[ctl->qnt_stat][ip] = 1;
14355
14356 /* Write data... */
14357 fprintf(out, "%.2f %g %g %g",
14358 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
14359 for (int iq = 0; iq < ctl->nq; iq++) {
14360 fprintf(out, " ");
14361 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
14362 }
14363 fprintf(out, "\n");
14364 }
14365
14366 /* Close file... */
14367 if (t == ctl->t_stop)
14368 fclose(out);
14369}
14370
14371/*****************************************************************************/
14372
14374 const char *filename,
14375 const ctl_t *ctl,
14376 const atm_t *atm,
14377 const double t) {
14378
14379 if (ctl->met_coord_type != 0)
14380 ERRMSG("Only lat/lon grid supported");
14381
14382 FILE *out;
14383
14384 /* Set timer... */
14385 SELECT_TIMER("WRITE_VTK", "OUTPUT");
14386
14387 /* Write info... */
14388 LOG(1, "Write VTK data: %s", filename);
14389
14390 /* Set time interval for output... */
14391 const double t0 = t - 0.5 * ctl->dt_mod;
14392 const double t1 = t + 0.5 * ctl->dt_mod;
14393
14394 /* Create file... */
14395 if (!(out = fopen(filename, "w")))
14396 ERRMSG("Cannot create file!");
14397
14398 /* Count data points... */
14399 int np = 0;
14400 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14401 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14402 continue;
14403 np++;
14404 }
14405
14406 /* Write header... */
14407 fprintf(out,
14408 "# vtk DataFile Version 3.0\n"
14409 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
14410
14411 /* Write point coordinates... */
14412 fprintf(out, "POINTS %d float\n", np);
14413 if (ctl->vtk_sphere) {
14414 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14415 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14416 continue;
14417 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
14418 + ctl->vtk_offset) / RE;
14419 const double coslat = cos(DEG2RAD(atm->lat[ip]));
14420 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
14421 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
14422 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
14423 fprintf(out, "%g %g %g\n", x, y, z);
14424 }
14425 } else
14426 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14427 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14428 continue;
14429 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
14430 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
14431 }
14432
14433 /* Write point data... */
14434 fprintf(out, "POINT_DATA %d\n", np);
14435 for (int iq = 0; iq < ctl->nq; iq++) {
14436 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
14437 ctl->qnt_name[iq]);
14438 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
14439 if (atm->time[ip] < t0 || atm->time[ip] > t1)
14440 continue;
14441 fprintf(out, "%g\n", atm->q[iq][ip]);
14442 }
14443 }
14444
14445 /* Close file... */
14446 fclose(out);
14447}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:8933
void mptrac_alloc(ctl_t **ctl, cache_t **cache, clim_t **clim, met_t **met0, met_t **met1, atm_t **atm, dd_t **dd)
Allocates and initializes memory resources for MPTRAC.
Definition: mptrac.c:5855
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:7553
void day2doy(const int year, const int mon, const int day, int *doy)
Get day of year from date.
Definition: mptrac.c:1858
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:8893
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:12400
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:9583
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:13828
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:11408
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:11755
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:3545
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:5568
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:4811
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:7997
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:8729
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:4164
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:11928
double cos_sza(const double sec, const double lon, const double lat)
Calculates the cosine of the solar zenith angle.
Definition: mptrac.c:1817
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:2995
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:9905
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:7964
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:10999
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:8786
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:11581
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:11799
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:3996
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:3506
void compress_log_header(FILE *out)
Write the ASCII header for per-level compression diagnostics.
Definition: mptrac.c:731
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:9386
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:895
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:10695
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:8116
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:2729
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:11136
void mptrac_run_timestep(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t **met0, met_t **met1, atm_t *atm, double t, dd_t *dd)
Executes a single timestep of the MPTRAC model simulation.
Definition: mptrac.c:7287
int compress_metvar_index(const char *varname)
Maps a meteorological variable name to its internal MPTRAC variable index.
Definition: mptrac.c:860
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:5615
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:12888
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:4918
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:4990
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:8088
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:10653
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:11827
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:8470
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:3442
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:4635
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:3289
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:13182
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:7441
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:12029
void mptrac_init(ctl_t *ctl, cache_t *cache, clim_t *clim, atm_t *atm, const int ntask)
Initializes the MPTRAC model and its associated components.
Definition: mptrac.c:6069
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:3059
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:2566
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:2509
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:5720
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:7757
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:11961
void compress_error_stats(const float *org, const float *cmp, const size_t n, double *mean, double *stddev, double *min, double *max, double *nrmse, double *org_mean, double *range)
Compute error statistics between original and reconstructed data.
Definition: mptrac.c:680
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:3831
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:8170
void read_met_nc_grid_dd_naive(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:10823
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:5428
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:10780
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:12060
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:12196
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:2932
void module_sort(const ctl_t *ctl, const met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:5456
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:4040
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:802
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:8269
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:3735
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:11856
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:3708
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:5234
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:5944
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:5530
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:12008
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:3121
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:8499
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:3472
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:13889
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:6163
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 rho, 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:758
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:13646
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:5292
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:6088
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:7497
void mptrac_write_output(const char *dirname, const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double t)
Writes various types of output data to files in a specified directory.
Definition: mptrac.c:7666
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:13553
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:11379
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:9248
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:5323
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:14284
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:12128
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:2479
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:2755
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:3088
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:5176
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:3525
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:13524
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:11259
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:7845
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:4203
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:3212
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:8310
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:12344
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:2635
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:4431
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:7901
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:7178
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:14373
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:5646
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:6223
void mptrac_free(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm, dd_t *dd)
Frees memory resources allocated for MPTRAC.
Definition: mptrac.c:5908
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:11197
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:4550
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:13286
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:7781
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:4280
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:13858
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:4705
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:5092
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:2548
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:9061
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:2659
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:3245
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:841
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:7803
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:2702
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:14119
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:12988
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:4487
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:13416
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:12294
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:8609
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:7617
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:12170
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:3271
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:12610
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:12561
MPTRAC library declarations.
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1493
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:349
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:315
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1965
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:499
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1520
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:290
#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 MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:295
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:354
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:374
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:925
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1625
#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:1473
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1260
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:1098
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1274
#define SELECT_TIMER(id, group)
Select and start a timer with specific attributes.
Definition: mptrac.h:2246
#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:860
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 DOTP(a, b)
Calculate the dot product of two vectors.
Definition: mptrac.h:802
#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:424
#define KARMAN
Karman's constant.
Definition: mptrac.h:280
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:940
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:1245
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2172
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1434
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:344
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1790
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 INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:971
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:379
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:384
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:480
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:2009
#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 P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1550
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:275
#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:399
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:364
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:905
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:670
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:606
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:339
#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:1598
#define DX2COORD(met, dx, lat)
Convert a distance in meters to a coordinate value based on grid type.
Definition: mptrac.h:732
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1890
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 SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1769
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:1866
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 TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1940
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:2040
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1919
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:707
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:2139
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:2059
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1702
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:1044
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:457
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:1746
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:414
#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:835
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:623
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:1803
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1642
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:359
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2216
#define COMPRESS_SPEED(nbytes, dt)
Calculate compression throughput in MiB/s.
Definition: mptrac.h:561
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:954
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1672
void module_dd(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_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1411
#define DD_EX_GLOB
Maximum number of longitudes of global meteo data.
Definition: mptrac.h:419
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:389
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:2102
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1303
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1841
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:524
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:369
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1333
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:334
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1574
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1727
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:394
void read_met_grib_grid(codes_handle **handles, int count_handles, met_t *met)
Reads global meteorological information from a grib file.
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1387
#define ECC(cmd)
Execute an ECCODES command and check for errors.
Definition: mptrac.h:816
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:1117
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:786
#define NC_INQ_DIM(dimname, ptr, min, max, check)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1363
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:585
#define DY2COORD(met, dy)
Convert a distance to coordinate value based on grid type.
Definition: mptrac.h:755
#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:404
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:688
void dd_push(const ctl_t *ctl, atm_t *atm, cache_t *cache, int *npart)
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1144
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:887
Air parcel data.
Definition: mptrac.h:3311
double time[NP]
Time [s].
Definition: mptrac.h:3317
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3326
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3323
int np
Number of air parcels.
Definition: mptrac.h:3314
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3329
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3320
Cache data structure.
Definition: mptrac.h:3366
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3387
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3375
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3378
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3372
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3384
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3381
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3369
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3398
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3404
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3413
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3434
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3410
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3428
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3431
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3425
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3419
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3440
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3443
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3422
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3437
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3416
int np
Number of pressure levels.
Definition: mptrac.h:3401
int no3c
Number of total ozone columns.
Definition: mptrac.h:3407
Climatological data.
Definition: mptrac.h:3506
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3548
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3524
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3536
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3527
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3509
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3554
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3542
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3545
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3539
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3518
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3533
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3512
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3530
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3521
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3515
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3551
Climatological data in the form of time series.
Definition: mptrac.h:3454
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3463
double time[CTS]
Time [s].
Definition: mptrac.h:3460
int ntime
Number of timesteps.
Definition: mptrac.h:3457
Climatological data in the form of zonal means.
Definition: mptrac.h:3474
double time[CT]
Time [s].
Definition: mptrac.h:3486
int np
Number of pressure levels.
Definition: mptrac.h:3483
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3492
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3495
int ntime
Number of timesteps.
Definition: mptrac.h:3477
int nlat
Number of latitudes.
Definition: mptrac.h:3480
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3489
Control parameters.
Definition: mptrac.h:2260
double met_utm_ref_lon
Reference longitude [deg] for UTM grid.
Definition: mptrac.h:2619
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3175
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2372
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3136
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3103
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2528
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:3024
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2633
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2405
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3112
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2883
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2351
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2552
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3299
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:3064
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2946
int met_zstd_nworkers
ZSTD number of worker threads (0=single-threaded, default=4).
Definition: mptrac.h:2645
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2970
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2279
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2291
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2561
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2300
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2384
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3106
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2393
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2922
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2871
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3127
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2360
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3253
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2931
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2776
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2943
double stat_r
Search radius around station [km].
Definition: mptrac.h:3259
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:3018
int met_zstd_level
ZSTD compression level (from -5 to 22, default=-3).
Definition: mptrac.h:2642
double met_utm_ref_lat
Reference latitude [deg] for UTM grid.
Definition: mptrac.h:2616
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3130
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3283
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2967
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2744
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2381
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2985
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2835
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2540
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2459
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3202
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3178
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2588
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2783
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2546
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2696
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2763
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2423
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2495
char species[LEN]
Species.
Definition: mptrac.h:2880
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3121
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3133
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2814
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2741
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2375
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2823
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3163
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3181
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3077
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2844
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3193
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2306
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2450
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2402
int qnt_Acs137
Quantity array index for radioactive activity of Cs-137.
Definition: mptrac.h:2573
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3184
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2429
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2760
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3238
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2489
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2607
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2904
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2988
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2732
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3154
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2808
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2294
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2327
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2471
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2859
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3265
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3097
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2805
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3199
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3124
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2333
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2994
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3169
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2456
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2976
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2877
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2441
int radio_decay
Switch for radioactive decay module (0=off, 1=on).
Definition: mptrac.h:3012
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2729
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2702
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2303
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2793
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3205
int met_pck_zstd
Apply an additional ZSTD compression step to PCK payloads (0=off, 1=on).
Definition: mptrac.h:2651
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2780
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2865
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2309
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3208
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3100
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2738
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3109
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2699
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2979
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2820
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3151
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3211
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2366
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2850
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2754
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3217
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2288
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2751
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2297
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2769
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2934
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2498
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2426
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3118
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3262
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2997
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3290
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2907
int qnt_eta
Quantity array index for eta vertical coordinate.
Definition: mptrac.h:2483
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2892
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:3036
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2940
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2447
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3082
int met_cms_nd0x
cmultiscale number of cells of coarsest grid in x-direction.
Definition: mptrac.h:2678
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2720
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:3006
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3094
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:3045
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2324
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2315
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2525
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3271
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2594
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2841
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3241
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2417
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3148
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2630
char met_comp_logfile[LEN]
Filename for per-level compression diagnostics ("-" disables output).
Definition: mptrac.h:2669
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2345
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2465
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2856
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2747
int met_dx
Stride for longitudes.
Definition: mptrac.h:2690
int qnt_destination
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2585
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2955
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2610
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2477
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2901
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:3009
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2597
int diffusion
Diffusion switch (0=off, 1=on).
Definition: mptrac.h:2796
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2513
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2486
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2507
int turb_pbl_scheme
PBL turbulence scheme (0=none, 1=closure).
Definition: mptrac.h:2799
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2348
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3280
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2363
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2444
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2853
double met_zfp_tol[METVAR]
ZFP compression tolerance.
Definition: mptrac.h:2657
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2766
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2420
int met_sz3_prec[METVAR]
SZ3 compression precision.
Definition: mptrac.h:2660
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2276
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2531
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2717
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2991
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2369
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3226
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2468
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2357
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3247
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2889
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3091
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3166
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2312
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3187
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2555
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2549
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2270
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:3061
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2958
int nens
Number of ensembles.
Definition: mptrac.h:3139
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2336
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2396
int advect
Advection scheme (1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2786
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3214
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2723
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2354
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3070
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:3003
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2474
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2832
int met_lz4_accel
LZ4 acceleration factor (>=1, default=8).
Definition: mptrac.h:2648
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3142
int qnt_Ai131
Quantity array index for radioactive activity of I-131.
Definition: mptrac.h:2576
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:3015
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:2623
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3115
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2492
int qnt_Apb210
Quantity array index for radioactive activity of Pb-210.
Definition: mptrac.h:2567
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3256
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2534
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3033
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3190
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2558
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2519
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2708
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2829
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2604
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2868
double met_cms_eps[METVAR]
cmultiscale compression epsilon.
Definition: mptrac.h:2687
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2964
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2408
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2480
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2847
int met_cms_nd0y
cmultiscale number of cells of coarsest grid in y-direction.
Definition: mptrac.h:2681
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2937
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2414
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2862
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2949
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2913
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2522
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2510
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3172
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2898
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2321
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3145
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3235
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3073
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2735
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2961
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:3067
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2925
int met_lossy_scale[METVAR]
Apply levelwise [0,1] scaling before lossy compression (0=off, 1=on).
Definition: mptrac.h:2666
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3232
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2672
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:3051
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2705
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3220
int qnt_Axe133
Quantity array index for radioactive activity of Xe-133.
Definition: mptrac.h:2579
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2973
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2390
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2438
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2453
int qnt_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2582
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2726
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3229
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2411
double turb_pbl_trans
Depth of turbulent PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2826
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:3054
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3223
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2639
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:3000
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2543
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3088
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:3042
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2982
int qnt_Abe7
Quantity array index for radioactive activity of Be-7.
Definition: mptrac.h:2570
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2916
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2675
int met_cms_maxlev
cmultiscale maximum refinement level.
Definition: mptrac.h:2684
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3160
double met_sz3_tol[METVAR]
SZ3 compression tolerance.
Definition: mptrac.h:2663
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3268
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:3048
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2339
int met_np
Number of target pressure levels.
Definition: mptrac.h:2711
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2285
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2636
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2928
int qnt_Arn222
Quantity array index for radioactive activity of Rn-222.
Definition: mptrac.h:2564
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2435
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3277
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2919
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3030
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2802
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2838
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2501
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev,...
Definition: mptrac.h:2790
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2432
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2537
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2330
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2952
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3085
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2895
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:3039
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2462
int met_coord_type
Type of coordinates for meteo data (-1=detect, 0=lat/lon [deg], 1=UTM [m]).
Definition: mptrac.h:2613
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2318
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:3027
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:3021
int met_dy
Stride for latitudes.
Definition: mptrac.h:2693
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2516
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2817
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2874
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3293
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2282
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2757
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2378
double t_start
Start time of simulation [s].
Definition: mptrac.h:2591
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2273
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2714
int nq
Number of quantities.
Definition: mptrac.h:2267
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2886
int met_zfp_prec[METVAR]
ZFP compression precision.
Definition: mptrac.h:2654
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3244
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3274
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3250
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2811
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3196
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3296
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2342
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:2627
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2387
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2399
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3157
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2504
Domain decomposition data structure.
Definition: mptrac.h:3742
size_t halo_bnd_count[4]
Extent of the periodic boundary halo hyperslab.
Definition: mptrac.h:3774
int halo_offset_end
Offset of the periodic halo block at the end of the local x-array.
Definition: mptrac.h:3780
int nx_glob
Number of global longitudes.
Definition: mptrac.h:3749
size_t halo_bnd_start[4]
Start indices of the periodic boundary halo hyperslab.
Definition: mptrac.h:3771
double lon_glob[DD_EX_GLOB]
Longitudes of the global grid [deg].
Definition: mptrac.h:3755
double lat_glob[DD_EY_GLOB]
Latitudes of the global grid [deg].
Definition: mptrac.h:3758
int halo_offset_start
Offset of the periodic halo block at the beginning of the local x-array.
Definition: mptrac.h:3777
size_t subdomain_count[4]
Extent of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:3768
int ny_glob
Number of global latitudes.
Definition: mptrac.h:3752
size_t subdomain_start[4]
Start indices of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:3765
Meteo data structure.
Definition: mptrac.h:3565
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3646
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3634
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3706
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3676
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3733
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3697
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3670
int coord_type
Definition: mptrac.h:3571
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3691
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3652
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3595
int nx
Number of longitudes.
Definition: mptrac.h:3574
int ny
Number of latitudes.
Definition: mptrac.h:3577
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3628
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3607
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3703
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3616
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3727
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3724
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3613
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3700
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3715
int np
Number of pressure levels.
Definition: mptrac.h:3580
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3682
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3610
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3685
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3622
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3721
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3655
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3667
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3673
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3661
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3586
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3640
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3643
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3637
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3619
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3679
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3688
int npl
Number of model levels.
Definition: mptrac.h:3583
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3631
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3709
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3649
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3694
double eta[EP]
Model level eta values.
Definition: mptrac.h:3604
double time
Time [s].
Definition: mptrac.h:3568
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3658
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3625
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3718
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3664
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3598
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3589
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3712
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3601
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3730
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3592
Particle data.
Definition: mptrac.h:3340
double p
Pressure [hPa].
Definition: mptrac.h:3346
double lat
Latitude [deg].
Definition: mptrac.h:3352
double time
Time [s].
Definition: mptrac.h:3343
double lon
Longitude [deg].
Definition: mptrac.h:3349
double q[NQ]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3355