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 /* Get OH data from climatology... */
101 const double oh = clim_zm(&clim->oh, t, lat, p);
102
103 /* Check beta... */
104 if (ctl->oh_chem_beta <= 0)
105 return oh;
106
107 /* Apply diurnal correction... */
108 const double csza = cos_sza(t, lon, lat);
109 const double denom = (csza >= csza_thresh) ? csza : csza_thresh;
110 return oh * exp(-ctl->oh_chem_beta / denom);
111}
112
113/*****************************************************************************/
114
116 const ctl_t *ctl,
117 clim_t *clim) {
118
119 /* Set SZA threshold... */
120 const double sza_thresh = DEG2RAD(85.), csza_thresh = cos(sza_thresh);
121
122 /* Loop over climatology data points... */
123 for (int it = 0; it < clim->oh.ntime; it++)
124 for (int iz = 0; iz < clim->oh.np; iz++)
125 for (int iy = 0; iy < clim->oh.nlat; iy++) {
126
127 /* Init... */
128 int n = 0;
129 double sum = 0;
130
131 /* Integrate day/night correction factor over longitude... */
132 for (double lon = -180; lon < 180; lon += 1.0) {
133 const double csza =
134 cos_sza(clim->oh.time[it], lon, clim->oh.lat[iy]);
135 const double denom = (csza >= csza_thresh) ? csza : csza_thresh;
136 sum += exp(-ctl->oh_chem_beta / denom);
137 n++;
138 }
139
140 /* Apply scaling factor to OH data... */
141 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
142 }
143}
144
145/*****************************************************************************/
146
148 const double rate[CP][CSZA][CO3],
149 const clim_photo_t *photo,
150 const double p,
151 const double sza,
152 const double o3c) {
153
154 /* Check pressure range... */
155 double p_help = p;
156 if (p < photo->p[photo->np - 1])
157 p_help = photo->p[photo->np - 1];
158 else if (p > photo->p[0])
159 p_help = photo->p[0];
160
161 /* Check sza range... */
162 double sza_help = sza;
163 if (sza < photo->sza[0])
164 sza_help = photo->sza[0];
165 else if (sza > photo->sza[photo->nsza - 1])
166 sza_help = photo->sza[photo->nsza - 1];
167
168 /* Check ozone column range... */
169 double o3c_help = o3c;
170 if (o3c < photo->o3c[0])
171 o3c_help = photo->o3c[0];
172 else if (o3c > photo->o3c[photo->no3c - 1])
173 o3c_help = photo->o3c[photo->no3c - 1];
174
175 /* Get indices... */
176 const int ip = locate_irr(photo->p, photo->np, p_help);
177 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
178 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
179
180 /* Interpolate photolysis rate... */
181 const double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
182 photo->p[ip + 1], rate[ip + 1][isza][io3c],
183 p_help);
184 const double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
185 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1],
186 p_help);
187 const double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
188 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c],
189 p_help);
190 const double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
191 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
192 p_help);
193 const double aux0 =
194 LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
195 const double aux1 =
196 LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
197 const double aux =
198 LIN(photo->sza[isza], aux0, photo->sza[isza + 1], aux1, sza_help);
199 return MAX(aux, 0.0);
200}
201
202/*****************************************************************************/
203
205 const clim_t *clim,
206 const double t,
207 const double lat) {
208
209 /* Get seconds since begin of year... */
210 double sec = FMOD(t, 365.25 * 86400.);
211 while (sec < 0)
212 sec += 365.25 * 86400.;
213
214 /* Get indices... */
215 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
216 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
217
218 /* Interpolate tropopause pressure... */
219 const double p0 = LIN(clim->tropo_lat[ilat],
220 clim->tropo[isec][ilat],
221 clim->tropo_lat[ilat + 1],
222 clim->tropo[isec][ilat + 1], lat);
223 const double p1 = LIN(clim->tropo_lat[ilat],
224 clim->tropo[isec + 1][ilat],
225 clim->tropo_lat[ilat + 1],
226 clim->tropo[isec + 1][ilat + 1], lat);
227 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
228}
229
230/*****************************************************************************/
231
233 clim_t *clim) {
234
235 /* Write info... */
236 LOG(1, "Initialize tropopause data...");
237
238 /* Set time [s]... */
239 clim->tropo_ntime = 12;
240 double tropo_time[12] = {
241 1209600.00, 3888000.00, 6393600.00,
242 9072000.00, 11664000.00, 14342400.00,
243 16934400.00, 19612800.00, 22291200.00,
244 24883200.00, 27561600.00, 30153600.00
245 };
246 memcpy(clim->tropo_time, tropo_time, sizeof(clim->tropo_time));
247
248 /* Set latitudes [deg]... */
249 clim->tropo_nlat = 73;
250 const double tropo_lat[73] = {
251 -90, -87.5, -85, -82.5, -80, -77.5, -75, -72.5, -70, -67.5,
252 -65, -62.5, -60, -57.5, -55, -52.5, -50, -47.5, -45, -42.5,
253 -40, -37.5, -35, -32.5, -30, -27.5, -25, -22.5, -20, -17.5,
254 -15, -12.5, -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10, 12.5,
255 15, 17.5, 20, 22.5, 25, 27.5, 30, 32.5, 35, 37.5, 40, 42.5,
256 45, 47.5, 50, 52.5, 55, 57.5, 60, 62.5, 65, 67.5, 70, 72.5,
257 75, 77.5, 80, 82.5, 85, 87.5, 90
258 };
259 memcpy(clim->tropo_lat, tropo_lat, sizeof(clim->tropo_lat));
260
261 /* Set tropopause pressure [hPa] (NCEP/NCAR Reanalysis 1)... */
262 const double tropo[12][73] = {
263 {324.1, 325.6, 325, 324.3, 322.5, 319.7, 314, 307.2, 301.8, 299.6,
264 297.1, 292.2, 285.6, 276.1, 264, 248.9, 231.9, 213.5, 194.4,
265 175.3, 157, 140.4, 126.7, 116.3, 109.5, 105.4, 103, 101.4, 100.4,
266 99.69, 99.19, 98.84, 98.56, 98.39, 98.39, 98.42, 98.44, 98.54,
267 98.68, 98.81, 98.89, 98.96, 99.12, 99.65, 101.4, 105.4, 113.5, 128,
268 152.1, 184.7, 214, 234.1, 247.3, 255.8, 262.6, 267.7, 271.7, 275,
269 277.2, 279, 280.1, 280.4, 280.6, 280.1, 279.3, 278.3, 276.8, 275.8,
270 275.3, 275.6, 275.4, 274.1, 273.5},
271 {337.3, 338.7, 337.8, 336.4, 333, 328.8, 321.1, 312.6, 306.6, 303.7,
272 300.2, 293.8, 285.4, 273.8, 259.6, 242.7, 224.4, 205.2, 186, 167.5,
273 150.3, 135, 122.8, 113.9, 108.2, 104.7, 102.5, 101.1, 100.2, 99.42,
274 98.88, 98.52, 98.25, 98.09, 98.07, 98.1, 98.12, 98.2, 98.25, 98.27,
275 98.26, 98.27, 98.36, 98.79, 100.2, 104.2, 113.7, 131.2, 159.5, 193,
276 220.4, 238.1, 250.2, 258.1, 264.7, 269.7, 273.7, 277.3, 280.2, 282.8,
277 284.9, 286.5, 288.1, 288.8, 289, 288.5, 287.2, 286.3, 286.1, 287.2,
278 287.5, 286.2, 285.8},
279 {335, 336, 335.7, 335.1, 332.3, 328.1, 320.6, 311.8, 305.1, 301.9,
280 297.6, 290, 280.4, 268.3, 254.6, 239.6, 223.9, 207.9, 192.2, 176.9,
281 161.7, 146.4, 132.2, 120.6, 112.3, 107.2, 104.3, 102.4, 101.3,
282 100.4, 99.86, 99.47, 99.16, 98.97, 98.94, 98.97, 99, 99.09, 99.2,
283 99.31, 99.35, 99.41, 99.51, 99.86, 101.1, 104.9, 114.3, 131, 156.8,
284 186.3, 209.3, 224.6, 236.8, 246.3, 254.9, 262.3, 268.8, 274.8,
285 279.9, 284.6, 288.6, 291.6, 294.9, 297.5, 299.8, 301.8, 303.1,
286 304.3, 304.9, 306, 306.6, 306.2, 306},
287 {306.2, 306.7, 305.7, 307.1, 307.3, 306.4, 301.8, 296.2, 292.4,
288 290.3, 287.1, 280.9, 273.4, 264.3, 254.1, 242.8, 231, 219, 207.2,
289 195.5, 183.3, 169.7, 154.7, 138.7, 124.1, 113.6, 107.8, 104.7,
290 102.8, 101.7, 100.9, 100.4, 100, 99.79, 99.7, 99.66, 99.68, 99.79,
291 99.94, 100.2, 100.5, 100.9, 101.4, 102.1, 103.4, 107, 115.2, 129.1,
292 148.7, 171, 190.8, 205.6, 218.4, 229.4, 239.6, 248.6, 256.5,
293 263.7, 270.3, 276.6, 282.6, 288.1, 294.5, 300.4, 306.3, 311.4,
294 315.1, 318.3, 320.3, 322.2, 322.8, 321.5, 321.1},
295 {266.5, 264.9, 260.8, 261, 262, 263, 261.3, 259.7, 259.2, 259.8,
296 260.1, 258.6, 256.7, 253.6, 249.5, 243.9, 237.4, 230, 222.1, 213.9,
297 205, 194.4, 180.4, 161.8, 140.7, 122.9, 112.1, 106.7, 104.1, 102.7,
298 101.8, 101.4, 101.1, 101, 101, 101, 101.1, 101.2, 101.5, 101.9,
299 102.4, 103, 103.8, 104.9, 106.8, 110.1, 115.6, 124, 135.2, 148.9,
300 165.2, 181.3, 198, 211.8, 223.5, 233.8, 242.9, 251.5, 259, 266.2,
301 273.1, 279.2, 286.2, 292.8, 299.6, 306, 311.1, 315.5, 318.8, 322.6,
302 325.3, 325.8, 325.8},
303 {220.1, 218.1, 210.8, 207.2, 207.6, 210.5, 211.4, 213.5, 217.3,
304 222.4, 227.9, 232.8, 237.4, 240.8, 242.8, 243, 241.5, 238.6, 234.2,
305 228.5, 221, 210.7, 195.1, 172.9, 147.8, 127.6, 115.6, 109.9, 107.1,
306 105.7, 105, 104.8, 104.8, 104.9, 105, 105.1, 105.3, 105.5, 105.8,
307 106.4, 107, 107.6, 108.1, 108.8, 110, 111.8, 114.2, 117.4, 121.6,
308 127.9, 137.3, 151.2, 169.5, 189, 205.8, 218.9, 229.1, 237.8, 245,
309 251.5, 257.1, 262.3, 268.2, 274, 280.4, 286.7, 292.4, 297.9, 302.9,
310 308.5, 312.2, 313.1, 313.3},
311 {187.4, 184.5, 173.3, 166.1, 165.4, 167.8, 169.6, 173.6, 179.6,
312 187.9, 198.9, 210, 220.5, 229.2, 235.7, 239.9, 241.8, 241.6, 239.6,
313 235.8, 229.4, 218.6, 200.9, 175.9, 149.4, 129.4, 118.3, 113.1,
314 110.8, 109.7, 109.3, 109.4, 109.7, 110, 110.2, 110.4, 110.5, 110.7,
315 111, 111.4, 111.8, 112.1, 112.3, 112.7, 113.2, 113.9, 115, 116.4,
316 117.9, 120.4, 124.1, 130.9, 142.2, 159.6, 179.6, 198.5, 212.9,
317 224.2, 232.7, 239.1, 243.8, 247.7, 252.4, 257.3, 263.2, 269.5,
318 275.4, 281.1, 286.3, 292, 296.3, 298.2, 298.8},
319 {166, 166.4, 155.7, 148.3, 147.1, 149, 152.1, 157, 163.6, 172.4,
320 185.3, 199.2, 212.6, 224, 233.2, 239.6, 243.3, 244.6, 243.6, 240.3,
321 233.9, 222.6, 203.7, 177, 149.5, 129.7, 119, 114, 111.7, 110.7,
322 110.3, 110.3, 110.6, 110.9, 111.1, 111.3, 111.5, 111.6, 111.9,
323 112.2, 112.5, 112.6, 112.8, 113, 113.4, 114, 115.1, 116.5, 118.3,
324 120.9, 124.4, 130.2, 139.4, 154.6, 173.8, 193.1, 208.1, 220.4,
325 230.1, 238.2, 244.7, 249.5, 254.5, 259.3, 264.5, 269.4, 273.7,
326 278.2, 282.6, 287.4, 290.9, 292.5, 293},
327 {171.9, 172.8, 166.2, 162.3, 161.4, 162.5, 165.2, 169.6, 175.3,
328 183.1, 193.8, 205.9, 218.3, 229.6, 238.5, 244.3, 246.9, 246.7,
329 243.8, 238.4, 230.2, 217.9, 199.6, 174.9, 148.9, 129.8, 119.5,
330 114.8, 112.3, 110.9, 110.3, 110.1, 110.2, 110.3, 110.4, 110.5,
331 110.6, 110.8, 111, 111.4, 111.8, 112, 112.2, 112.4, 112.9, 113.6,
332 114.7, 116.3, 118.4, 121.9, 127.1, 136.1, 149.8, 168.4, 186.9,
333 203.3, 217, 229.1, 238.7, 247, 254, 259.3, 264.3, 268.3, 272.5,
334 276.6, 280.4, 284.4, 288.4, 293.3, 297.2, 298.7, 299.1},
335 {191.6, 192.2, 189, 188.1, 190.2, 193.7, 197.8, 202.9, 208.5,
336 215.6, 224.2, 233.1, 241.2, 247.3, 250.8, 251.3, 248.9, 244.2,
337 237.3, 228.4, 217.2, 202.9, 184.5, 162.5, 140.7, 124.8, 116.2,
338 111.8, 109.4, 107.9, 107, 106.7, 106.6, 106.6, 106.7, 106.7,
339 106.8, 107, 107.4, 108, 108.7, 109.3, 109.8, 110.4, 111.2,
340 112.4, 114.2, 116.9, 121.1, 127.9, 139.3, 155.2, 173.6, 190.7,
341 206.1, 220.1, 232.3, 243, 251.8, 259.2, 265.7, 270.6, 275.3,
342 279.3, 283.3, 286.9, 289.7, 292.8, 296.1, 300.5, 303.9, 304.8,
343 305.1},
344 {241.5, 239.6, 236.8, 237.4, 239.4, 242.3, 244.2, 246.4, 249.2,
345 253.6, 258.6, 262.7, 264.8, 264.2, 260.6, 254.1, 245.5, 235.3,
346 223.9, 211.7, 198.3, 183.1, 165.6, 147.1, 130.5, 118.7, 111.9,
347 108.1, 105.8, 104.3, 103.4, 102.8, 102.5, 102.4, 102.5, 102.5,
348 102.5, 102.7, 103.1, 103.8, 104.6, 105.4, 106.1, 107, 108.2,
349 109.9, 112.8, 117.5, 126, 140.4, 161, 181.9, 201.2, 216.8, 230.4,
350 241.8, 251.4, 259.9, 266.9, 272.8, 277.4, 280.4, 282.9, 284.6,
351 286.1, 287.4, 288.3, 289.5, 290.9, 294.2, 296.9, 297.5, 297.6},
352 {301.2, 300.3, 296.6, 295.4, 295, 294.3, 291.2, 287.4, 284.9, 284.7,
353 284.1, 281.5, 277.1, 270.4, 261.7, 250.6, 237.6, 223.1, 207.9, 192,
354 175.8, 158.8, 142.1, 127.6, 116.8, 109.9, 106, 103.6, 102.1, 101.1,
355 100.4, 99.96, 99.6, 99.37, 99.32, 99.32, 99.31, 99.46, 99.77, 100.2,
356 100.7, 101.3, 101.8, 102.7, 104.1, 106.8, 111.9, 121, 136.7, 160,
357 186.9, 209.9, 228.1, 241.2, 251.5, 259.5, 265.7, 270.9, 274.8, 278,
358 280.3, 281.8, 283, 283.3, 283.7, 283.8, 283, 282.2, 281.2, 281.4,
359 281.7, 281.1, 281.2}
360 };
361 memcpy(clim->tropo, tropo, sizeof(clim->tropo));
362
363 /* Get range... */
364 double tropomin = 1e99, tropomax = -1e99;
365 for (int it = 0; it < clim->tropo_ntime; it++)
366 for (int iy = 0; iy < clim->tropo_nlat; iy++) {
367 tropomin = MIN(tropomin, clim->tropo[it][iy]);
368 tropomax = MAX(tropomax, clim->tropo[it][iy]);
369 }
370
371 /* Write info... */
372 LOG(2, "Number of time steps: %d", clim->tropo_ntime);
373 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
374 clim->tropo_time[0], clim->tropo_time[1],
375 clim->tropo_time[clim->tropo_ntime - 1]);
376 LOG(2, "Number of latitudes: %d", clim->tropo_nlat);
377 LOG(2, "Latitudes: %g, %g ... %g deg",
378 clim->tropo_lat[0], clim->tropo_lat[1],
379 clim->tropo_lat[clim->tropo_nlat - 1]);
380 LOG(2, "Tropopause altitude range: %g ... %g hPa", Z(tropomax),
381 Z(tropomin));
382 LOG(2, "Tropopause pressure range: %g ... %g hPa", tropomin, tropomax);
383}
384
385/*****************************************************************************/
386
387double clim_ts(
388 const clim_ts_t *ts,
389 const double t) {
390
391 /* Interpolate... */
392 if (t <= ts->time[0])
393 return ts->vmr[0];
394 else if (t >= ts->time[ts->ntime - 1])
395 return ts->vmr[ts->ntime - 1];
396 else {
397 const int idx = locate_irr(ts->time, ts->ntime, t);
398 return LIN(ts->time[idx], ts->vmr[idx],
399 ts->time[idx + 1], ts->vmr[idx + 1], t);
400 }
401}
402
403/*****************************************************************************/
404
405double clim_zm(
406 const clim_zm_t *zm,
407 const double t,
408 const double lat,
409 const double p) {
410
411 /* Get seconds since begin of year... */
412 double sec = FMOD(t, 365.25 * 86400.);
413 while (sec < 0)
414 sec += 365.25 * 86400.;
415
416 /* Check pressure range... */
417 double p_help = p;
418 if (p < zm->p[zm->np - 1])
419 p_help = zm->p[zm->np - 1];
420 else if (p > zm->p[0])
421 p_help = zm->p[0];
422
423 /* Check latitude range... */
424 double lat_help = lat;
425 if (lat < zm->lat[0])
426 lat_help = zm->lat[0];
427 else if (lat > zm->lat[zm->nlat - 1])
428 lat_help = zm->lat[zm->nlat - 1];
429
430 /* Get indices... */
431 const int isec = locate_irr(zm->time, zm->ntime, sec);
432 const int ilat = locate_reg(zm->lat, zm->nlat, lat_help);
433 const int ip = locate_irr(zm->p, zm->np, p_help);
434
435 /* Interpolate climatology data... */
436 const double aux00 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat],
437 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat],
438 p_help);
439 const double aux01 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat + 1],
440 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat + 1],
441 p_help);
442 const double aux10 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat],
443 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat],
444 p_help);
445 const double aux11 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat + 1],
446 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat + 1],
447 p_help);
448 const double aux0 =
449 LIN(zm->lat[ilat], aux00, zm->lat[ilat + 1], aux01, lat_help);
450 const double aux1 =
451 LIN(zm->lat[ilat], aux10, zm->lat[ilat + 1], aux11, lat_help);
452 const double aux = LIN(zm->time[isec], aux0, zm->time[isec + 1], aux1, sec);
453 return MAX(aux, 0.0);
454}
455
456/*****************************************************************************/
457
458#ifdef CMS
459void compress_cms(
460 const ctl_t *ctl,
461 const char *varname,
462 float *array,
463 const size_t nx,
464 const size_t ny,
465 const size_t np,
466 const double *plev,
467 const int decompress,
468 FILE *inout) {
469
470 /* Set lon-lat grid... */
471 const size_t nxy = nx * ny;
472 double lon[EX], lat[EY];
473 for (size_t ix = 0; ix < nx; ix++)
474 lon[ix] = 360. * (double) ix / ((double) nx - 1.);
475 for (size_t iy = 0; iy < ny; iy++)
476 lat[iy] = 90. - 180. * (double) iy / ((double) ny - 1.);
477
478 /* Set multiscale parameters... */
479 const char domain[] = "[0.0, 360.0]x[-90.0, 90.0]";
480 const int Nd0_x = ctl->met_cms_nd0x;
481 const int Nd0_y = ctl->met_cms_nd0y;
482 const int max_level_grid = ctl->met_cms_maxlev;
483 cms_param_t *cms_param
484 = cms_set_parameters(nx, ny, max_level_grid, Nd0_x, Nd0_y, domain);
485
486 /* Init... */
487 double cr = 0, t_coars = 0, t_eval = 0;
488
489 /* Read compressed stream and decompress array... */
490 if (decompress) {
491
492 /* Loop over levels... */
493 for (size_t ip = 0; ip < np; ip++) {
494
495 /* Initialize multiscale module... */
496 cms_module_t *cms_ptr = cms_init(cms_param);
497
498 /* Read binary data... */
499 cms_sol_t *cms_sol;
500 if (ctl->met_cms_zstd == 1)
501 cms_sol = cms_read_zstd_sol(cms_ptr, inout);
502 else
503 cms_sol = cms_read_sol(cms_ptr, inout);
504
505 /* Evaluate... */
506#pragma omp parallel for collapse(2) default(shared)
507 for (size_t ix = 0; ix < nx; ix++)
508 for (size_t iy = 0; iy < ny; iy++) {
509 double val;
510 const double x[] = { lon[ix], lat[iy] };
511 cms_eval(cms_ptr, cms_sol, x, &val);
512 array[ARRAY_3D(ix, iy, ny, ip, np)] = (float) val;
513 }
514
515 /* Calculate harmonic mean of compression rates... */
516 cr += 1.0 / cms_compression_rate(cms_ptr, cms_sol);
517
518 /* Free... */
519 cms_delete_sol(cms_sol);
520 cms_delete_module(cms_ptr);
521 }
522
523 /* Write info... */
524 LOG(2, "Read 3-D variable: %s (CMS, RATIO= %g)", varname,
525 (double) np / cr);
526 }
527
528 /* Compress array and output compressed stream... */
529 else {
530
531 /* Init... */
532 cms_module_t *cms_ptr[EP];
533 cms_sol_t *cms_sol[EP];
534
535 /* Loop over batches... */
536 const size_t dip = (ctl->met_cms_batch <= 0
537 ? (size_t) omp_get_max_threads()
538 : (size_t) ctl->met_cms_batch);
539 for (size_t ip0 = 0; ip0 < np; ip0 += dip) {
540
541 /* Measure time... */
542 double t0 = omp_get_wtime();
543
544 /* Loop over levels... */
545#pragma omp parallel for default(shared)
546 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
547
548 /* Allocate... */
549 float *tmp_arr;
550 ALLOC(tmp_arr, float,
551 nxy);
552
553 /* Copy level data... */
554 for (size_t ix = 0; ix < nx; ++ix)
555 for (size_t iy = 0; iy < ny; ++iy)
556 tmp_arr[ARRAY_2D(ix, iy, ny)] =
557 array[ARRAY_3D(ix, iy, ny, ip, np)];
558
559 /* Set eps threshold value... */
560 double c_thresh_test;
561 if (strcasecmp(varname, "Z") == 0)
562 c_thresh_test = ctl->met_cms_eps_z;
563 else if (strcasecmp(varname, "T") == 0)
564 c_thresh_test = ctl->met_cms_eps_t;
565 else if (strcasecmp(varname, "U") == 0)
566 c_thresh_test = ctl->met_cms_eps_u;
567 else if (strcasecmp(varname, "V") == 0)
568 c_thresh_test = ctl->met_cms_eps_v;
569 else if (strcasecmp(varname, "W") == 0)
570 c_thresh_test = ctl->met_cms_eps_w;
571 else if (strcasecmp(varname, "PV") == 0)
572 c_thresh_test = ctl->met_cms_eps_pv;
573 else if (strcasecmp(varname, "H2O") == 0)
574 c_thresh_test = ctl->met_cms_eps_h2o;
575 else if (strcasecmp(varname, "O3") == 0)
576 c_thresh_test = ctl->met_cms_eps_o3;
577 else if (strcasecmp(varname, "LWC") == 0)
578 c_thresh_test = ctl->met_cms_eps_lwc;
579 else if (strcasecmp(varname, "RWC") == 0)
580 c_thresh_test = ctl->met_cms_eps_rwc;
581 else if (strcasecmp(varname, "IWC") == 0)
582 c_thresh_test = ctl->met_cms_eps_iwc;
583 else if (strcasecmp(varname, "SWC") == 0)
584 c_thresh_test = ctl->met_cms_eps_swc;
585 else if (strcasecmp(varname, "CC") == 0)
586 c_thresh_test = ctl->met_cms_eps_cc;
587 else
588 ERRMSG("Variable name unknown!");
589
590 /* Initialize multiscale module... */
591 cms_ptr[ip] = cms_init(cms_param);
592
593 /* Coarsening... */
594 cms_sol[ip] =
595 cms_read_arr_new(cms_ptr[ip], tmp_arr, lon, lat,
596 nx, ny, c_thresh_test);
597
598 /* Free... */
599 free(tmp_arr);
600 }
601
602 /* Measure time... */
603 t_coars += (omp_get_wtime() - t0);
604
605 /* Loop over levels... */
606 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
607
608 /* Allocate... */
609 double *tmp_cms, *tmp_org, *tmp_diff;
610 ALLOC(tmp_cms, double,
611 nxy);
612 ALLOC(tmp_org, double,
613 nxy);
614 ALLOC(tmp_diff, double,
615 nxy);
616
617 /* Measure time... */
618 t0 = omp_get_wtime();
619
620 /* Evaluate... */
621#pragma omp parallel for collapse(2) default(shared)
622 for (size_t ix = 0; ix < nx; ix++)
623 for (size_t iy = 0; iy < ny; iy++) {
624 const size_t idx = ARRAY_2D(ix, iy, ny);
625 const double x[] = { lon[ix], lat[iy] };
626 cms_eval(cms_ptr[ip], cms_sol[ip], x, &tmp_cms[idx]);
627 tmp_org[idx] = array[ARRAY_3D(ix, iy, ny, ip, np)];
628 tmp_diff[idx] = tmp_cms[idx] - tmp_org[idx];
629 }
630
631 /* Measure time... */
632 t_eval += (omp_get_wtime() - t0);
633
634 /* Write info... */
635 const double bias = gsl_stats_mean(tmp_diff, 1, nxy);
636 const double stddev = gsl_stats_sd_m(tmp_diff, 1, nxy, bias);
637 const double rmse = sqrt(SQR(bias) + SQR(stddev));
638 const double range =
639 gsl_stats_max(tmp_org, 1, nxy) - gsl_stats_min(tmp_org, 1, nxy);
640 const double nrmse = (range > 0 ? rmse / range : NAN);
641 LOG(2,
642 "cmultiscale: var= %s / lev= %lu / plev= %g / ratio= %g / rho= %g"
643 " / mean= %g / sd= %g / min= %g / max= %g / NRMSE= %g", varname,
644 ip, plev[ip], cms_compression_rate(cms_ptr[ip], cms_sol[ip]),
645 gsl_stats_correlation(tmp_cms, 1, tmp_org, 1, nxy), bias, stddev,
646 gsl_stats_min(tmp_diff, 1, nxy), gsl_stats_max(tmp_diff, 1, nxy),
647 nrmse);
648
649 /* Calculate harmonic mean of compression rates... */
650 cr += 1.0 / cms_compression_rate(cms_ptr[ip], cms_sol[ip]);
651
652 /* Save binary data... */
653 if (ctl->met_cms_zstd == 1)
654 cms_save_zstd_sol(cms_sol[ip], inout, 3);
655 else
656 cms_save_sol(cms_sol[ip], inout);
657
658 /* Free... */
659 cms_delete_sol(cms_sol[ip]);
660 cms_delete_module(cms_ptr[ip]);
661 free(tmp_cms);
662 free(tmp_org);
663 free(tmp_diff);
664 }
665 }
666
667 /* Write info... */
668 LOG(2, "Write 3-D variable: %s"
669 " (CMS, RATIO= %g, T_COARS= %g s, T_EVAL= %g s)",
670 varname, (double) np / cr, t_coars, t_eval);
671 }
672
673 /* Free... */
674 cms_delete_param(cms_param);
675}
676#endif
677
678/*****************************************************************************/
679
681 const char *varname,
682 float *array,
683 const size_t nxy,
684 const size_t nz,
685 const int decompress,
686 FILE *inout) {
687
688 double min[EP], max[EP], off[EP], scl[EP];
689
690 unsigned short *sarray;
691
692 /* Allocate... */
693 ALLOC(sarray, unsigned short,
694 nxy * nz);
695
696 /* Read compressed stream and decompress array... */
697 if (decompress) {
698
699 /* Write info... */
700 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
701 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
702
703 /* Read data... */
704 FREAD(&scl, double,
705 nz,
706 inout);
707 FREAD(&off, double,
708 nz,
709 inout);
710 FREAD(sarray, unsigned short,
711 nxy * nz,
712 inout);
713
714 /* Convert to float... */
715#pragma omp parallel for default(shared)
716 for (size_t ixy = 0; ixy < nxy; ixy++)
717 for (size_t iz = 0; iz < nz; iz++)
718 array[ixy * nz + iz]
719 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
720 }
721
722 /* Compress array and output compressed stream... */
723 else {
724
725 /* Write info... */
726 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
727 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
728
729 /* Get range... */
730 for (size_t iz = 0; iz < nz; iz++) {
731 min[iz] = array[iz];
732 max[iz] = array[iz];
733 }
734 for (size_t ixy = 1; ixy < nxy; ixy++)
735 for (size_t iz = 0; iz < nz; iz++) {
736 if (array[ixy * nz + iz] < min[iz])
737 min[iz] = array[ixy * nz + iz];
738 if (array[ixy * nz + iz] > max[iz])
739 max[iz] = array[ixy * nz + iz];
740 }
741
742 /* Get offset and scaling factor... */
743 for (size_t iz = 0; iz < nz; iz++) {
744 scl[iz] = (max[iz] - min[iz]) / 65533.;
745 off[iz] = min[iz];
746 }
747
748 /* Convert to short... */
749#pragma omp parallel for default(shared)
750 for (size_t ixy = 0; ixy < nxy; ixy++)
751 for (size_t iz = 0; iz < nz; iz++)
752 if (scl[iz] != 0)
753 sarray[ixy * nz + iz] = (unsigned short)
754 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
755 else
756 sarray[ixy * nz + iz] = 0;
757
758 /* Write data... */
759 FWRITE(&scl, double,
760 nz,
761 inout);
762 FWRITE(&off, double,
763 nz,
764 inout);
765 FWRITE(sarray, unsigned short,
766 nxy * nz,
767 inout);
768 }
769
770 /* Free... */
771 free(sarray);
772}
773
774/*****************************************************************************/
775
776#ifdef SZ3
777void compress_sz3(
778 const char *varname,
779 float *array,
780 int nx,
781 int ny,
782 int nz,
783 int precision,
784 double tolerance,
785 int decompress,
786 FILE *inout) {
787
788 if ((precision > 0) == (tolerance > 0.0))
789 ERRMSG("Exactly one of precision or tolerance must be set for SZ3!");
790
791 size_t r1 = (size_t) nx, r2 = (size_t) ny, r3 = (size_t) nz,
792 outSize = 0, total_elems = r1 * r2 * r3;
793
794 unsigned char *bytes = NULL;
795
796 /* Read compressed stream and decompress array... */
797 if (decompress) {
798
799 size_t sz3size;
800 FREAD(&sz3size, size_t,
801 1,
802 inout);
803 ALLOC(bytes, char,
804 sz3size);
805 FREAD(bytes, unsigned char,
806 sz3size,
807 inout);
808
809 void *outData = SZ_decompress(SZ_FLOAT, bytes, sz3size, 0, 0, r3, r2, r1);
810 if (!outData)
811 ERRMSG("Decompression failed!");
812
813 memcpy(array, outData, total_elems * sizeof(float));
814
815 free(outData);
816 free(bytes);
817
818 LOG(2, "Read 3-D variable: %s (SZ3, PREC=%d, TOL=%g, RATIO=%g)",
819 varname, precision, tolerance,
820 (double) (total_elems * sizeof(float)) / (double) sz3size);
821 }
822
823 /* Compress array and output compressed stream... */
824 else {
825
826 const int errBoundMode = (precision > 0) ? REL : ABS;
827 const double absBound = (errBoundMode == ABS) ? tolerance : 0.0;
828 const double relBound =
829 (errBoundMode == REL) ? pow(2.0, -(double) precision) : 0.0;
830
831 bytes = SZ_compress_args(SZ_FLOAT, array, &outSize,
832 errBoundMode, absBound, relBound, 0.0,
833 0, 0, r3, r2, r1);
834 if (!bytes || outSize == 0)
835 ERRMSG("Compression failed!");
836
837 FWRITE(&outSize, size_t,
838 1,
839 inout);
840 FWRITE(bytes, unsigned char,
841 outSize,
842 inout);
843
844 free(bytes);
845
846 LOG(2, "Write 3-D variable: %s (SZ3, PREC=%d, TOL=%g, RATIO=%g)",
847 varname, precision, tolerance,
848 (double) (total_elems * sizeof(float)) / (double) outSize);
849 }
850}
851#endif
852
853/*****************************************************************************/
854
855#ifdef ZFP
856void compress_zfp(
857 const char *varname,
858 float *array,
859 const int nx,
860 const int ny,
861 const int nz,
862 const int precision,
863 const double tolerance,
864 const int decompress,
865 FILE *inout) {
866
867 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
868 const size_t snx = (size_t) nx;
869 const size_t sny = (size_t) ny;
870 const size_t snz = (size_t) nz;
871 const zfp_type type = zfp_type_float;
872 zfp_field *field = zfp_field_3d(array, type, snx, sny, snz);
873
874 /* Allocate meta data for a compressed stream... */
875 zfp_stream *zfp = zfp_stream_open(NULL);
876 if (!field || !zfp)
877 ERRMSG("Failed to allocate zfp structures!");
878
879 /* Set compression mode... */
880 int actual_prec = 0;
881 double actual_tol = 0;
882 if ((precision > 0 && tolerance > 0) || (precision <= 0 && tolerance <= 0)) {
883 ERRMSG("Exactly one of precision or tolerance must be set for zfp!");
884 } else if (precision > 0)
885 actual_prec =
886 (int) zfp_stream_set_precision(zfp, (unsigned int) precision);
887 else if (tolerance > 0)
888 actual_tol = zfp_stream_set_accuracy(zfp, tolerance);
889
890 /* Allocate buffer for compressed data... */
891 const size_t bufsize = zfp_stream_maximum_size(zfp, field);
892 void *buffer;
893 ALLOC(buffer, char,
894 bufsize);
895
896 /* Associate bit stream with allocated buffer... */
897 bitstream *stream = stream_open(buffer, bufsize);
898 zfp_stream_set_bit_stream(zfp, stream);
899 zfp_stream_rewind(zfp);
900
901 /* Read compressed stream and decompress array... */
902 size_t zfpsize;
903 if (decompress) {
904 FREAD(&zfpsize, size_t,
905 1,
906 inout);
907 if (zfpsize > bufsize)
908 ERRMSG("Compressed data size exceeds allocated buffer!");
909 FREAD(buffer, unsigned char,
910 zfpsize,
911 inout);
912 if (!zfp_decompress(zfp, field))
913 ERRMSG("Decompression failed!");
914 const double cr =
915 ((double) (snx * sny * snz * sizeof(float))) / (double) zfpsize;
916 const double bpv = (8.0 * (double) zfpsize) / (double) (snx * sny * snz);
917 LOG(2,
918 "Read 3-D variable: %s (ZFP, PREC= %d, TOL= %g, RATIO= %g, BPV= %g)",
919 varname, actual_prec, actual_tol, cr, bpv);
920 }
921
922 /* Compress array and output compressed stream... */
923 else {
924 zfpsize = zfp_compress(zfp, field);
925 if (!zfpsize) {
926 ERRMSG("Compression failed!");
927 } else {
928 FWRITE(&zfpsize, size_t,
929 1,
930 inout);
931 FWRITE(buffer, unsigned char,
932 zfpsize,
933 inout);
934 }
935 const double cr =
936 ((double) (snx * sny * snz * sizeof(float))) / (double) zfpsize;
937 const double bpv = (8.0 * (double) zfpsize) / (double) (snx * sny * snz);
938 LOG(2,
939 "Write 3-D variable: %s (ZFP, PREC= %d, TOL= %g, RATIO= %g, BPV= %g)",
940 varname, actual_prec, actual_tol, cr, bpv);
941 }
942
943 /* Free... */
944 zfp_field_free(field);
945 stream_close(stream);
946 zfp_stream_close(zfp);
947 free(buffer);
948}
949#endif
950
951/*****************************************************************************/
952
953#ifdef ZSTD
954void compress_zstd(
955 const char *varname,
956 float *array,
957 const size_t n,
958 const int decompress,
959 const int level,
960 FILE *inout) {
961
962 /* Get buffer sizes... */
963 const size_t uncomprLen = n * sizeof(float);
964 size_t compsize, comprLen = ZSTD_compressBound(uncomprLen);
965
966 /* Allocate... */
967 char *compr = calloc(comprLen, 1);
968 if (!compr)
969 ERRMSG("Memory allocation failed!");
970 char *uncompr = (char *) array;
971
972 /* Read compressed stream and decompress array... */
973 if (decompress) {
974 FREAD(&comprLen, size_t,
975 1,
976 inout);
977 FREAD(compr, unsigned char,
978 comprLen,
979 inout);
980 compsize = ZSTD_decompress(uncompr, uncomprLen, compr, comprLen);
981 if (ZSTD_isError(compsize) || compsize != uncomprLen)
982 ERRMSG("Decompression failed or size mismatch!");
983 LOG(2, "Read 3-D variable: %s (ZSTD, RATIO= %g)",
984 varname, ((double) uncomprLen) / (double) comprLen);
985 }
986
987 /* Compress array and output compressed stream... */
988 else {
989 compsize = ZSTD_compress(compr, comprLen, uncompr, uncomprLen, level);
990 if (ZSTD_isError(compsize)) {
991 ERRMSG("Compression failed!");
992 } else {
993 FWRITE(&compsize, size_t,
994 1,
995 inout);
996 FWRITE(compr, unsigned char,
997 compsize,
998 inout);
999 }
1000 LOG(2, "Write 3-D variable: %s (ZSTD, RATIO= %g)",
1001 varname, ((double) uncomprLen) / (double) compsize);
1002 }
1003
1004 /* Free... */
1005 free(compr);
1006}
1007#endif
1008
1009/*****************************************************************************/
1010
1011double cos_sza(
1012 const double sec,
1013 const double lon,
1014 const double lat) {
1015
1016 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
1017 const double D = sec / 86400 - 0.5;
1018
1019 /* Geocentric apparent ecliptic longitude [rad]... */
1020 const double g = DEG2RAD(357.529 + 0.98560028 * D);
1021 const double q = 280.459 + 0.98564736 * D;
1022 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
1023
1024 /* Mean obliquity of the ecliptic [rad]... */
1025 const double e = DEG2RAD(23.439 - 0.00000036 * D);
1026
1027 /* Declination [rad]... */
1028 const double sindec = sin(e) * sin(L);
1029
1030 /* Right ascension [rad]... */
1031 const double ra = atan2(cos(e) * sin(L), cos(L));
1032
1033 /* Greenwich Mean Sidereal Time [h]... */
1034 const double GMST = 18.697374558 + 24.06570982441908 * D;
1035
1036 /* Local Sidereal Time [h]... */
1037 const double LST = GMST + lon / 15;
1038
1039 /* Hour angle [rad]... */
1040 const double h = LST / 12 * M_PI - ra;
1041
1042 /* Convert latitude... */
1043 const double lat_help = DEG2RAD(lat);
1044
1045 /* Return cosine of solar zenith angle... */
1046 return sin(lat_help) * sindec + cos(lat_help) * sqrt(1 -
1047 SQR(sindec)) * cos(h);
1048}
1049
1050/*****************************************************************************/
1051
1053 const int year,
1054 const int mon,
1055 const int day,
1056 int *doy) {
1057
1058 const int
1059 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1060 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1061
1062 /* Get day of year... */
1063 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
1064 *doy = d0l[mon - 1] + day - 1;
1065 else
1066 *doy = d0[mon - 1] + day - 1;
1067}
1068
1069/*****************************************************************************/
1070
1071#ifdef DD
1073 const ctl_t *ctl,
1074 const dd_t *dd,
1075 atm_t *atm,
1076 const int init) {
1077
1078 /* Set timer... */
1079 SELECT_TIMER("DD_ASSIGN_SUBDOMAINS", "DD");
1080
1081 /* Get MPI rank... */
1082 int rank;
1083 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
1084
1085 /* Determine owned core subdomain in index space... */
1086 const int zonal_rank = rank / ctl->dd_subdomains_meridional;
1087 const int merid_rank = rank % ctl->dd_subdomains_meridional;
1088
1089 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
1090 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
1091
1092 const int ix0 = zonal_rank * nx_block;
1093 const int iy0 = merid_rank * ny_block;
1094
1095 const int ix1 = ix0 + nx_block
1096 + (zonal_rank == ctl->dd_subdomains_zonal - 1 ?
1097 dd->nx_glob - ctl->dd_subdomains_zonal * nx_block : 0);
1098
1099 const int iy1 = iy0 + ny_block
1100 + (merid_rank == ctl->dd_subdomains_meridional - 1 ?
1101 dd->ny_glob - ctl->dd_subdomains_meridional * ny_block : 0);
1102
1103 /* Loop over particles... */
1104#ifdef _OPENACC
1105#pragma acc update device(dd->nx_glob, dd->ny_glob, \
1106 dd->lon_glob[:dd->nx_glob], \
1107 dd->lat_glob[:dd->ny_glob])
1108#pragma acc data present(atm, ctl, dd)
1109#pragma acc parallel loop independent gang vector
1110#endif
1111 for (int ip = 0; ip < atm->np; ip++) {
1112
1113 /* Skip already invalid particles... */
1114 if (!init && (int) atm->q[ctl->qnt_subdomain][ip] == -1)
1115 continue;
1116
1117 /* Normalize coordinates... */
1118 double lon = atm->lon[ip];
1119 double lat = atm->lat[ip];
1120 dd_normalize_lon_lat(dd, &lon, &lat);
1121
1122 /* Check whether particle is inside owned core subdomain... */
1123 const int ix = locate_reg(dd->lon_glob, dd->nx_glob, lon);
1124 const int iy = locate_irr(dd->lat_glob, dd->ny_glob, lat);
1125 const int inside = (ix >= ix0 && ix < ix1 && iy >= iy0 && iy < iy1);
1126
1127 /* Init... */
1128 if (init) {
1129 atm->q[ctl->qnt_subdomain][ip] = inside ? rank : -1;
1130 atm->q[ctl->qnt_destination][ip] = inside ? rank : -1;
1131 }
1132
1133 /* Reassign... */
1134 else {
1135 atm->q[ctl->qnt_destination][ip] =
1136 inside ? rank : dd_calc_subdomain_from_coords(ctl, dd, lon, lat);
1137 }
1138 }
1139}
1140#endif
1141
1142/*****************************************************************************/
1143
1144#ifdef DD
1145void dd_atm2particles(
1146 const ctl_t *ctl,
1147 cache_t *cache,
1148 atm_t *atm,
1149 particle_t *particles,
1150 const int npart) {
1151
1152 /* Set timer... */
1153 SELECT_TIMER("DD_ATM2PARTICLES", "DD");
1154
1155 /* Check if particles are present... */
1156 if (npart == 0)
1157 return;
1158
1159 int rank;
1160 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
1161
1162 /* Select the particles that will be send... */
1163#ifdef _OPENACC
1164#pragma acc enter data create(npart, particles[:npart])
1165#pragma acc update device(npart, particles[:npart])
1166#pragma acc parallel loop present(atm, ctl, particles, cache, npart)
1167#endif
1168 for (int ip = atm->np; ip < atm->np + npart; ip++)
1169 if (((int) (atm->q[ctl->qnt_destination][ip]) != rank)
1170 && ((int) (atm->q[ctl->qnt_destination][ip]) >= 0)
1171 && ((int) atm->q[ctl->qnt_subdomain][ip] >= 0)) {
1172
1173 particles[ip - atm->np].time = atm->time[ip];
1174 particles[ip - atm->np].lon = atm->lon[ip];
1175 particles[ip - atm->np].lat = atm->lat[ip];
1176 particles[ip - atm->np].p = atm->p[ip];
1177 for (int iq = 0; iq < ctl->nq; iq++)
1178 particles[ip - atm->np].q[iq] = atm->q[iq][ip];
1179
1180 atm->q[ctl->qnt_subdomain][ip] = -1;
1181 cache->dt[ip] = 0;
1182 }
1183#ifdef _OPENACC
1184#pragma acc update host( particles[:npart])
1185#pragma acc exit data delete(npart, particles)
1186#endif
1187}
1188#endif
1189
1190/*****************************************************************************/
1191
1192#ifdef DD
1194 const ctl_t *ctl,
1195 const dd_t *dd,
1196 double lon,
1197 double lat) {
1198
1199 /* Normalize coordinates... */
1200 dd_normalize_lon_lat(dd, &lon, &lat);
1201
1202 /* Get grid index... */
1203 const int ix = locate_reg(dd->lon_glob, dd->nx_glob, lon);
1204 const int iy = locate_irr(dd->lat_glob, dd->ny_glob, lat);
1205
1206 /* Get zonal subdomain index... */
1207 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
1208 int zonal_rank = ix / nx_block;
1209 if (zonal_rank >= ctl->dd_subdomains_zonal)
1210 zonal_rank = ctl->dd_subdomains_zonal - 1;
1211
1212 /* Get meridional subdomain index... */
1213 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
1214 int merid_rank = iy / ny_block;
1215 if (merid_rank >= ctl->dd_subdomains_meridional)
1216 merid_rank = ctl->dd_subdomains_meridional - 1;
1217
1218 /* Return rank... */
1219 return zonal_rank * ctl->dd_subdomains_meridional + merid_rank;
1220}
1221#endif
1222
1223/*****************************************************************************/
1224
1225#ifdef DD
1227 const ctl_t *ctl,
1228 const dd_t *dd,
1229 particle_t **particles,
1230 int *npart,
1231 int *capacity) {
1232
1233 /* Set timer... */
1234 SELECT_TIMER("DD_COMMUNICATE_PARTICLES", "DD");
1235
1236 int rank, size;
1237 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
1238 MPI_Comm_size(MPI_COMM_WORLD, &size);
1239
1240 int *send_counts, *recv_counts;
1241 int *send_displs, *recv_displs;
1242 int *offsets;
1243
1244 particle_t *sendbuf = NULL;
1245 particle_t *recvbuf = NULL;
1246
1247 ALLOC(send_counts, int,
1248 size);
1249 ALLOC(recv_counts, int,
1250 size);
1251 ALLOC(send_displs, int,
1252 size);
1253 ALLOC(recv_displs, int,
1254 size);
1255 ALLOC(offsets, int,
1256 size);
1257
1258 /* Count particles per destination rank... */
1259 for (int ip = 0; ip < *npart; ip++) {
1260 const int dest = (int) (*particles)[ip].q[ctl->qnt_destination];
1261 if (dest == rank)
1262 continue;
1263 if (dest < 0 || dest >= size)
1264 ERRMSG("Invalid destination rank!");
1265 send_counts[dest]++;
1266 }
1267
1268 /* Compute send displacements... */
1269 int nsend = 0;
1270 for (int i = 0; i < size; i++) {
1271 send_displs[i] = nsend;
1272 nsend += send_counts[i];
1273 }
1274
1275 /* Exchange particle counts... */
1276 MPI_Alltoall(send_counts, 1, MPI_INT,
1277 recv_counts, 1, MPI_INT, MPI_COMM_WORLD);
1278
1279 /* Compute receive displacements... */
1280 int nrecv = 0;
1281 for (int i = 0; i < size; i++) {
1282 recv_displs[i] = nrecv;
1283 nrecv += recv_counts[i];
1284 }
1285 if (nsend > 0)
1286 ALLOC(sendbuf, particle_t, nsend);
1287 if (nrecv > 0)
1288 ALLOC(recvbuf, particle_t, nrecv);
1289 for (int i = 0; i < size; i++)
1290 offsets[i] = send_displs[i];
1291
1292 /* Pack particles into send buffer... */
1293 for (int ip = 0; ip < *npart; ip++) {
1294 const int dest = (int) (*particles)[ip].q[ctl->qnt_destination];
1295 if (dest == rank)
1296 continue;
1297 memcpy(&sendbuf[offsets[dest]], &(*particles)[ip], sizeof(particle_t));
1298 offsets[dest]++;
1299 }
1300
1301 /* Exchange particle data... */
1302 MPI_Alltoallv(sendbuf,
1303 send_counts,
1304 send_displs,
1305 dd->MPI_Particle,
1306 recvbuf,
1307 recv_counts, recv_displs, dd->MPI_Particle, MPI_COMM_WORLD);
1308
1309 /* Resize particle buffer if necessary... */
1310 if (nrecv > *capacity) {
1311 const int newcap = nrecv + nrecv / 2 + 1;
1312 particle_t *tmp =
1313 realloc(*particles, (size_t) newcap * sizeof(particle_t));
1314 if (!tmp)
1315 ERRMSG("Out of memory!");
1316 *particles = tmp;
1317 *capacity = newcap;
1318 }
1319
1320 /* Copy received particles... */
1321 for (int ip = 0; ip < nrecv; ip++) {
1322 (*particles)[ip] = recvbuf[ip];
1323 (*particles)[ip].q[ctl->qnt_destination] = rank;
1324 (*particles)[ip].q[ctl->qnt_subdomain] = rank;
1325 }
1326 *npart = nrecv;
1327
1328 /* Free temporary buffers... */
1329 if (sendbuf)
1330 free(sendbuf);
1331 if (recvbuf)
1332 free(recvbuf);
1333 free(send_counts);
1334 free(recv_counts);
1335 free(send_displs);
1336 free(recv_displs);
1337 free(offsets);
1338}
1339#endif
1340
1341/*****************************************************************************/
1342
1343#ifdef DD
1344void dd_init(
1345 const ctl_t *ctl,
1346 dd_t *dd,
1347 atm_t *atm) {
1348
1349 /* Check if enough tasks are requested... */
1350 int size;
1351 MPI_Comm_size(MPI_COMM_WORLD, &size);
1352 if (size != ctl->dd_subdomains_meridional * ctl->dd_subdomains_zonal)
1353 ERRMSG("Number of tasks and subdomains is not identical!");
1354
1355 /* Register the MPI_Particle data type... */
1356 const MPI_Datatype types[5] =
1357 { MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE };
1358 const int blocklengths[5] = { 1, 1, 1, 1, NQ };
1359 const MPI_Aint displacements[5] =
1360 { offsetof(particle_t, time), offsetof(particle_t, p),
1361 offsetof(particle_t, lon), offsetof(particle_t, lat),
1362 offsetof(particle_t, q)
1363 };
1364 MPI_Type_create_struct(5, blocklengths, displacements, types,
1365 &dd->MPI_Particle);
1366 MPI_Type_commit(&dd->MPI_Particle);
1367
1368 /* Check if particles are in subdomain... */
1369 dd_assign_subdomains(ctl, dd, atm, 1);
1370}
1371#endif
1372
1373/*****************************************************************************/
1374
1375#ifdef DD
1377 const dd_t *dd,
1378 double *lon,
1379 double *lat) {
1380
1381 const double lon_min = (dd->lon_glob[0] < 0) ? -180.0 : 0.0;
1382
1383 /* Normalize longitude to match global grid convention... */
1384 *lon = FMOD(*lon - lon_min, 360.0);
1385 if (*lon < 0.0)
1386 *lon += 360.0;
1387 *lon += lon_min;
1388
1389 /* Wrap latitude across the poles and shift longitude... */
1390 if (*lat > 90.0) {
1391 *lat = 180.0 - *lat;
1392 *lon += 180.0;
1393 } else if (*lat < -90.0) {
1394 *lat = -180.0 - *lat;
1395 *lon += 180.0;
1396 }
1397
1398 /* Renormalize longitude after pole crossing... */
1399 *lon = FMOD(*lon - lon_min, 360.0);
1400 if (*lon < 0.0)
1401 *lon += 360.0;
1402 *lon += lon_min;
1403}
1404#endif
1405
1406/*****************************************************************************/
1407
1408#ifdef DD
1409void dd_particles2atm(
1410 const ctl_t *ctl,
1411 cache_t *cache,
1412 const particle_t *particles,
1413 const int npart,
1414 atm_t *atm) {
1415
1416 /* Set timer... */
1417 SELECT_TIMER("DD_PARTICLES2ATM", "DD");
1418
1419 /* Check if particles are present... */
1420 if (npart == 0)
1421 return;
1422
1423 /* Check number of particles... */
1424 if (atm->np + npart > NP)
1425 ERRMSG("Too many particles. Increase NP!");
1426
1427#ifdef _OPENACC
1428#pragma acc enter data create(npart, particles[:npart])
1429#pragma acc update device(particles[:npart], npart)
1430#pragma acc data present(atm, ctl, cache, particles, npart)
1431#pragma acc parallel loop
1432#endif
1433 for (int ip = atm->np; ip < atm->np + npart; ip++) {
1434 atm->time[ip] = particles[ip - atm->np].time;
1435 atm->lon[ip] = particles[ip - atm->np].lon;
1436 atm->lat[ip] = particles[ip - atm->np].lat;
1437 atm->p[ip] = particles[ip - atm->np].p;
1438 for (int iq = 0; iq < ctl->nq; iq++)
1439 atm->q[iq][ip] = particles[ip - atm->np].q[iq];
1440 cache->dt[ip] = ctl->dt_mod;
1441 }
1442#ifdef _OPENACC
1443#pragma acc exit data delete(npart, particles)
1444#endif
1445
1446 /* Reset size... */
1447 atm->np += npart;
1448#ifdef _OPENACC
1449#pragma acc update device(atm->np)
1450#endif
1451}
1452#endif
1453
1454/*****************************************************************************/
1455
1456#ifdef DD
1457void dd_sort(
1458 const ctl_t *ctl,
1459 const met_t *met0,
1460 atm_t *atm,
1461 dd_t *dd,
1462 int *npart) {
1463
1464 /* Set timer... */
1465 SELECT_TIMER("DD_SORT", "DD");
1466
1467 int rank;
1468 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
1469
1470 /* Allocate... */
1471 const int np = atm->np;
1472 double amax = (met0->nx * met0->ny + met0->ny) * met0->np + met0->np;
1473#ifdef _OPENACC
1474#pragma acc enter data create(amax)
1475#pragma acc update device(amax)
1476#pragma acc data present(ctl,met0,atm,dd,amax)
1477#endif
1478
1479 /* Get box index... */
1480#ifdef _OPENACC
1481#pragma acc parallel loop independent gang vector
1482#else
1483#pragma omp parallel for default(shared)
1484#endif
1485 for (int ip = 0; ip < np; ip++) {
1486 if ((int) atm->q[ctl->qnt_subdomain][ip] != -1) {
1487 if ((int) atm->q[ctl->qnt_destination][ip] == rank)
1488 dd->sort_key[ip] =
1489 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) *
1490 met0->ny + locate_irr(met0->lat, met0->ny, atm->lat[ip]))
1491 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
1492 else
1493 dd->sort_key[ip] = amax + 1;
1494 } else {
1495 dd->sort_key[ip] = amax + 2;
1496 }
1497 dd->perm[ip] = ip;
1498 }
1499
1500 /* Sorting... */
1501#ifdef THRUST
1502#ifdef _OPENACC
1503#pragma acc host_data use_device(dd->sort_key, dd->perm)
1504#endif
1505 thrustSortWrapper(dd->sort_key, np, dd->perm);
1506#else
1507 size_t *perm_sz = (size_t *) malloc((size_t) np * sizeof(size_t));
1508 if (perm_sz == NULL)
1509 ERRMSG("Out of memory!");
1510#ifdef _OPENACC
1511#pragma acc update self(dd->sort_key[0:np])
1512#endif
1513 gsl_sort_index(perm_sz, dd->sort_key, 1, (size_t) np);
1514 for (int ip = 0; ip < np; ++ip)
1515 dd->perm[ip] = (int) perm_sz[ip];
1516 free(perm_sz);
1517#ifdef _OPENACC
1518#pragma acc update device(dd->perm[0:np])
1519#endif
1520#endif
1521
1522 /* Sort data... */
1523 dd_sort_help(atm->time, dd, np);
1524 dd_sort_help(atm->p, dd, np);
1525 dd_sort_help(atm->lon, dd, np);
1526 dd_sort_help(atm->lat, dd, np);
1527 for (int iq = 0; iq < ctl->nq; iq++)
1528 dd_sort_help(atm->q[iq], dd, np);
1529
1530 /* Reset the size... */
1531 int nkeep = 0;
1532#ifdef _OPENACC
1533#pragma acc parallel loop reduction(+:nkeep) present(atm, ctl)
1534#endif
1535 for (int ip = 0; ip < np; ip++)
1536 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
1537 && ((int) atm->q[ctl->qnt_destination][ip] == rank))
1538 nkeep++;
1539
1540 /* Count number of particles to send... */
1541 int nsend = 0;
1542#ifdef _OPENACC
1543#pragma acc parallel loop reduction(+:nsend) present(atm, ctl)
1544#endif
1545 for (int ip = nkeep; ip < np; ip++)
1546 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
1547 && ((int) atm->q[ctl->qnt_destination][ip] != rank))
1548 nsend++;
1549
1550 /* Reset sizes... */
1551 *npart = nsend;
1552
1553 /* Count particles with -1 subdomain (these will be effectively lost) */
1554 int nlost = 0;
1555 for (int ip = 0; ip < np; ip++)
1556 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
1557 nlost++;
1558
1559 if (nlost > 0)
1560 WARN
1561 ("Rank %d: %d particles have subdomain index -1 and will be lost (kept: %d, to_send: %d, total_before: %d)",
1562 rank, nlost, nkeep, nsend, np);
1563
1564 atm->np = nkeep;
1565#ifdef _OPENACC
1566#pragma acc update device(atm->np)
1567#endif
1568
1569 /* Free... */
1570#ifdef _OPENACC
1571#pragma acc exit data delete(amax)
1572#endif
1573}
1574#endif
1575
1576/*****************************************************************************/
1577
1578#ifdef DD
1579void dd_sort_help(
1580 double *a,
1581 dd_t *dd,
1582 const int np) {
1583
1584 /* Reordering of array... */
1585#ifdef _OPENACC
1586#pragma acc data present(dd,a)
1587#pragma acc parallel loop independent gang vector
1588#else
1589#pragma omp parallel for default(shared)
1590#endif
1591 for (int ip = 0; ip < np; ip++)
1592 dd->tmp[ip] = a[dd->perm[ip]];
1593#ifdef _OPENACC
1594#pragma acc parallel loop independent gang vector
1595#else
1596#pragma omp parallel for default(shared)
1597#endif
1598 for (int ip = 0; ip < np; ip++)
1599 a[ip] = dd->tmp[ip];
1600}
1601#endif
1602
1603/*****************************************************************************/
1604
1606 const int year,
1607 const int doy,
1608 int *mon,
1609 int *day) {
1610
1611 const int
1612 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1613 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1614
1615 int i;
1616
1617 /* Get month and day... */
1618 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
1619 for (i = 11; i > 0; i--)
1620 if (d0l[i] <= doy)
1621 break;
1622 *mon = i + 1;
1623 *day = doy - d0l[i] + 1;
1624 } else {
1625 for (i = 11; i > 0; i--)
1626 if (d0[i] <= doy)
1627 break;
1628 *mon = i + 1;
1629 *day = doy - d0[i] + 1;
1630 }
1631}
1632
1633/*****************************************************************************/
1634
1636 double *fcReal,
1637 double *fcImag,
1638 const int n) {
1639
1640 double data[2 * EX];
1641
1642 /* Check size... */
1643 if (n > EX)
1644 ERRMSG("Too many data points!");
1645
1646 /* Allocate... */
1647 gsl_fft_complex_wavetable *wavetable =
1648 gsl_fft_complex_wavetable_alloc((size_t) n);
1649 gsl_fft_complex_workspace *workspace =
1650 gsl_fft_complex_workspace_alloc((size_t) n);
1651
1652 /* Set data (real, complex)... */
1653 for (int i = 0; i < n; i++) {
1654 data[2 * i] = fcReal[i];
1655 data[2 * i + 1] = fcImag[i];
1656 }
1657
1658 /* Calculate FFT... */
1659 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
1660
1661 /* Copy data... */
1662 for (int i = 0; i < n; i++) {
1663 fcReal[i] = data[2 * i];
1664 fcImag[i] = data[2 * i + 1];
1665 }
1666
1667 /* Free... */
1668 gsl_fft_complex_wavetable_free(wavetable);
1669 gsl_fft_complex_workspace_free(workspace);
1670}
1671
1672/*****************************************************************************/
1673
1675 const double z,
1676 const double lon,
1677 const double lat,
1678 double *x) {
1679
1680 const double radius = z + RE;
1681 const double latrad = DEG2RAD(lat);
1682 const double lonrad = DEG2RAD(lon);
1683 const double coslat = cos(latrad);
1684
1685 x[0] = radius * coslat * cos(lonrad);
1686 x[1] = radius * coslat * sin(lonrad);
1687 x[2] = radius * sin(latrad);
1688}
1689
1690/*****************************************************************************/
1691
1693 const ctl_t *ctl,
1694 const double t,
1695 const int direct,
1696 const char *metbase,
1697 const double dt_met,
1698 char *filename) {
1699
1700 char repl[LEN];
1701
1702 double t6, r;
1703
1704 int year, mon, day, hour, min, sec;
1705
1706 /* Round time to fixed intervals... */
1707 if (direct == -1)
1708 t6 = floor(t / dt_met) * dt_met;
1709 else
1710 t6 = ceil(t / dt_met) * dt_met;
1711
1712 /* Decode time... */
1713 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1714
1715 /* Set filename of MPTRAC meteo files... */
1716 if (ctl->met_clams == 0) {
1717 if (ctl->met_type == 0)
1718 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1719 else if (ctl->met_type == 1)
1720 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1721 else if (ctl->met_type == 2)
1722 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1723 else if (ctl->met_type == 3)
1724 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1725 else if (ctl->met_type == 4)
1726 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1727 else if (ctl->met_type == 5)
1728 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1729 else if (ctl->met_type == 7)
1730 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
1731 sprintf(repl, "%d", year);
1732 get_met_replace(filename, "YYYY", repl);
1733 sprintf(repl, "%02d", mon);
1734 get_met_replace(filename, "MM", repl);
1735 sprintf(repl, "%02d", day);
1736 get_met_replace(filename, "DD", repl);
1737 sprintf(repl, "%02d", hour);
1738 get_met_replace(filename, "HH", repl);
1739 }
1740
1741 /* Set filename of CLaMS meteo files... */
1742 else {
1743 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1744 sprintf(repl, "%d", year);
1745 get_met_replace(filename, "YYYY", repl);
1746 sprintf(repl, "%02d", year % 100);
1747 get_met_replace(filename, "YY", repl);
1748 sprintf(repl, "%02d", mon);
1749 get_met_replace(filename, "MM", repl);
1750 sprintf(repl, "%02d", day);
1751 get_met_replace(filename, "DD", repl);
1752 sprintf(repl, "%02d", hour);
1753 get_met_replace(filename, "HH", repl);
1754 }
1755}
1756
1757/*****************************************************************************/
1758
1760 char *orig,
1761 const char *search,
1762 const char *repl) {
1763
1764 char buffer[LEN];
1765
1766 /* Iterate... */
1767 for (int i = 0; i < 3; i++) {
1768
1769 /* Replace sub-string... */
1770 char *ch;
1771 if (!(ch = strstr(orig, search)))
1772 return;
1773 strncpy(buffer, orig, (size_t) (ch - orig));
1774 buffer[ch - orig] = 0;
1775 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1776 orig[0] = 0;
1777 strcpy(orig, buffer);
1778 }
1779}
1780
1781/*****************************************************************************/
1782
1784 const int met_tropo,
1785 ctl_t *ctl,
1786 const clim_t *clim,
1787 met_t *met,
1788 const double *lons,
1789 const int nx,
1790 const double *lats,
1791 const int ny,
1792 double *pt,
1793 double *zt,
1794 double *tt,
1795 double *qt,
1796 double *o3t,
1797 double *ps,
1798 double *zs) {
1799
1801
1802 ctl->met_tropo = met_tropo;
1803 read_met_tropo(ctl, clim, met);
1804#pragma omp parallel for default(shared) private(ci,cw)
1805 for (int ix = 0; ix < nx; ix++)
1806 for (int iy = 0; iy < ny; iy++) {
1807 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1808 &pt[iy * nx + ix], ci, cw, 1);
1809 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1810 &ps[iy * nx + ix], ci, cw, 0);
1811 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1812 &zs[iy * nx + ix], ci, cw, 0);
1813 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1814 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1815 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1816 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1817 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1818 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1819 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1820 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1821 }
1822}
1823
1824/*****************************************************************************/
1825
1827 const double *lons,
1828 const int nlon,
1829 const double *lats,
1830 const int nlat,
1831 const double lon,
1832 const double lat,
1833 double *lon2,
1834 double *lat2) {
1835
1836 /* Check longitude... */
1837 *lon2 = FMOD(lon, 360.);
1838 if (*lon2 < lons[0])
1839 *lon2 += 360;
1840 else if (*lon2 > lons[nlon - 1])
1841 *lon2 -= 360;
1842
1843 /* Check latitude... */
1844 *lat2 = lat;
1845 if (lats[0] < lats[nlat - 1])
1846 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
1847 else
1848 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
1849}
1850
1851/*****************************************************************************/
1852
1854 const met_t *met0,
1855 float heights0[EX][EY][EP],
1856 float array0[EX][EY][EP],
1857 const met_t *met1,
1858 float heights1[EX][EY][EP],
1859 float array1[EX][EY][EP],
1860 const double ts,
1861 const double height,
1862 const double lon,
1863 const double lat,
1864 double *var,
1865 int *ci,
1866 double *cw,
1867 const int init) {
1868
1869 if (init) {
1870
1871 /* Check longitude and latitude... */
1872 double lon2, lat2;
1873 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
1874 &lon2, &lat2);
1875
1876 /* Get horizontal indizes... */
1877 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
1878 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
1879
1880 /* Locate the vertical indizes for each edge of the column... */
1881 int ind[2][4];
1882 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1883 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1884
1885 /* Find minimum and maximum indizes... */
1886 ci[2] = ind[0][0];
1887 int k_max = ind[0][0];
1888 for (int i = 0; i < 2; i++)
1889 for (int j = 0; j < 4; j++) {
1890 if (ci[2] > ind[i][j])
1891 ci[2] = ind[i][j];
1892 if (k_max < ind[i][j])
1893 k_max = ind[i][j];
1894 }
1895
1896 /* Get weighting factors for time, longitude and latitude... */
1897 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1898 cw[0] = (lon2 - met0->lon[ci[0]]) /
1899 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1900 cw[1] = (lat2 - met0->lat[ci[1]]) /
1901 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1902
1903 /* Interpolate in time at the lowest level... */
1904 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1905 - heights0[ci[0]][ci[1]][ci[2]])
1906 + heights0[ci[0]][ci[1]][ci[2]];
1907 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1908 - heights0[ci[0]][ci[1] + 1][ci[2]])
1909 + heights0[ci[0]][ci[1] + 1][ci[2]];
1910 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1911 - heights0[ci[0] + 1][ci[1]][ci[2]])
1912 + heights0[ci[0] + 1][ci[1]][ci[2]];
1913 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1914 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1915 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1916
1917 /* Interpolate in latitude direction... */
1918 double height0 = cw[1] * (height01 - height00) + height00;
1919 double height1 = cw[1] * (height11 - height10) + height10;
1920
1921 /* Interpolate in longitude direction... */
1922 double height_bot = cw[0] * (height1 - height0) + height0;
1923
1924 /* Interpolate in time at the upper level... */
1925 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1926 - heights0[ci[0]][ci[1]][ci[2] + 1])
1927 + heights0[ci[0]][ci[1]][ci[2] + 1];
1928 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1929 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1930 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1931 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1932 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1933 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1934 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1935 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1936 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1937
1938 /* Interpolate in latitude direction... */
1939 height0 = cw[1] * (height01 - height00) + height00;
1940 height1 = cw[1] * (height11 - height10) + height10;
1941
1942 /* Interpolate in longitude direction... */
1943 double height_top = cw[0] * (height1 - height0) + height0;
1944
1945 /* Search at higher levels if height is not in box... */
1946 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1947 ((height_bot <= height) || (height_top > height))
1948 && (height_bot >= height) && (ci[2] < k_max))
1949 ||
1950 ((heights0[0][0][0] < heights0[0][0][1]) &&
1951 ((height_bot >= height) || (height_top < height))
1952 && (height_bot <= height) && (ci[2] < k_max))
1953 ) {
1954
1955 ci[2]++;
1956 height_bot = height_top;
1957
1958 /* Interpolate in time at the next level... */
1959 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1960 - heights0[ci[0]][ci[1]][ci[2] + 1])
1961 + heights0[ci[0]][ci[1]][ci[2] + 1];
1962 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1963 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1964 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1965 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1966 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1967 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1968 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1969 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1970 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1971
1972 /* Interpolate in latitude direction... */
1973 height0 = cw[1] * (height01 - height00) + height00;
1974 height1 = cw[1] * (height11 - height10) + height10;
1975
1976 /* Interpolate in longitude direction... */
1977 height_top = cw[0] * (height1 - height0) + height0;
1978 }
1979
1980 /* Get vertical weighting factors... */
1981 cw[2] = (height - height_bot)
1982 / (height_top - height_bot);
1983 }
1984
1985 /* Calculate the needed array values... */
1986 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1987 - array0[ci[0]][ci[1]][ci[2]])
1988 + array0[ci[0]][ci[1]][ci[2]];
1989 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1990 - array0[ci[0] + 1][ci[1]][ci[2]])
1991 + array0[ci[0] + 1][ci[1]][ci[2]];
1992 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1993 - array0[ci[0]][ci[1] + 1][ci[2]])
1994 + array0[ci[0]][ci[1] + 1][ci[2]];
1995 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1996 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1997 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1998 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1999 - array0[ci[0]][ci[1]][ci[2] + 1])
2000 + array0[ci[0]][ci[1]][ci[2] + 1];
2001 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2002 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2003 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2004 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2005 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2006 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2007 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2008 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2009 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2010
2011 const double array00 = cw[0] * (array100 - array000) + array000;
2012 const double array10 = cw[0] * (array110 - array010) + array010;
2013 const double array01 = cw[0] * (array101 - array001) + array001;
2014 const double array11 = cw[0] * (array111 - array011) + array011;
2015
2016 const double aux0 = cw[1] * (array10 - array00) + array00;
2017 const double aux1 = cw[1] * (array11 - array01) + array01;
2018
2019 /* Interpolate vertically... */
2020 *var = cw[2] * (aux1 - aux0) + aux0;
2021}
2022
2023/*****************************************************************************/
2024
2026 const met_t *met,
2027 float array[EX][EY][EP],
2028 const double p,
2029 const double lon,
2030 const double lat,
2031 double *var,
2032 int *ci,
2033 double *cw,
2034 const int init) {
2035
2036 /* Initialize interpolation... */
2037 if (init) {
2038
2039 /* Check longitude and latitude... */
2040 double lon2, lat2;
2041 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2042 &lon2, &lat2);
2043
2044 /* Get interpolation indices... */
2045 ci[0] = locate_irr(met->p, met->np, p);
2046 ci[1] = locate_reg(met->lon, met->nx, lon2);
2047 ci[2] = locate_irr(met->lat, met->ny, lat2);
2048
2049 /* Get interpolation weights... */
2050 cw[0] = (met->p[ci[0] + 1] - p)
2051 / (met->p[ci[0] + 1] - met->p[ci[0]]);
2052 cw[1] = (met->lon[ci[1] + 1] - lon2)
2053 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2054 cw[2] = (met->lat[ci[2] + 1] - lat2)
2055 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2056 }
2057
2058 /* Interpolate vertically... */
2059 const double aux00 =
2060 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
2061 + array[ci[1]][ci[2]][ci[0] + 1];
2062 const double aux01 =
2063 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
2064 array[ci[1]][ci[2] + 1][ci[0] + 1])
2065 + array[ci[1]][ci[2] + 1][ci[0] + 1];
2066 const double aux10 =
2067 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
2068 array[ci[1] + 1][ci[2]][ci[0] + 1])
2069 + array[ci[1] + 1][ci[2]][ci[0] + 1];
2070 const double aux11 =
2071 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
2072 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
2073 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
2074
2075 /* Interpolate horizontally... */
2076 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2077 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2078 *var = cw[1] * (aux0 - aux1) + aux1;
2079}
2080
2081/*****************************************************************************/
2082
2084 const met_t *met,
2085 float array[EX][EY],
2086 const double lon,
2087 const double lat,
2088 double *var,
2089 int *ci,
2090 double *cw,
2091 const int init) {
2092
2093 /* Initialize interpolation... */
2094 if (init) {
2095
2096 /* Check longitude and latitude... */
2097 double lon2, lat2;
2098 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2099 &lon2, &lat2);
2100
2101 /* Get interpolation indices... */
2102 ci[1] = locate_reg(met->lon, met->nx, lon2);
2103 ci[2] = locate_irr(met->lat, met->ny, lat2);
2104
2105 /* Get interpolation weights... */
2106 cw[1] = (met->lon[ci[1] + 1] - lon2)
2107 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2108 cw[2] = (met->lat[ci[2] + 1] - lat2)
2109 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2110 }
2111
2112 /* Set variables... */
2113 const double aux00 = array[ci[1]][ci[2]];
2114 const double aux01 = array[ci[1]][ci[2] + 1];
2115 const double aux10 = array[ci[1] + 1][ci[2]];
2116 const double aux11 = array[ci[1] + 1][ci[2] + 1];
2117
2118 /* Interpolate horizontally... */
2119 if (isfinite(aux00) && isfinite(aux01)
2120 && isfinite(aux10) && isfinite(aux11)) {
2121 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2122 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2123 *var = cw[1] * (aux0 - aux1) + aux1;
2124 } else {
2125 if (cw[2] < 0.5) {
2126 if (cw[1] < 0.5)
2127 *var = aux11;
2128 else
2129 *var = aux01;
2130 } else {
2131 if (cw[1] < 0.5)
2132 *var = aux10;
2133 else
2134 *var = aux00;
2135 }
2136 }
2137}
2138
2139/*****************************************************************************/
2140
2142 const met_t *met0,
2143 float array0[EX][EY][EP],
2144 const met_t *met1,
2145 float array1[EX][EY][EP],
2146 const double ts,
2147 const double p,
2148 const double lon,
2149 const double lat,
2150 double *var,
2151 int *ci,
2152 double *cw,
2153 const int init) {
2154
2155 double var0, var1;
2156
2157 /* Spatial interpolation... */
2158 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
2159 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
2160
2161 /* Get weighting factor... */
2162 const double wt = (met1->time - ts) / (met1->time - met0->time);
2163
2164 /* Interpolate... */
2165 *var = wt * (var0 - var1) + var1;
2166}
2167
2168/*****************************************************************************/
2169
2171 const met_t *met0,
2172 float array0[EX][EY],
2173 const met_t *met1,
2174 float array1[EX][EY],
2175 const double ts,
2176 const double lon,
2177 const double lat,
2178 double *var,
2179 int *ci,
2180 double *cw,
2181 const int init) {
2182
2183 double var0, var1;
2184
2185 /* Spatial interpolation... */
2186 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
2187 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
2188
2189 /* Get weighting factor... */
2190 const double wt = (met1->time - ts) / (met1->time - met0->time);
2191
2192 /* Interpolate... */
2193 if (isfinite(var0) && isfinite(var1))
2194 *var = wt * (var0 - var1) + var1;
2195 else if (wt < 0.5)
2196 *var = var1;
2197 else
2198 *var = var0;
2199}
2200
2201/*****************************************************************************/
2202
2204 const double time0,
2205 float array0[EX][EY],
2206 const double time1,
2207 float array1[EX][EY],
2208 const double lons[EX],
2209 const double lats[EY],
2210 const int nlon,
2211 const int nlat,
2212 const double time,
2213 const double lon,
2214 const double lat,
2215 const int method,
2216 double *var,
2217 double *sigma) {
2218
2219 double mean = 0;
2220
2221 int n = 0;
2222
2223 /* Check longitude and latitude... */
2224 double lon2, lat2;
2225 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
2226
2227 /* Get indices... */
2228 const int ix = locate_reg(lons, (int) nlon, lon2);
2229 const int iy = locate_irr(lats, (int) nlat, lat2);
2230
2231 /* Calculate standard deviation... */
2232 *sigma = 0;
2233 for (int dx = 0; dx < 2; dx++)
2234 for (int dy = 0; dy < 2; dy++) {
2235 if (isfinite(array0[ix + dx][iy + dy])) {
2236 mean += array0[ix + dx][iy + dy];
2237 *sigma += SQR(array0[ix + dx][iy + dy]);
2238 n++;
2239 }
2240 if (isfinite(array1[ix + dx][iy + dy])) {
2241 mean += array1[ix + dx][iy + dy];
2242 *sigma += SQR(array1[ix + dx][iy + dy]);
2243 n++;
2244 }
2245 }
2246 if (n > 0)
2247 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
2248
2249 /* Linear interpolation... */
2250 if (method == 1 && isfinite(array0[ix][iy])
2251 && isfinite(array0[ix][iy + 1])
2252 && isfinite(array0[ix + 1][iy])
2253 && isfinite(array0[ix + 1][iy + 1])
2254 && isfinite(array1[ix][iy])
2255 && isfinite(array1[ix][iy + 1])
2256 && isfinite(array1[ix + 1][iy])
2257 && isfinite(array1[ix + 1][iy + 1])) {
2258
2259 const double aux00 = LIN(lons[ix], array0[ix][iy],
2260 lons[ix + 1], array0[ix + 1][iy], lon2);
2261 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
2262 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2263 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2264
2265 const double aux10 = LIN(lons[ix], array1[ix][iy],
2266 lons[ix + 1], array1[ix + 1][iy], lon2);
2267 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
2268 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2269 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2270
2271 *var = LIN(time0, aux0, time1, aux1, time);
2272 }
2273
2274 /* Nearest neighbor interpolation... */
2275 else {
2276 const double aux00 = NN(lons[ix], array0[ix][iy],
2277 lons[ix + 1], array0[ix + 1][iy], lon2);
2278 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
2279 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2280 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2281
2282 const double aux10 = NN(lons[ix], array1[ix][iy],
2283 lons[ix + 1], array1[ix + 1][iy], lon2);
2284 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
2285 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2286 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2287
2288 *var = NN(time0, aux0, time1, aux1, time);
2289 }
2290}
2291
2292/*****************************************************************************/
2293
2295 const double jsec,
2296 int *year,
2297 int *mon,
2298 int *day,
2299 int *hour,
2300 int *min,
2301 int *sec,
2302 double *remain) {
2303
2304 struct tm t0, *t1;
2305
2306 t0.tm_year = 100;
2307 t0.tm_mon = 0;
2308 t0.tm_mday = 1;
2309 t0.tm_hour = 0;
2310 t0.tm_min = 0;
2311 t0.tm_sec = 0;
2312
2313 const time_t jsec0 = (time_t) jsec + timegm(&t0);
2314 t1 = gmtime(&jsec0);
2315
2316 *year = t1->tm_year + 1900;
2317 *mon = t1->tm_mon + 1;
2318 *day = t1->tm_mday;
2319 *hour = t1->tm_hour;
2320 *min = t1->tm_min;
2321 *sec = t1->tm_sec;
2322 *remain = jsec - floor(jsec);
2323}
2324
2325/*****************************************************************************/
2326
2328 const double kz[EP],
2329 const double kw[EP],
2330 const int nk,
2331 const double p) {
2332
2333 /* Check number of data points... */
2334 if (nk < 2)
2335 return 1.0;
2336
2337 /* Get altitude... */
2338 const double z = Z(p);
2339
2340 /* Get weighting factor... */
2341 if (z < kz[0])
2342 return kw[0];
2343 else if (z > kz[nk - 1])
2344 return kw[nk - 1];
2345 else {
2346 const int idx = locate_irr(kz, nk, z);
2347 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
2348 }
2349}
2350
2351/*****************************************************************************/
2352
2354 const double t,
2355 const double h2o) {
2356
2357 /*
2358 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
2359 and water vapor volume mixing ratio [1].
2360
2361 Reference: https://en.wikipedia.org/wiki/Lapse_rate
2362 */
2363
2364 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
2365
2366 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
2367}
2368
2369/*****************************************************************************/
2370
2372 ctl_t *ctl) {
2373
2374 if (0 == ctl->met_press_level_def) {
2375
2376 ERRMSG
2377 ("MET_PRESS_LEVEL_DEF=0 is disabled. Use 3 for the extended L137 set.");
2378
2379 } else if (1 == ctl->met_press_level_def) {
2380
2381 ERRMSG
2382 ("MET_PRESS_LEVEL_DEF=1 is disabled. Use 4 for the extended L91 set.");
2383
2384 } else if (2 == ctl->met_press_level_def) {
2385
2386 ERRMSG
2387 ("MET_PRESS_LEVEL_DEF=2 is disabled. Use 5 for the extended L60 set.");
2388
2389 } else if (3 == ctl->met_press_level_def) {
2390
2391 ctl->met_np = 147;
2392
2393 const double press[147] = {
2394 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
2395 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
2396 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
2397 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
2398 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2399 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
2400 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
2401 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
2402 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
2403 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
2404 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
2405 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
2406 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
2407 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
2408 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
2409 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
2410 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
2411 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
2412 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
2413 1031.97,
2414 1035.09, 1038.21, 1041.33, 1044.45
2415 };
2416
2417 for (int ip = 0; ip < ctl->met_np; ip++)
2418 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2419
2420 } else if (4 == ctl->met_press_level_def) {
2421
2422 ctl->met_np = 101;
2423
2424 const double press[101] = {
2425 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
2426 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
2427 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
2428 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
2429 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
2430 113.6382,
2431 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
2432 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
2433 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2434 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2435 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2436 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2437 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2438 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
2439 1028.85, 1031.97,
2440 1035.09, 1038.21, 1041.33, 1044.45
2441 };
2442
2443 for (int ip = 0; ip < ctl->met_np; ip++)
2444 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2445
2446 } else if (5 == ctl->met_press_level_def) {
2447
2448 ctl->met_np = 62;
2449
2450 const double press[62] = {
2451 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2452 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2453 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2454 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2455 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2456 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2457 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2458 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
2459 1044.45
2460 };
2461
2462 for (int ip = 0; ip < ctl->met_np; ip++)
2463 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2464
2465 } else if (6 == ctl->met_press_level_def) {
2466
2467 ctl->met_np = 137;
2468
2469 const double press[137] = {
2470 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
2471 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
2472 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
2473 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
2474 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
2475 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2476 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
2477 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
2478 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
2479 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
2480 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
2481 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
2482 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
2483 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
2484 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
2485 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
2486 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
2487 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
2488 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
2489 1030.06, 1037.25, 1044.45
2490 };
2491
2492 for (int ip = 0; ip < ctl->met_np; ip++)
2493 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2494
2495 } else if (7 == ctl->met_press_level_def) {
2496
2497 ctl->met_np = 59;
2498
2499 const double press[59] = {
2500 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2501 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2502 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2503 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2504 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2505 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2506 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2507 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2508 1028.53, 1046.13
2509 };
2510
2511 for (int ip = 0; ip < ctl->met_np; ip++)
2512 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2513
2514 } else {
2515 ERRMSG("Use values between 3 and 7.");
2516 }
2517
2518 if (ctl->met_np > EP)
2519 ERRMSG("Recompile with larger EP to use this pressure level definition!");
2520}
2521
2522/*****************************************************************************/
2523
2525 const double *xx,
2526 const int n,
2527 const double x) {
2528
2529 int ilo = 0;
2530 int ihi = n - 1;
2531 int i = (ihi + ilo) >> 1;
2532
2533 if (xx[i] < xx[i + 1])
2534 while (ihi > ilo + 1) {
2535 i = (ihi + ilo) >> 1;
2536 if (xx[i] > x)
2537 ihi = i;
2538 else
2539 ilo = i;
2540 } else
2541 while (ihi > ilo + 1) {
2542 i = (ihi + ilo) >> 1;
2543 if (xx[i] <= x)
2544 ihi = i;
2545 else
2546 ilo = i;
2547 }
2548
2549 return ilo;
2550}
2551
2552/*****************************************************************************/
2553
2555 const float *xx,
2556 const int n,
2557 const double x,
2558 const int ig) {
2559
2560 int ilo = 0;
2561 int ihi = n - 1;
2562 int i = (ihi + ilo) >> 1;
2563
2564 if ((xx[ig] <= x && x < xx[ig + 1]) || (xx[ig] >= x && x > xx[ig + 1]))
2565 return ig;
2566
2567 if (xx[i] < xx[i + 1])
2568 while (ihi > ilo + 1) {
2569 i = (ihi + ilo) >> 1;
2570 if (xx[i] > x)
2571 ihi = i;
2572 else
2573 ilo = i;
2574 } else
2575 while (ihi > ilo + 1) {
2576 i = (ihi + ilo) >> 1;
2577 if (xx[i] <= x)
2578 ihi = i;
2579 else
2580 ilo = i;
2581 }
2582
2583 return ilo;
2584}
2585
2586/*****************************************************************************/
2587
2589 const double *xx,
2590 const int n,
2591 const double x) {
2592
2593 /* Calculate index... */
2594 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2595
2596 /* Check range... */
2597 if (i < 0)
2598 return 0;
2599 else if (i > n - 2)
2600 return n - 2;
2601 else
2602 return i;
2603}
2604
2605/*****************************************************************************/
2606
2608 float profiles[EX][EY][EP],
2609 const int np,
2610 const int lon_ap_ind,
2611 const int lat_ap_ind,
2612 const double height_ap,
2613 int *ind) {
2614
2615 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2616 np, height_ap, 0);
2617 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2618 np, height_ap, ind[0]);
2619 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2620 np, height_ap, ind[1]);
2621 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2622 np, height_ap, ind[2]);
2623}
2624
2625/*****************************************************************************/
2626
2628 const ctl_t *ctl,
2629 const cache_t *cache,
2630 met_t *met0,
2631 met_t *met1,
2632 atm_t *atm) {
2633
2634 /* Set timer... */
2635 SELECT_TIMER("MODULE_ADVECT", "PHYSICS");
2636
2637 /* Use omega vertical velocity... */
2638 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2639
2640 /* Loop over particles... */
2641 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2642
2643 /* Init... */
2645 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2646 x[3] = { 0, 0, 0 };
2647
2648 /* Loop over integration nodes... */
2649 for (int i = 0; i < ctl->advect; i++) {
2650
2651 /* Set position... */
2652 if (i == 0) {
2653 dts = 0.0;
2654 x[0] = atm->lon[ip];
2655 x[1] = atm->lat[ip];
2656 x[2] = atm->p[ip];
2657 } else {
2658 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2659 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2660 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2661 x[2] = atm->p[ip] + dts * w[i - 1];
2662 }
2663 const double tm = atm->time[ip] + dts;
2664
2665 /* Interpolate meteo data on pressure levels... */
2666 if (ctl->advect_vert_coord == 0) {
2667 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2668 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2669 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2670 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2671 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2672 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2673 }
2674
2675 /* Interpolate meteo data on model levels... */
2676 else {
2677 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
2678 met1, met1->pl, met1->ul,
2679 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2680 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
2681 met1, met1->pl, met1->vl,
2682 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2683 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
2684 met1, met1->pl, met1->wl,
2685 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2686 }
2687
2688 /* Get mean wind... */
2689 double k = 1.0;
2690 if (ctl->advect == 2)
2691 k = (i == 0 ? 0.0 : 1.0);
2692 else if (ctl->advect == 4)
2693 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2694 um += k * u[i];
2695 vm += k * v[i];
2696 wm += k * w[i];
2697 }
2698
2699 /* Set new position... */
2700 atm->time[ip] += cache->dt[ip];
2701 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2702 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2703 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2704 atm->p[ip] += cache->dt[ip] * wm;
2705 }
2706 }
2707
2708 /* Use zeta or eta vertical velocity... */
2709 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
2710
2711 /* Select quantity index depending on coordinate... */
2712 const int qnt = (ctl->advect_vert_coord == 1
2713 ? ctl->qnt_zeta : ctl->qnt_eta);
2714
2715 /* Loop over particles... */
2716 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2717
2718 /* Convert pressure to vertical coordinate (zeta or eta)... */
2720 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
2721 met1, met1->pl, met1->zetal,
2722 atm->time[ip], atm->p[ip],
2723 atm->lon[ip], atm->lat[ip],
2724 &atm->q[qnt][ip], ci, cw, 1);
2725
2726 /* Init... */
2727 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
2728 wdotm = 0, x[3] = { 0, 0, 0 };
2729
2730 /* Loop over integration nodes (Runge–Kutta steps)... */
2731 for (int i = 0; i < ctl->advect; i++) {
2732
2733 /* Set position... */
2734 if (i == 0) {
2735 dts = 0.0;
2736 x[0] = atm->lon[ip];
2737 x[1] = atm->lat[ip];
2738 x[2] = atm->q[qnt][ip];
2739 } else {
2740 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2741 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2742 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2743 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
2744 }
2745
2746 const double tm = atm->time[ip] + dts;
2747
2748 /* Interpolate meteo data... */
2749 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
2750 met1, met1->zetal, met1->ul,
2751 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2752 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
2753 met1, met1->zetal, met1->vl,
2754 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2755 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
2756 met1, met1->zetal, met1->zeta_dotl,
2757 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
2758
2759 /* Compute Runge–Kutta weights... */
2760 double k = 1.0;
2761 if (ctl->advect == 2)
2762 k = (i == 0 ? 0.0 : 1.0);
2763 else if (ctl->advect == 4)
2764 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2765
2766 um += k * u[i];
2767 vm += k * v[i];
2768 wdotm += k * wdot[i];
2769 }
2770
2771 /* Update particle position... */
2772 atm->time[ip] += cache->dt[ip];
2773 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2774 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2775 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2776 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
2777
2778 /* Convert vertical coordinate (zeta or eta) back to pressure... */
2779 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
2780 met1, met1->zetal, met1->pl,
2781 atm->time[ip],
2782 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
2783 &atm->p[ip], ci, cw, 1);
2784 }
2785 }
2786}
2787
2788/*****************************************************************************/
2789
2791 const ctl_t *ctl,
2792 const cache_t *cache,
2793 met_t *met0,
2794 met_t *met1,
2795 atm_t *atm) {
2796
2797 /* Check parameters... */
2798 if (ctl->advect_vert_coord != 1)
2799 return;
2800
2801 /* Set timer... */
2802 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS");
2803
2804 /* Loop over particles... */
2805 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
2806
2807 /* Initialize pressure consistent with zeta... */
2809 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
2810 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2811 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2812 }
2813}
2814
2815/*****************************************************************************/
2816
2818 const ctl_t *ctl,
2819 const cache_t *cache,
2820 const clim_t *clim,
2821 met_t *met0,
2822 met_t *met1,
2823 atm_t *atm) {
2824
2825 /* Set timer... */
2826 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS");
2827
2828 /* Check quantity flags... */
2829 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2830 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2831 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2832 return;
2833
2834 /* Loop over particles... */
2835 PARTICLE_LOOP(0, atm->np, 1,
2836 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2837
2838 /* Check latitude and pressure range... */
2839 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2840 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2841 continue;
2842
2843 /* Check surface layer... */
2844 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2845 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2846
2847 /* Get surface pressure... */
2848 double ps;
2850 INTPOL_2D(ps, 1);
2851
2852 /* Check pressure... */
2853 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2854 continue;
2855
2856 /* Check height... */
2857 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2858 continue;
2859
2860 /* Check zeta range... */
2861 if (ctl->bound_zetas > 0) {
2862 double t;
2863 INTPOL_3D(t, 1);
2864 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2865 continue;
2866 }
2867
2868 /* Check planetary boundary layer... */
2869 if (ctl->bound_pbl) {
2870 double pbl;
2871 INTPOL_2D(pbl, 0);
2872 if (atm->p[ip] < pbl)
2873 continue;
2874 }
2875 }
2876
2877 /* Set mass and volume mixing ratio... */
2878 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2879 atm->q[ctl->qnt_m][ip] =
2880 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2881 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2882 atm->q[ctl->qnt_vmr][ip] =
2883 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2884
2885 /* Set CFC-10 volume mixing ratio... */
2886 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2887 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2888
2889 /* Set CFC-11 volume mixing ratio... */
2890 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2891 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2892
2893 /* Set CFC-12 volume mixing ratio... */
2894 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2895 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2896
2897 /* Set N2O volume mixing ratio... */
2898 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2899 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2900
2901 /* Set SF6 volume mixing ratio... */
2902 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2903 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2904
2905 /* Set age of air... */
2906 if (ctl->qnt_aoa >= 0)
2907 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2908 }
2909}
2910
2911/*****************************************************************************/
2912
2914 const ctl_t *ctl,
2915 met_t *met0,
2916 met_t *met1,
2917 atm_t *atm,
2918 const double tt) {
2919
2920 /* Check quantities... */
2921 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
2922 return;
2923 if (ctl->molmass <= 0)
2924 ERRMSG("Molar mass is not defined!");
2925
2926 /* Set timer... */
2927 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS");
2928
2929 /* Allocate... */
2930 const int ensemble_mode = (ctl->nens > 0);
2931 const int np = atm->np;
2932 const int nz = ctl->chemgrid_nz;
2933 const int nx = ctl->chemgrid_nx;
2934 const int ny = ctl->chemgrid_ny;
2935 const int ngrid = nx * ny * nz;
2936 const int nens = ensemble_mode ? ctl->nens : 1;
2937
2938 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2939 double *restrict const press =
2940 (double *) malloc((size_t) nz * sizeof(double));
2941 double *restrict const mass =
2942 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
2943 double *restrict const area =
2944 (double *) malloc((size_t) ny * sizeof(double));
2945 double *restrict const lon =
2946 (double *) malloc((size_t) nx * sizeof(double));
2947 double *restrict const lat =
2948 (double *) malloc((size_t) ny * sizeof(double));
2949
2950 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2951 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2952 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2953
2954 /* Set grid box size... */
2955 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2956 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2957 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2958
2959 /* Set vertical coordinates... */
2960#ifdef _OPENACC
2961#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])
2962#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2963#pragma acc parallel loop independent gang vector
2964#else
2965#pragma omp parallel for default(shared)
2966#endif
2967 for (int iz = 0; iz < nz; iz++) {
2968 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2969 press[iz] = P(z[iz]);
2970 }
2971
2972 /* Set time interval for output... */
2973 const double t0 = tt - 0.5 * ctl->dt_mod;
2974 const double t1 = tt + 0.5 * ctl->dt_mod;
2975
2976 /* Get indices... */
2977#ifdef _OPENACC
2978#pragma acc parallel loop independent gang vector
2979#else
2980#pragma omp parallel for default(shared)
2981#endif
2982 for (int ip = 0; ip < np; ip++) {
2983 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2984 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2985 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2986 if (atm->time[ip] < t0 || atm->time[ip] > t1
2987 || ixs[ip] < 0 || ixs[ip] >= nx
2988 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2989 izs[ip] = -1;
2990 }
2991
2992 /* Set horizontal coordinates... */
2993#ifdef _OPENACC
2994#pragma acc parallel loop independent gang vector
2995#else
2996#pragma omp parallel for default(shared)
2997#endif
2998 for (int ix = 0; ix < nx; ix++)
2999 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3000
3001#ifdef _OPENACC
3002#pragma acc parallel loop independent gang vector
3003#else
3004#pragma omp parallel for default(shared)
3005#endif
3006 for (int iy = 0; iy < ny; iy++) {
3007 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3008 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3009 }
3010
3011 /* Get mass per grid box... */
3012#ifdef _OPENACC
3013#pragma acc parallel loop independent gang vector
3014#endif
3015 for (int ip = 0; ip < np; ip++) {
3016 if (izs[ip] >= 0) {
3017 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3018 if (ensemble_mode) {
3019 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3020 mass_idx += ens * ngrid;
3021 }
3022#ifdef _OPENACC
3023#pragma acc atomic update
3024#endif
3025 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
3026 }
3027 }
3028
3029 /* Assign grid data to air parcels ... */
3030#ifdef _OPENACC
3031#pragma acc parallel loop independent gang vector
3032#else
3033#pragma omp parallel for default(shared)
3034#endif
3035 for (int ip = 0; ip < np; ip++)
3036 if (izs[ip] >= 0) {
3037
3038 /* Interpolate temperature... */
3039 double temp;
3041 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
3042 press[izs[ip]],
3043 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
3044
3045 /* Set mass... */
3046 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3047 if (ensemble_mode) {
3048 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3049 mass_idx += ens * ngrid;
3050 }
3051
3052 /* Calculate volume mixing ratio... */
3053 const double m = mass[mass_idx];
3054 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
3055 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
3056 }
3057
3058 /* Free... */
3059#ifdef _OPENACC
3060#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
3061#endif
3062 free(mass);
3063 free(lon);
3064 free(lat);
3065 free(area);
3066 free(z);
3067 free(press);
3068 free(ixs);
3069 free(iys);
3070 free(izs);
3071}
3072
3073/*****************************************************************************/
3074
3076 const ctl_t *ctl,
3077 const cache_t *cache,
3078 const clim_t *clim,
3079 met_t *met0,
3080 met_t *met1,
3081 atm_t *atm) {
3082
3083 /* Set timer... */
3084 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS");
3085
3086 /* Loop over particles... */
3087 PARTICLE_LOOP(0, atm->np, 0,
3088 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3089
3090 /* Set H2O and O3 using meteo data... */
3092 if (ctl->qnt_Ch2o >= 0) {
3093 double h2o;
3094 INTPOL_3D(h2o, 1);
3095 SET_ATM(qnt_Ch2o, h2o);
3096 }
3097 if (ctl->qnt_Co3 >= 0) {
3098 double o3;
3099 INTPOL_3D(o3, 1);
3100 SET_ATM(qnt_Co3, o3);
3101 }
3102
3103 /* Set radical species... */
3104 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
3105 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3106 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
3107 atm->lat[ip], atm->p[ip]));
3108 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
3109 atm->lat[ip], atm->p[ip]));
3110 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
3111 atm->lat[ip], atm->p[ip]));
3112 }
3113}
3114
3115/*****************************************************************************/
3116
3118 const ctl_t *ctl,
3119 cache_t *cache,
3120 met_t *met0,
3121 met_t *met1,
3122 atm_t *atm) {
3123
3124 /* Set timer... */
3125 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS");
3126
3127 /* Create random numbers... */
3128 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
3129
3130 /* Loop over particles... */
3131 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3132
3133 /* Interpolate surface pressure... */
3134 double ps;
3136 INTPOL_2D(ps, 1);
3137
3138 /* Initialize pressure range for vertical mixing... */
3139 double pbot = ps, ptop = ps;
3140
3141 /* Mixing in the PBL... */
3142 if (ctl->conv_mix_pbl) {
3143
3144 /* Interpolate PBL... */
3145 double pbl;
3146 INTPOL_2D(pbl, 0);
3147
3148 /* Set pressure range... */
3149 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
3150 }
3151
3152 /* Convective mixing... */
3153 if (ctl->conv_cape >= 0) {
3154
3155 /* Interpolate CAPE, CIN, and equilibrium level... */
3156 double cape, cin, pel;
3157 INTPOL_2D(cape, 0);
3158 INTPOL_2D(cin, 0);
3159 INTPOL_2D(pel, 0);
3160
3161 /* Set pressure range... */
3162 if (isfinite(cape) && cape >= ctl->conv_cape
3163 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
3164 ptop = GSL_MIN(ptop, pel);
3165 }
3166
3167 /* Apply vertical mixing... */
3168 if (ptop != pbot && atm->p[ip] >= ptop) {
3169
3170 /* Get density range... */
3171 double tbot, ttop;
3172 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
3173 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
3174 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
3175 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
3176 const double rhobot = pbot / tbot;
3177 const double rhotop = ptop / ttop;
3178
3179 /* Get new density... */
3180 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
3181
3182 /* Get pressure... */
3183 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
3184 }
3185 }
3186}
3187
3188/*****************************************************************************/
3189
3190#ifdef DD
3191void module_dd(
3192 const ctl_t *ctl,
3193 cache_t *cache,
3194 dd_t *dd,
3195 atm_t *atm,
3196 met_t **met) {
3197
3198 /* Set timer... */
3199 SELECT_TIMER("MODULE_DD", "DD");
3200
3201 /* Initialize particles locally... */
3202 int npart = 0, capacity = 0;
3203 particle_t *particles = NULL;
3204
3205 /* Assign particles to new subdomains... */
3206 dd_assign_subdomains(ctl, dd, atm, 0);
3207
3208 /* Sort particles according to location and target rank... */
3209 dd_sort(ctl, *met, atm, dd, &npart);
3210
3211 /* Ensure particle buffer is large enough for outgoing particles... */
3212 if (npart > capacity) {
3213 const int newcap = npart + npart / 2 + 1;
3214 particle_t *tmp =
3215 realloc(particles, (size_t) newcap * sizeof(particle_t));
3216 if (!tmp)
3217 ERRMSG("Out of memory!");
3218 particles = tmp;
3219 capacity = newcap;
3220 }
3221
3222 /* Transform from struct of array to array of struct... */
3223 dd_atm2particles(ctl, cache, atm, particles, npart);
3224
3225 /* Perform the communication... */
3226 dd_communicate_particles(ctl, dd, &particles, &npart, &capacity);
3227
3228 /* Transform from array of struct to struct of array... */
3229 dd_particles2atm(ctl, cache, particles, npart, atm);
3230
3231 /* Free local particle array... */
3232 free(particles);
3233}
3234#endif
3235
3236/*****************************************************************************/
3237
3239 const ctl_t *ctl,
3240 const cache_t *cache,
3241 const clim_t *clim,
3242 atm_t *atm) {
3243
3244 /* Set timer... */
3245 SELECT_TIMER("MODULE_DECAY", "PHYSICS");
3246
3247 /* Check quantity flags... */
3248 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3249 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3250
3251 /* Loop over particles... */
3252 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
3253
3254 /* Get weighting factor... */
3255 const double w = tropo_weight(clim, atm, ip);
3256
3257 /* Set lifetime... */
3258 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
3259
3260 /* Calculate exponential decay... */
3261 const double aux = exp(-cache->dt[ip] / tdec);
3262 if (ctl->qnt_m >= 0) {
3263 if (ctl->qnt_mloss_decay >= 0)
3264 atm->q[ctl->qnt_mloss_decay][ip]
3265 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3266 atm->q[ctl->qnt_m][ip] *= aux;
3267 if (ctl->qnt_loss_rate >= 0)
3268 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
3269 }
3270 if (ctl->qnt_vmr >= 0)
3271 atm->q[ctl->qnt_vmr][ip] *= aux;
3272 }
3273}
3274
3275/*****************************************************************************/
3276
3278 const ctl_t *ctl,
3279 cache_t *cache,
3280 met_t *met0,
3281 met_t *met1,
3282 atm_t *atm) {
3283
3284 /* Set timer... */
3285 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS");
3286
3287 /* Create random numbers... */
3288 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3289
3290 /* Loop over particles... */
3291 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3292
3293 /* Get indices... */
3294 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
3295 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
3296 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
3297
3298 /* Get standard deviations of local wind data... */
3299 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
3300 for (int i = 0; i < 2; i++)
3301 for (int j = 0; j < 2; j++)
3302 for (int k = 0; k < 2; k++) {
3303 umean += met0->u[ix + i][iy + j][iz + k];
3304 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
3305 vmean += met0->v[ix + i][iy + j][iz + k];
3306 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
3307 wmean += met0->w[ix + i][iy + j][iz + k];
3308 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
3309
3310 umean += met1->u[ix + i][iy + j][iz + k];
3311 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
3312 vmean += met1->v[ix + i][iy + j][iz + k];
3313 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
3314 wmean += met1->w[ix + i][iy + j][iz + k];
3315 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
3316 }
3317 usig = usig / 16.f - SQR(umean / 16.f);
3318 usig = (usig > 0 ? sqrtf(usig) : 0);
3319 vsig = vsig / 16.f - SQR(vmean / 16.f);
3320 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
3321 wsig = wsig / 16.f - SQR(wmean / 16.f);
3322 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
3323
3324 /* Set temporal correlations for mesoscale fluctuations... */
3325 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
3326 const double r2 = sqrt(1 - r * r);
3327
3328 /* Calculate horizontal mesoscale wind fluctuations... */
3329 if (ctl->turb_mesox > 0) {
3330 cache->uvwp[ip][0] =
3331 (float) (r * cache->uvwp[ip][0] +
3332 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
3333 atm->lon[ip] +=
3334 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3335
3336 cache->uvwp[ip][1] =
3337 (float) (r * cache->uvwp[ip][1] +
3338 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
3339 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3340 }
3341
3342 /* Calculate vertical mesoscale wind fluctuations... */
3343 if (ctl->turb_mesoz > 0) {
3344 cache->uvwp[ip][2] =
3345 (float) (r * cache->uvwp[ip][2] +
3346 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
3347 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
3348 }
3349 }
3350}
3351
3352/*****************************************************************************/
3353
3355 const ctl_t *ctl,
3356 cache_t *cache,
3357 met_t *met0,
3358 met_t *met1,
3359 atm_t *atm) {
3360
3361 /* Set timer... */
3362 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS");
3363
3364 /* Create random numbers... */
3365 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3366
3367 /* Loop over particles... */
3368 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3369
3370 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
3371 tau_u = 300., tau_w = 100.;
3372
3373 /* Get surface and PBL pressure... */
3374 double pbl, ps;
3376 INTPOL_2D(ps, 1);
3377 INTPOL_2D(pbl, 0);
3378
3379 /* Boundary layer... */
3380 if (atm->p[ip] >= pbl) {
3381
3382 /* Calculate heights... */
3383 const double p = MIN(atm->p[ip], ps);
3384 const double zs = Z(ps);
3385 const double z = 1e3 * (Z(p) - zs);
3386 const double zi = 1e3 * (Z(pbl) - zs);
3387 const double zratio = z / zi;
3388
3389 /* Calculate friction velocity... */
3390 double ess, nss, h2o, t;
3391 INTPOL_2D(ess, 0);
3392 INTPOL_2D(nss, 0);
3393 INTPOL_3D(t, 1);
3394 INTPOL_3D(h2o, 0);
3395 const double rho = RHO(p, TVIRT(t, h2o));
3396 const double tau = sqrt(SQR(ess) + SQR(nss));
3397 const double ustar = sqrt(tau / rho);
3398
3399 /* Get surface sensible heat flux... */
3400 double shf;
3401 INTPOL_2D(shf, 1);
3402
3403 /* Stable or neutral conditions... */
3404 if (shf <= 0) {
3405
3406 /* Calcalute turbulent velocity variances... */
3407 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
3408 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
3409
3410 /* Calculate derivative dsig_w/dz... */
3411 dsigw_dz = -1.3 * ustar / zi;
3412
3413 /* Calcalute Lagrangian timescales... */
3414 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
3415 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
3416 }
3417
3418 /* Unstable conditions... */
3419 else {
3420
3421 /* Convective velocity... */
3422 const double wstar =
3423 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
3424
3425 /* Calcalute turbulent velocity variances... */
3426 sig_u = 1e-2
3427 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
3428 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
3429 * pow(zratio, 2.0 / 3.0)
3430 + (1.8 - 1.4 * zratio) * SQR(ustar));
3431
3432 /* Calculate derivative dsig_w/dz... */
3433 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
3434 * (0.8 *
3435 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
3436 - 1.8 * pow(zratio, 2.0 / 3.0)));
3437
3438 /* Calculate Lagrangian timescales... */
3439 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
3440 const double eps =
3441 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
3442 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
3443 tau_u = 2 * SQR(sig_u) / (C0 * eps);
3444 tau_w = 2 * SQR(sig_w) / (C0 * eps);
3445 }
3446 }
3447
3448 /* Set minimum values... */
3449 sig_u = MAX(sig_u, 0.25);
3450 sig_w = MAX(sig_w, 0.1);
3451 tau_u = MAX(tau_u, 300.);
3452 tau_w = MAX(tau_w, 100.);
3453
3454 /* Update perturbations... */
3455 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
3456 const double ru2 = sqrt(1.0 - SQR(ru));
3457 cache->uvwp[ip][0]
3458 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
3459 cache->uvwp[ip][1]
3460 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
3461
3462 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
3463 const double rw2 = sqrt(1.0 - SQR(rw));
3464 cache->uvwp[ip][2]
3465 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
3466 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
3467
3468 /* Calculate new air parcel position... */
3469 atm->lon[ip] +=
3470 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3471 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3472 atm->p[ip] +=
3473 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
3474 }
3475}
3476
3477/*****************************************************************************/
3478
3480 const ctl_t *ctl,
3481 cache_t *cache,
3482 const clim_t *clim,
3483 met_t *met0,
3484 met_t *met1,
3485 atm_t *atm) {
3486
3487 /* Set timer... */
3488 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS");
3489
3490 /* Create random numbers... */
3491 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3492
3493 /* Loop over particles... */
3494 PARTICLE_LOOP(0, atm->np, 1,
3495 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3496
3497 /* Get PBL and surface pressure... */
3498 double pbl, ps;
3500 INTPOL_2D(pbl, 1);
3501 INTPOL_2D(ps, 0);
3502
3503 /* Get weighting factors... */
3504 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
3505 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
3506 const double wstrat = 1.0 - wpbl - wtrop;
3507
3508 /* Set diffusivity... */
3509 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
3510 + wstrat * ctl->turb_dx_strat;
3511 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
3512 + wstrat * ctl->turb_dz_strat;
3513
3514 /* Horizontal turbulent diffusion... */
3515 if (dx > 0) {
3516 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
3517 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
3518 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
3519 }
3520
3521 /* Vertical turbulent diffusion... */
3522 if (dz > 0) {
3523 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
3524 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
3525 }
3526 }
3527}
3528
3529/*****************************************************************************/
3530
3532 const ctl_t *ctl,
3533 const cache_t *cache,
3534 met_t *met0,
3535 met_t *met1,
3536 atm_t *atm) {
3537
3538 /* Set timer... */
3539 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS");
3540
3541 /* Check quantity flags... */
3542 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3543 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3544
3545 /* Loop over particles... */
3546 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3547
3548 /* Get surface pressure... */
3549 double ps;
3551 INTPOL_2D(ps, 1);
3552
3553 /* Check whether particle is above the surface layer... */
3554 if (atm->p[ip] < ps - ctl->dry_depo_dp)
3555 continue;
3556
3557 /* Set depth of surface layer... */
3558 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
3559
3560 /* Calculate sedimentation velocity for particles... */
3561 double v_dep;
3562 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
3563
3564 /* Get temperature... */
3565 double t;
3566 INTPOL_3D(t, 1);
3567
3568 /* Set deposition velocity... */
3569 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3570 atm->q[ctl->qnt_rhop][ip]);
3571 }
3572
3573 /* Use explicit sedimentation velocity for gases... */
3574 else
3575 v_dep = ctl->dry_depo_vdep;
3576
3577 /* Calculate loss of mass based on deposition velocity... */
3578 const double aux = exp(-cache->dt[ip] * v_dep / dz);
3579 if (ctl->qnt_m >= 0) {
3580 if (ctl->qnt_mloss_dry >= 0)
3581 atm->q[ctl->qnt_mloss_dry][ip]
3582 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3583 atm->q[ctl->qnt_m][ip] *= aux;
3584 if (ctl->qnt_loss_rate >= 0)
3585 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
3586 }
3587 if (ctl->qnt_vmr >= 0)
3588 atm->q[ctl->qnt_vmr][ip] *= aux;
3589 }
3590}
3591
3592/*****************************************************************************/
3593
3595 const ctl_t *ctl,
3596 const cache_t *cache,
3597 const clim_t *clim,
3598 met_t *met0,
3599 met_t *met1,
3600 atm_t *atm) {
3601
3602 /* Set timer... */
3603 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS");
3604
3605 /* Check quantity flags... */
3606 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3607 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3608
3609 /* Parameter of SO2 correction... */
3610 const double a = 3.12541941e-06;
3611 const double b = -5.72532259e-01;
3612 const double low = pow(1. / a, 1. / b);
3613
3614 /* Loop over particles... */
3615 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3616
3617 /* Check whether particle is inside cloud... */
3618 double lwc, rwc;
3620 INTPOL_3D(lwc, 1);
3621 INTPOL_3D(rwc, 0);
3622 if (!(lwc > 0 || rwc > 0))
3623 continue;
3624
3625 /* Get temperature... */
3626 double t;
3627 INTPOL_3D(t, 0);
3628
3629 /* Get molecular density... */
3630 const double M = MOLEC_DENS(atm->p[ip], t);
3631
3632 /* Reaction rate (Berglen et al., 2004)... */
3633 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3634
3635 /* Henry constant of SO2... */
3636 const double H_SO2 =
3637 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3638 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3639
3640 /* Henry constant of H2O2... */
3641 const double H_h2o2 =
3642 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3643
3644 /* Correction factor for high SO2 concentration
3645 (if qnt_Cx is defined, the correction is switched on)... */
3646 double cor = 1.0;
3647 if (ctl->qnt_Cx >= 0)
3648 cor = atm->q[ctl->qnt_Cx][ip] >
3649 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3650
3651 const double h2o2 = H_h2o2
3652 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3653 * M * cor * 1000. / AVO; /* unit: mol/L */
3654
3655 /* Volume water content in cloud [m^3 m^(-3)]... */
3656 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3657 const double CWC = (lwc + rwc) * rho_air / 1e3;
3658
3659 /* Calculate exponential decay (Rolph et al., 1992)... */
3660 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3661 const double aux = exp(-cache->dt[ip] * rate_coef);
3662 if (ctl->qnt_m >= 0) {
3663 if (ctl->qnt_mloss_h2o2 >= 0)
3664 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3665 atm->q[ctl->qnt_m][ip] *= aux;
3666 if (ctl->qnt_loss_rate >= 0)
3667 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3668 }
3669 if (ctl->qnt_vmr >= 0)
3670 atm->q[ctl->qnt_vmr][ip] *= aux;
3671 }
3672}
3673
3674/*****************************************************************************/
3675
3677 const ctl_t *ctl,
3678 cache_t *cache,
3679 met_t *met0,
3680 met_t *met1,
3681 atm_t *atm) {
3682
3683 double t;
3684
3685 /* Set timer... */
3686 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS");
3687
3688 /* Save pressure... */
3689 if (ctl->isosurf == 1) {
3690 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
3691 cache->iso_var[ip] = atm->p[ip];
3692 }
3693 }
3694
3695 /* Save density... */
3696 else if (ctl->isosurf == 2) {
3697 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3699 INTPOL_3D(t, 1);
3700 cache->iso_var[ip] = atm->p[ip] / t;
3701 }
3702 }
3703
3704 /* Save potential temperature... */
3705 else if (ctl->isosurf == 3) {
3706 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3708 INTPOL_3D(t, 1);
3709 cache->iso_var[ip] = THETA(atm->p[ip], t);
3710 }
3711 }
3712
3713 /* Read balloon pressure data... */
3714 else if (ctl->isosurf == 4) {
3715
3716 /* Write info... */
3717 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3718
3719 /* Open file... */
3720 FILE *in;
3721 if (!(in = fopen(ctl->balloon, "r")))
3722 ERRMSG("Cannot open file!");
3723
3724 /* Read pressure time series... */
3725 char line[LEN];
3726 while (fgets(line, LEN, in))
3727 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3728 &(cache->iso_ps[cache->iso_n])) == 2)
3729 if ((++cache->iso_n) > NP)
3730 ERRMSG("Too many data points!");
3731
3732 /* Check number of points... */
3733 if (cache->iso_n < 1)
3734 ERRMSG("Could not read any data!");
3735
3736 /* Close file... */
3737 fclose(in);
3738
3739 /* Update of cache data on device... */
3740 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
3741 }
3742}
3743
3744/*****************************************************************************/
3745
3747 const ctl_t *ctl,
3748 const cache_t *cache,
3749 met_t *met0,
3750 met_t *met1,
3751 atm_t *atm) {
3752
3753 /* Set timer... */
3754 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS");
3755
3756 /* Loop over particles... */
3757 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
3758
3759 /* Init... */
3760 double t;
3762
3763 /* Restore pressure... */
3764 if (ctl->isosurf == 1)
3765 atm->p[ip] = cache->iso_var[ip];
3766
3767 /* Restore density... */
3768 else if (ctl->isosurf == 2) {
3769 INTPOL_3D(t, 1);
3770 atm->p[ip] = cache->iso_var[ip] * t;
3771 }
3772
3773 /* Restore potential temperature... */
3774 else if (ctl->isosurf == 3) {
3775 INTPOL_3D(t, 1);
3776 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3777 }
3778
3779 /* Interpolate pressure... */
3780 else if (ctl->isosurf == 4) {
3781 if (atm->time[ip] <= cache->iso_ts[0])
3782 atm->p[ip] = cache->iso_ps[0];
3783 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3784 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3785 else {
3786 const int idx =
3787 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3788 atm->p[ip] =
3789 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
3790 cache->iso_ps[idx + 1], atm->time[ip]);
3791 }
3792 }
3793 }
3794}
3795
3796/*****************************************************************************/
3797
3798#ifdef KPP
3799void module_kpp_chem(
3800 ctl_t *ctl,
3801 cache_t *cache,
3802 clim_t *clim,
3803 met_t *met0,
3804 met_t *met1,
3805 atm_t *atm) {
3806
3807 /* Set timer... */
3808 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS");
3809
3810 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
3811 double rtol[1] = { 1.0e-3 };
3812 double atol[1] = { 1.0 };
3813
3814 /* Loop over particles... */
3815#ifdef _OPENACC
3816#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
3817#endif
3818 PARTICLE_LOOP(0, atm->np, 1,
3819 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
3820
3821 /* Initialize... */
3822 double var[nvar], fix[nfix], rconst[nreact];
3823 for (int i = 0; i < nvar; i++)
3824 var[i] = 0.0;
3825 for (int i = 0; i < nfix; i++)
3826 fix[i] = 0.0;
3827 for (int i = 0; i < nreact; i++)
3828 rconst[i] = 0.0;
3829 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
3830
3831 /* Integrate... */
3832 double rpar[20];
3833 int ipar[20];
3834 for (int i = 0; i < 20; i++) {
3835 ipar[i] = 0;
3836 rpar[i] = 0.0;
3837 }
3838 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) */
3839 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
3840 ipar[3] = 4; /* choice of the method:Rodas3 */
3841 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
3842 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
3843
3844 /* Save results.. */
3845 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
3846 }
3847}
3848#endif
3849
3850/*****************************************************************************/
3851
3853 const ctl_t *ctl,
3854 const cache_t *cache,
3855 const clim_t *clim,
3856 met_t *met0,
3857 met_t *met1,
3858 atm_t *atm) {
3859
3860 /* Set timer... */
3861 SELECT_TIMER("MODULE_METEO", "PHYSICS");
3862
3863 /* Check quantity flags... */
3864 if (ctl->qnt_tsts >= 0)
3865 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3866 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3867
3868 /* Loop over particles... */
3869 PARTICLE_LOOP(0, atm->np, 0,
3870 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3871
3872 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
3873 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
3874 o3, lwc, rwc, iwc, swc, cc, z, zt;
3875
3876 /* Interpolate meteo data... */
3878 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3879
3880 /* Set quantities... */
3881 SET_ATM(qnt_ps, ps);
3882 SET_ATM(qnt_ts, ts);
3883 SET_ATM(qnt_zs, zs);
3884 SET_ATM(qnt_us, us);
3885 SET_ATM(qnt_vs, vs);
3886 SET_ATM(qnt_ess, ess);
3887 SET_ATM(qnt_nss, nss);
3888 SET_ATM(qnt_shf, shf);
3889 SET_ATM(qnt_lsm, lsm);
3890 SET_ATM(qnt_sst, sst);
3891 SET_ATM(qnt_pbl, pbl);
3892 SET_ATM(qnt_pt, pt);
3893 SET_ATM(qnt_tt, tt);
3894 SET_ATM(qnt_zt, zt);
3895 SET_ATM(qnt_h2ot, h2ot);
3896 SET_ATM(qnt_zg, z);
3897 SET_ATM(qnt_p, atm->p[ip]);
3898 SET_ATM(qnt_t, t);
3899 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3900 SET_ATM(qnt_u, u);
3901 SET_ATM(qnt_v, v);
3902 SET_ATM(qnt_w, w);
3903 SET_ATM(qnt_h2o, h2o);
3904 SET_ATM(qnt_o3, o3);
3905 SET_ATM(qnt_lwc, lwc);
3906 SET_ATM(qnt_rwc, rwc);
3907 SET_ATM(qnt_iwc, iwc);
3908 SET_ATM(qnt_swc, swc);
3909 SET_ATM(qnt_cc, cc);
3910 SET_ATM(qnt_pct, pct);
3911 SET_ATM(qnt_pcb, pcb);
3912 SET_ATM(qnt_cl, cl);
3913 SET_ATM(qnt_plcl, plcl);
3914 SET_ATM(qnt_plfc, plfc);
3915 SET_ATM(qnt_pel, pel);
3916 SET_ATM(qnt_cape, cape);
3917 SET_ATM(qnt_cin, cin);
3918 SET_ATM(qnt_o3c, o3c);
3919 SET_ATM(qnt_hno3,
3920 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3921 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3922 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3923 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3924 atm->lat[ip], atm->p[ip]));
3925 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3926 atm->lat[ip], atm->p[ip]));
3927 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3928 atm->lat[ip], atm->p[ip]));
3929 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3930 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3931 SET_ATM(qnt_psat, PSAT(t));
3932 SET_ATM(qnt_psice, PSICE(t));
3933 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3934 SET_ATM(qnt_sh, SH(h2o));
3935 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3936 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3937 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3938 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3939 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3940 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
3941 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
3942 SET_ATM(qnt_eta_dot, atm->q[ctl->qnt_eta_dot][ip]);
3943 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3944 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3945 SET_ATM(qnt_pv, pv);
3946 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3947 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3948 SET_ATM(qnt_tnat,
3949 nat_temperature(atm->p[ip], h2o,
3950 clim_zm(&clim->hno3, atm->time[ip],
3951 atm->lat[ip], atm->p[ip])));
3952 SET_ATM(qnt_tsts,
3953 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3954 }
3955}
3956
3957/*****************************************************************************/
3958
3960 const ctl_t *ctl,
3961 const clim_t *clim,
3962 atm_t *atm,
3963 const double t) {
3964
3965 /* Set timer... */
3966 SELECT_TIMER("MODULE_MIXING", "PHYSICS");
3967
3968 /* Allocate... */
3969 const int np = atm->np;
3970 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3971 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3972 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3973
3974 /* Set grid box size... */
3975 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3976 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3977 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3978
3979 /* Set time interval... */
3980 const double t0 = t - 0.5 * ctl->dt_mod;
3981 const double t1 = t + 0.5 * ctl->dt_mod;
3982
3983 /* Get indices... */
3984#ifdef _OPENACC
3985#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3986#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3987#pragma acc parallel loop independent gang vector
3988#else
3989#pragma omp parallel for default(shared)
3990#endif
3991 for (int ip = 0; ip < np; ip++) {
3992 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3993 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3994 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3995 if (atm->time[ip] < t0 || atm->time[ip] > t1
3996 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3997 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3998 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3999 izs[ip] = -1;
4000 }
4001
4002 /* Calculate interparcel mixing... */
4003 const int use_ensemble = (ctl->nens > 0);
4004
4005 const int quantities[] = {
4006 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
4007 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
4008 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
4009 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
4010 ctl->qnt_Csf6, ctl->qnt_aoa, ctl->qnt_Arn222, ctl->qnt_Apb210,
4011 ctl->qnt_Abe7, ctl->qnt_Acs137, ctl->qnt_Ai131, ctl->qnt_Axe133
4012 };
4013 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
4014
4015 for (int i = 0; i < n_qnt; i++)
4016 if (quantities[i] >= 0)
4017 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
4018 use_ensemble);
4019
4020 /* Free... */
4021#ifdef _OPENACC
4022#pragma acc exit data delete(ixs,iys,izs)
4023#endif
4024 free(ixs);
4025 free(iys);
4026 free(izs);
4027}
4028
4029/*****************************************************************************/
4030
4032 const ctl_t *ctl,
4033 const clim_t *clim,
4034 atm_t *atm,
4035 const int *ixs,
4036 const int *iys,
4037 const int *izs,
4038 const int qnt_idx,
4039 const int use_ensemble) {
4040
4041 const int np = atm->np;
4042 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
4043 const int nens = use_ensemble ? ctl->nens : 1;
4044 const int total_grid = ngrid * nens;
4045
4046 double *restrict const cmean =
4047 (double *) malloc((size_t) total_grid * sizeof(double));
4048 int *restrict const count =
4049 (int *) malloc((size_t) total_grid * sizeof(int));
4050
4051 /* Init... */
4052#ifdef _OPENACC
4053#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
4054#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
4055#pragma acc parallel loop independent gang vector
4056#else
4057#ifdef __NVCOMPILER
4058#pragma novector
4059#endif
4060#pragma omp parallel for
4061#endif
4062 for (int i = 0; i < total_grid; i++) {
4063 count[i] = 0;
4064 cmean[i] = 0.0;
4065 }
4066
4067 /* Loop over particles... */
4068#ifdef _OPENACC
4069#pragma acc parallel loop independent gang vector
4070#endif
4071 for (int ip = 0; ip < np; ip++)
4072 if (izs[ip] >= 0) {
4073 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4074 const int idx =
4075 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4076 ctl->mixing_nz);
4077#ifdef _OPENACC
4078#pragma acc atomic update
4079#endif
4080 cmean[idx] += atm->q[qnt_idx][ip];
4081#ifdef _OPENACC
4082#pragma acc atomic update
4083#endif
4084 count[idx]++;
4085 }
4086
4087 /* Compute means... */
4088#ifdef _OPENACC
4089#pragma acc parallel loop independent gang vector
4090#else
4091#ifdef __NVCOMPILER
4092#pragma novector
4093#endif
4094#pragma omp parallel for
4095#endif
4096 for (int i = 0; i < total_grid; i++)
4097 if (count[i] > 0)
4098 cmean[i] /= count[i];
4099
4100 /* Interparcel mixing... */
4101#ifdef _OPENACC
4102#pragma acc parallel loop independent gang vector
4103#else
4104#pragma omp parallel for
4105#endif
4106 for (int ip = 0; ip < np; ip++) {
4107 if (izs[ip] >= 0) {
4108 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4109
4110 double mixparam = 1.0;
4111 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
4112 const double w = tropo_weight(clim, atm, ip);
4113 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
4114 }
4115
4116 const int idx =
4117 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4118 ctl->mixing_nz);
4119 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
4120 }
4121 }
4122
4123 /* Free... */
4124#ifdef _OPENACC
4125#pragma acc exit data delete(cmean,count)
4126#endif
4127 free(cmean);
4128 free(count);
4129}
4130
4131/*****************************************************************************/
4132
4134 const ctl_t *ctl,
4135 const cache_t *cache,
4136 const clim_t *clim,
4137 met_t *met0,
4138 met_t *met1,
4139 atm_t *atm) {
4140
4141 /* Set timer... */
4142 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS");
4143
4144 /* Check quantity flags... */
4145 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4146 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4147
4148 /* Parameter of SO2 correction... */
4149 const double a = 4.71572206e-08;
4150 const double b = -8.28782867e-01;
4151 const double low = pow(1. / a, 1. / b);
4152
4153 /* Loop over particles... */
4154 PARTICLE_LOOP(0, atm->np, 1,
4155 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4156
4157 /* Get temperature... */
4158 double t;
4160 INTPOL_3D(t, 1);
4161
4162 /* Calculate molecular density... */
4163 const double M = MOLEC_DENS(atm->p[ip], t);
4164
4165 /* Use constant reaction rate... */
4166 double k = NAN;
4167 if (ctl->oh_chem_reaction == 1)
4168 k = ctl->oh_chem[0];
4169
4170 /* Calculate bimolecular reaction rate... */
4171 else if (ctl->oh_chem_reaction == 2)
4172 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
4173
4174 /* Calculate termolecular reaction rate... */
4175 if (ctl->oh_chem_reaction == 3) {
4176
4177 /* Calculate rate coefficient for X + OH + M -> XOH + M
4178 (JPL Publication 19-05) ... */
4179 const double k0 =
4180 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
4181 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
4182 const double ki =
4183 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
4184 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
4185 const double c = log10(k0 * M / ki);
4186 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
4187 }
4188
4189 /* Correction factor for high SO2 concentration
4190 (if qnt_Cx is defined, the correction is switched on)... */
4191 double cor = 1;
4192 if (ctl->qnt_Cx >= 0)
4193 cor =
4194 atm->q[ctl->qnt_Cx][ip] >
4195 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
4196
4197 /* Calculate exponential decay... */
4198 const double rate_coef =
4199 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
4200 atm->lat[ip], atm->p[ip]) * M * cor;
4201 const double aux = exp(-cache->dt[ip] * rate_coef);
4202 if (ctl->qnt_m >= 0) {
4203 if (ctl->qnt_mloss_oh >= 0)
4204 atm->q[ctl->qnt_mloss_oh][ip]
4205 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4206 atm->q[ctl->qnt_m][ip] *= aux;
4207 if (ctl->qnt_loss_rate >= 0)
4208 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4209 }
4210 if (ctl->qnt_vmr >= 0)
4211 atm->q[ctl->qnt_vmr][ip] *= aux;
4212 }
4213}
4214
4215/*****************************************************************************/
4216
4218 const cache_t *cache,
4219 met_t *met0,
4220 met_t *met1,
4221 atm_t *atm) {
4222
4223 /* Set timer... */
4224 SELECT_TIMER("MODULE_POSITION", "PHYSICS");
4225
4226 /* Loop over particles... */
4227 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
4228
4229 /* Init... */
4230 double ps;
4232
4233 /* Calculate modulo... */
4234 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
4235 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
4236
4237 /* Check latitude... */
4238 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
4239 if (atm->lat[ip] > 90) {
4240 atm->lat[ip] = 180 - atm->lat[ip];
4241 atm->lon[ip] += 180;
4242 }
4243 if (atm->lat[ip] < -90) {
4244 atm->lat[ip] = -180 - atm->lat[ip];
4245 atm->lon[ip] += 180;
4246 }
4247 }
4248
4249 /* Check longitude... */
4250 while (atm->lon[ip] < -180)
4251 atm->lon[ip] += 360;
4252 while (atm->lon[ip] >= 180)
4253 atm->lon[ip] -= 360;
4254
4255 /* Check pressure... */
4256 if (atm->p[ip] < met0->p[met0->np - 1]) {
4257 atm->p[ip] = met0->p[met0->np - 1];
4258 } else if (atm->p[ip] > 300.) {
4259 INTPOL_2D(ps, 1);
4260 if (atm->p[ip] > ps)
4261 atm->p[ip] = ps;
4262 }
4263 }
4264}
4265
4266/*****************************************************************************/
4267
4269 const ctl_t *ctl,
4270 const cache_t *cache,
4271 atm_t *atm) {
4272
4273 /* Set timer... */
4274 SELECT_TIMER("MODULE_RADIO_DECAY", "PHYSICS");
4275
4276 /* Set decay constants of radioactive species [s^-1]... */
4277 const double lambda_rn222 = log(2.0) / (3.8235 * 86400.0);
4278 const double lambda_pb210 = log(2.0) / (22.3 * 365.25 * 86400.0);
4279 const double lambda_be7 = log(2.0) / (53.22 * 86400.0);
4280 const double lambda_cs137 = log(2.0) / (30.05 * 365.25 * 86400.0);
4281 const double lambda_i131 = log(2.0) / (8.02 * 86400.0);
4282 const double lambda_xe133 = log(2.0) / (5.2474 * 86400.0);
4283
4284 /* Loop over particles... */
4285 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,atm)") {
4286
4287 /* Set timestep... */
4288 const double dt = cache->dt[ip];
4289
4290 /* Loss for Pb-210... */
4291 if (ctl->qnt_Apb210 >= 0)
4292 atm->q[ctl->qnt_Apb210][ip] *= exp(-dt * lambda_pb210);
4293
4294 /* Loss for Rn-222... */
4295 if (ctl->qnt_Arn222 >= 0) {
4296 const double old = atm->q[ctl->qnt_Arn222][ip];
4297 const double aux = exp(-dt * lambda_rn222);
4298 const double lost = old * (1.0 - aux);
4299 atm->q[ctl->qnt_Arn222][ip] = old * aux;
4300
4301 /* Parent-daughter process for Pb-210... */
4302 if (ctl->qnt_Apb210 >= 0)
4303 atm->q[ctl->qnt_Apb210][ip] += lost * lambda_pb210 / lambda_rn222;
4304 }
4305
4306 /* Loss for Be-7... */
4307 if (ctl->qnt_Abe7 >= 0)
4308 atm->q[ctl->qnt_Abe7][ip] *= exp(-dt * lambda_be7);
4309
4310 /* Loss for Cs-137... */
4311 if (ctl->qnt_Acs137 >= 0)
4312 atm->q[ctl->qnt_Acs137][ip] *= exp(-dt * lambda_cs137);
4313
4314 /* Loss for I-131... */
4315 if (ctl->qnt_Ai131 >= 0)
4316 atm->q[ctl->qnt_Ai131][ip] *= exp(-dt * lambda_i131);
4317
4318 /* Loss for Xe-133... */
4319 if (ctl->qnt_Axe133 >= 0)
4320 atm->q[ctl->qnt_Axe133][ip] *= exp(-dt * lambda_xe133);
4321 }
4322}
4323
4324/*****************************************************************************/
4325
4327 const int ntask) {
4328
4329 /* Initialize GSL random number generators... */
4330 gsl_rng_env_setup();
4331 if (omp_get_max_threads() > NTHREADS)
4332 ERRMSG("Too many threads!");
4333 for (int i = 0; i < NTHREADS; i++) {
4334 rng[i] = gsl_rng_alloc(gsl_rng_default);
4335 gsl_rng_set(rng[i], gsl_rng_default_seed
4336 + (long unsigned) (ntask * NTHREADS + i));
4337 }
4338
4339 /* Initialize cuRAND random number generators... */
4340#ifdef CURAND
4341 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
4342 CURAND_STATUS_SUCCESS)
4343 ERRMSG("Cannot create random number generator!");
4344 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
4345 CURAND_STATUS_SUCCESS)
4346 ERRMSG("Cannot set seed for random number generator!");
4347 if (curandSetStream
4348 (rng_curand,
4349 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
4350 CURAND_STATUS_SUCCESS)
4351 ERRMSG("Cannot set stream for random number generator!");
4352#endif
4353}
4354
4355/*****************************************************************************/
4356
4358 const ctl_t *ctl,
4359 double *rs,
4360 const size_t n,
4361 const int method) {
4362
4363 /* Use GSL random number generators... */
4364 if (ctl->rng_type == 0) {
4365
4366 /* Uniform distribution... */
4367 if (method == 0) {
4368#pragma omp parallel for default(shared)
4369 for (size_t i = 0; i < n; ++i)
4370 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
4371 }
4372
4373 /* Normal distribution... */
4374 else if (method == 1) {
4375#pragma omp parallel for default(shared)
4376 for (size_t i = 0; i < n; ++i)
4377 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
4378 }
4379
4380 /* Update of random numbers on device... */
4381#ifdef _OPENACC
4382 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
4383#pragma acc update device(rs[:n])
4384#endif
4385 }
4386
4387 /* Use Squares random number generator (Widynski, 2022)... */
4388 else if (ctl->rng_type == 1) {
4389
4390 /* Set key (don't change this!)... */
4391 const uint64_t key = 0xc8e4fd154ce32f6d;
4392
4393 /* Uniform distribution... */
4394#ifdef _OPENACC
4395#pragma acc data present(rs)
4396#pragma acc parallel loop independent gang vector
4397#else
4398#pragma omp parallel for default(shared)
4399#endif
4400 for (size_t i = 0; i < n + 1; ++i) {
4401 uint64_t r, t, x, y, z;
4402 y = x = (rng_ctr + i) * key;
4403 z = y + key;
4404 x = x * x + y;
4405 x = (x >> 32) | (x << 32);
4406 x = x * x + z;
4407 x = (x >> 32) | (x << 32);
4408 x = x * x + y;
4409 x = (x >> 32) | (x << 32);
4410 t = x = x * x + z;
4411 x = (x >> 32) | (x << 32);
4412 r = t ^ ((x * x + y) >> 32);
4413 rs[i] = (double) r / (double) UINT64_MAX;
4414 }
4415 rng_ctr += n + 1;
4416
4417 /* Normal distribution... */
4418 if (method == 1) {
4419#ifdef _OPENACC
4420#pragma acc parallel loop independent gang vector
4421#else
4422#pragma omp parallel for default(shared)
4423#endif
4424 for (size_t i = 0; i < n; i += 2) {
4425 const double r = sqrt(-2.0 * log(rs[i]));
4426 const double phi = 2.0 * M_PI * rs[i + 1];
4427 rs[i] = r * cosf((float) phi);
4428 rs[i + 1] = r * sinf((float) phi);
4429 }
4430 }
4431 }
4432
4433 /* Use cuRAND random number generators... */
4434 else if (ctl->rng_type == 2) {
4435#ifdef CURAND
4436#pragma acc host_data use_device(rs)
4437 {
4438
4439 /* Uniform distribution... */
4440 if (method == 0) {
4441 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
4442 CURAND_STATUS_SUCCESS)
4443 ERRMSG("Cannot create random numbers!");
4444 }
4445
4446 /* Normal distribution... */
4447 else if (method == 1) {
4448 if (curandGenerateNormalDouble
4449 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
4450 1.0) != CURAND_STATUS_SUCCESS)
4451 ERRMSG("Cannot create random numbers!");
4452 }
4453 }
4454#else
4455 ERRMSG("MPTRAC was compiled without cuRAND!");
4456#endif
4457 }
4458}
4459
4460/*****************************************************************************/
4461
4463 const ctl_t *ctl,
4464 const cache_t *cache,
4465 met_t *met0,
4466 met_t *met1,
4467 atm_t *atm) {
4468
4469 /* Set timer... */
4470 SELECT_TIMER("MODULE_SEDI", "PHYSICS");
4471
4472 /* Loop over particles... */
4473 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4474
4475 /* Get temperature... */
4476 double t;
4478 INTPOL_3D(t, 1);
4479
4480 /* Sedimentation velocity... */
4481 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4482 atm->q[ctl->qnt_rhop][ip]);
4483
4484 /* Calculate pressure change... */
4485 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
4486 }
4487}
4488
4489/*****************************************************************************/
4490
4492 const ctl_t *ctl,
4493 const met_t *met0,
4494 atm_t *atm) {
4495
4496 /* Set timer... */
4497 SELECT_TIMER("MODULE_SORT", "PHYSICS");
4498
4499 /* Allocate... */
4500 const int np = atm->np;
4501 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
4502 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
4503 if (a == NULL || p == NULL)
4504 ERRMSG("Out of memory!");
4505
4506#ifdef _OPENACC
4507#pragma acc enter data create(a[0:np],p[0:np])
4508#pragma acc data present(ctl,met0,atm,a,p)
4509#endif
4510
4511 /* Get box index... */
4512#ifdef _OPENACC
4513#pragma acc parallel loop independent gang vector
4514#else
4515#pragma omp parallel for default(shared)
4516#endif
4517 for (int ip = 0; ip < np; ip++) {
4518 a[ip] =
4519 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
4520 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
4521 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
4522 p[ip] = ip;
4523 }
4524
4525 /* Sorting... */
4526#ifdef THRUST
4527#ifdef _OPENACC
4528#pragma acc host_data use_device(a,p)
4529#endif
4530 thrustSortWrapper(a, np, p);
4531#else
4532 size_t *perm_sz = (size_t *) malloc((size_t) np * sizeof(size_t));
4533 if (perm_sz == NULL)
4534 ERRMSG("Out of memory!");
4535#ifdef _OPENACC
4536#pragma acc update self(a[0:np])
4537#endif
4538 gsl_sort_index(perm_sz, a, 1, (size_t) np);
4539 for (int ip = 0; ip < np; ++ip)
4540 p[ip] = (int) perm_sz[ip];
4541 free(perm_sz);
4542#ifdef _OPENACC
4543#pragma acc update device(p[0:np])
4544#endif
4545#endif
4546
4547 /* Sort data... */
4548 module_sort_help(atm->time, p, np);
4549 module_sort_help(atm->p, p, np);
4550 module_sort_help(atm->lon, p, np);
4551 module_sort_help(atm->lat, p, np);
4552 for (int iq = 0; iq < ctl->nq; iq++)
4553 module_sort_help(atm->q[iq], p, np);
4554
4555 /* Free... */
4556#ifdef _OPENACC
4557#pragma acc exit data delete(a,p)
4558#endif
4559 free(a);
4560 free(p);
4561}
4562
4563/*****************************************************************************/
4564
4566 double *a,
4567 const int *p,
4568 const int np) {
4569
4570 /* Allocate... */
4571 double *restrict const help =
4572 (double *) malloc((size_t) np * sizeof(double));
4573 if (help == NULL)
4574 ERRMSG("Out of memory!");
4575
4576 /* Reordering of array... */
4577#ifdef _OPENACC
4578#pragma acc enter data create(help[0:np])
4579#pragma acc data present(a,p,help)
4580#pragma acc parallel loop independent gang vector
4581#else
4582#pragma omp parallel for default(shared)
4583#endif
4584 for (int ip = 0; ip < np; ip++)
4585 help[ip] = a[p[ip]];
4586#ifdef _OPENACC
4587#pragma acc parallel loop independent gang vector
4588#else
4589#pragma omp parallel for default(shared)
4590#endif
4591 for (int ip = 0; ip < np; ip++)
4592 a[ip] = help[ip];
4593
4594 /* Free... */
4595#ifdef _OPENACC
4596#pragma acc exit data delete(help)
4597#endif
4598 free(help);
4599}
4600
4601/*****************************************************************************/
4602
4604 const ctl_t *ctl,
4605 cache_t *cache,
4606 met_t *met0,
4607 atm_t *atm,
4608 const double t) {
4609
4610 /* Set timer... */
4611 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS");
4612
4613 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
4614 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
4615
4616 const int local =
4617 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
4618
4619 /* Loop over particles... */
4620 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
4621
4622 /* Set time step for each air parcel... */
4623 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
4624 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
4625 && ctl->direction * (atm->time[ip] - t) < 0))
4626 cache->dt[ip] = t - atm->time[ip];
4627 else
4628 cache->dt[ip] = 0.0;
4629
4630 /* Check horizontal boundaries of local meteo data... */
4631#ifndef DD
4632 int dd = 1;
4633#else
4634 int dd = 0;
4635#endif
4636 if (dd) {
4637 if (local && (atm->lon[ip] <= met0->lon[0]
4638 || atm->lon[ip] >= met0->lon[met0->nx - 1]
4639 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
4640 cache->dt[ip] = 0.0;
4641 } else {
4642 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
4643 cache->dt[ip] = 0;
4644 }
4645 }
4646}
4647
4648/*****************************************************************************/
4649
4651 ctl_t *ctl,
4652 const atm_t *atm) {
4653
4654 /* Set timer... */
4655 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS");
4656
4657 /* Set start time... */
4658 if (ctl->direction == 1) {
4659 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4660 if (ctl->t_stop > 1e99)
4661 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4662 } else {
4663 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4664 if (ctl->t_stop > 1e99)
4665 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4666 }
4667
4668 /* Check time interval... */
4669 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
4670 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
4671
4672 /* Round start time... */
4673 if (ctl->direction == 1)
4674 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4675 else
4676 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4677}
4678
4679/*****************************************************************************/
4680
4682 const ctl_t *ctl,
4683 const cache_t *cache,
4684 const clim_t *clim,
4685 met_t *met0,
4686 met_t *met1,
4687 atm_t *atm) {
4688
4689 /* Set timer... */
4690 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS");
4691
4692 /* Loop over particles... */
4693 PARTICLE_LOOP(0, atm->np, 1,
4694 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4695
4696 /* Get temperature... */
4697 double t;
4699 INTPOL_3D(t, 1);
4700
4701 /* Get molecular density... */
4702 const double M = MOLEC_DENS(atm->p[ip], t);
4703
4704 /* Get total column ozone... */
4705 double o3c;
4706 INTPOL_2D(o3c, 1);
4707
4708 /* Get solar zenith angle... */
4709 const double sza =
4710 acos(cos_sza(atm->time[ip], atm->lon[ip], atm->lat[ip]));
4711
4712 /* Get O(1D) volume mixing ratio... */
4713 const double o1d =
4714 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4715
4716 /* Reactions for CFC-10... */
4717 if (ctl->qnt_Cccl4 >= 0) {
4718 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4719 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4720 atm->p[ip], sza, o3c);
4721 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4722 }
4723
4724 /* Reactions for CFC-11... */
4725 if (ctl->qnt_Cccl3f >= 0) {
4726 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4727 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4728 atm->p[ip], sza, o3c);
4729 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4730 }
4731
4732 /* Reactions for CFC-12... */
4733 if (ctl->qnt_Cccl2f2 >= 0) {
4734 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4735 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4736 atm->p[ip], sza, o3c);
4737 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4738 }
4739
4740 /* Reactions for N2O... */
4741 if (ctl->qnt_Cn2o >= 0) {
4742 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4743 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4744 atm->p[ip], sza, o3c);
4745 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4746 }
4747 }
4748}
4749
4750/*****************************************************************************/
4751
4753 const ctl_t *ctl,
4754 const cache_t *cache,
4755 met_t *met0,
4756 met_t *met1,
4757 atm_t *atm) {
4758
4759 /* Set timer... */
4760 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS");
4761
4762 /* Check quantity flags... */
4763 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4764 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4765
4766 /* Loop over particles... */
4767 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4768
4769 /* Check whether particle is below cloud top... */
4770 double pct;
4772 INTPOL_2D(pct, 1);
4773 if (!isfinite(pct) || atm->p[ip] <= pct)
4774 continue;
4775
4776 /* Get cloud bottom pressure... */
4777 double pcb;
4778 INTPOL_2D(pcb, 0);
4779
4780 /* Estimate precipitation rate (Pisso et al., 2019)... */
4781 double cl;
4782 INTPOL_2D(cl, 0);
4783 const double Is =
4784 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4785 if (Is < 0.01)
4786 continue;
4787
4788 /* Check whether particle is inside or below cloud... */
4789 double lwc, rwc, iwc, swc;
4790 INTPOL_3D(lwc, 1);
4791 INTPOL_3D(rwc, 0);
4792 INTPOL_3D(iwc, 0);
4793 INTPOL_3D(swc, 0);
4794 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4795
4796 /* Get temperature... */
4797 double t;
4798 INTPOL_3D(t, 0);
4799
4800 /* Calculate in-cloud scavenging coefficient... */
4801 double lambda = 0;
4802 if (inside) {
4803
4804 /* Calculate retention factor... */
4805 double eta;
4806 if (t > 273.15)
4807 eta = 1;
4808 else if (t <= 238.15)
4809 eta = ctl->wet_depo_ic_ret_ratio;
4810 else
4811 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4812
4813 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4814 if (ctl->wet_depo_ic_a > 0)
4815 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4816
4817 /* Use Henry's law for gases... */
4818 else if (ctl->wet_depo_ic_h[0] > 0) {
4819
4820 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4821 double h = ctl->wet_depo_ic_h[0]
4822 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4823
4824 /* Use effective Henry's constant for SO2
4825 (Berglen, 2004; Simpson, 2012)... */
4826 if (ctl->wet_depo_so2_ph > 0) {
4827 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
4828 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4829 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4830 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
4831 }
4832
4833 /* Estimate depth of cloud layer... */
4834 const double dz = 1e3 * (Z(pct) - Z(pcb));
4835
4836 /* Calculate scavenging coefficient... */
4837 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4838 }
4839 }
4840
4841 /* Calculate below-cloud scavenging coefficient... */
4842 else {
4843
4844 /* Calculate retention factor... */
4845 double eta;
4846 if (t > 270)
4847 eta = 1;
4848 else
4849 eta = ctl->wet_depo_bc_ret_ratio;
4850
4851 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4852 if (ctl->wet_depo_bc_a > 0)
4853 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4854
4855 /* Use Henry's law for gases... */
4856 else if (ctl->wet_depo_bc_h[0] > 0) {
4857
4858 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4859 const double h = ctl->wet_depo_bc_h[0]
4860 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4861
4862 /* Estimate depth of cloud layer... */
4863 const double dz = 1e3 * (Z(pct) - Z(pcb));
4864
4865 /* Calculate scavenging coefficient... */
4866 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4867 }
4868 }
4869
4870 /* Calculate exponential decay of mass... */
4871 const double aux = exp(-cache->dt[ip] * lambda);
4872 if (ctl->qnt_m >= 0) {
4873 if (ctl->qnt_mloss_wet >= 0)
4874 atm->q[ctl->qnt_mloss_wet][ip]
4875 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4876 atm->q[ctl->qnt_m][ip] *= aux;
4877 if (ctl->qnt_loss_rate >= 0)
4878 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4879 }
4880 if (ctl->qnt_vmr >= 0)
4881 atm->q[ctl->qnt_vmr][ip] *= aux;
4882 }
4883}
4884
4885/*****************************************************************************/
4886
4888 ctl_t **ctl,
4889 cache_t **cache,
4890 clim_t **clim,
4891 met_t **met0,
4892 met_t **met1,
4893 atm_t **atm,
4894 dd_t **dd) {
4895
4896 /* Initialize GPU... */
4897#ifdef _OPENACC
4898 SELECT_TIMER("ACC_INIT", "INIT");
4899 int rank = 0;
4900#ifdef MPI
4901 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
4902#endif
4903 if (acc_get_num_devices(acc_device_nvidia) <= 0)
4904 ERRMSG("Not running on a GPU device!");
4905 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
4906 acc_device_nvidia);
4907 acc_device_t device_type = acc_get_device_type();
4908 acc_init(device_type);
4909#endif
4910
4911 /* Allocate... */
4912 SELECT_TIMER("ALLOC", "MEMORY");
4913 ALLOC(*ctl, ctl_t, 1);
4914 ALLOC(*cache, cache_t, 1);
4915 ALLOC(*clim, clim_t, 1);
4916 ALLOC(*met0, met_t, 1);
4917 ALLOC(*met1, met_t, 1);
4918 ALLOC(*atm, atm_t, 1);
4919 ALLOC(*dd, dd_t, 1);
4920
4921 /* Create data region on GPU... */
4922#ifdef _OPENACC
4923 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY");
4924 ctl_t *ctlup = *ctl;
4925 cache_t *cacheup = *cache;
4926 clim_t *climup = *clim;
4927 met_t *met0up = *met0;
4928 met_t *met1up = *met1;
4929 atm_t *atmup = *atm;
4930#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
4931#ifdef DD
4932 dd_t *ddup = *dd;
4933#pragma acc enter data create(ddup[:1])
4934#endif
4935#endif
4936}
4937
4938/*****************************************************************************/
4939
4941 ctl_t *ctl,
4942 cache_t *cache,
4943 clim_t *clim,
4944 met_t *met0,
4945 met_t *met1,
4946 atm_t *atm,
4947 dd_t *dd) {
4948
4949 /* Delete data region on GPU... */
4950#ifdef _OPENACC
4951 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY");
4952#pragma acc exit data delete(ctl,cache,clim,met0,met1,atm)
4953#ifdef DD
4954#pragma acc exit data delete(dd)
4955#endif
4956#endif
4957
4958 /* Free... */
4959 SELECT_TIMER("FREE", "MEMORY");
4960 free(atm);
4961 free(ctl);
4962 free(cache);
4963 free(clim);
4964 free(met0);
4965 free(met1);
4966
4967 /* Free MPI datatype... */
4968#ifdef DD
4969 MPI_Type_free(&dd->MPI_Particle);
4970#endif
4971 free(dd);
4972}
4973
4974/*****************************************************************************/
4975
4977 ctl_t *ctl,
4978 clim_t *clim,
4979 const double t,
4980 met_t **met0,
4981 met_t **met1,
4982 dd_t *dd) {
4983
4984 static int init;
4985
4986 met_t *mets;
4987
4988 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
4989
4990 /* Set timer... */
4991 SELECT_TIMER("GET_MET", "INPUT");
4992
4993 /* Init... */
4994 if (t == ctl->t_start || !init) {
4995 init = 1;
4996
4997 /* Read meteo data... */
4998 get_met_filename(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
4999 ctl->metbase, ctl->dt_met, filename);
5000 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5001 ERRMSG("Cannot open file!");
5002
5003 get_met_filename(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
5004 ctl->metbase, ctl->dt_met, filename);
5005 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5006 ERRMSG("Cannot open file!");
5007
5008 /* Update GPU... */
5009 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
5010 SELECT_TIMER("GET_MET", "INPUT");
5011
5012 /* Caching... */
5013 if (ctl->met_cache && t != ctl->t_stop) {
5014 get_met_filename(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
5015 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
5016 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5017 LOG(1, "Caching: %s", cachefile);
5018 if (system(cmd) != 0)
5019 WARN("Caching command failed!");
5020 }
5021 }
5022
5023 /* Read new data for forward trajectories... */
5024 if (t > (*met1)->time) {
5025
5026 /* Pointer swap... */
5027 mets = *met1;
5028 *met1 = *met0;
5029 *met0 = mets;
5030
5031 /* Read new meteo data... */
5032 get_met_filename(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
5033 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5034 ERRMSG("Cannot open file!");
5035
5036 /* Update GPU... */
5037 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
5038 SELECT_TIMER("GET_MET", "INPUT");
5039
5040 /* Caching... */
5041 if (ctl->met_cache && t != ctl->t_stop) {
5042 get_met_filename(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
5043 cachefile);
5044 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5045 LOG(1, "Caching: %s", cachefile);
5046 if (system(cmd) != 0)
5047 WARN("Caching command failed!");
5048 }
5049 }
5050
5051 /* Read new data for backward trajectories... */
5052 if (t < (*met0)->time) {
5053
5054 /* Pointer swap... */
5055 mets = *met1;
5056 *met1 = *met0;
5057 *met0 = mets;
5058
5059 /* Read new meteo data... */
5060 get_met_filename(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
5061 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5062 ERRMSG("Cannot open file!");
5063
5064 /* Update GPU... */
5065 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
5066 SELECT_TIMER("GET_MET", "INPUT");
5067
5068 /* Caching... */
5069 if (ctl->met_cache && t != ctl->t_stop) {
5070 get_met_filename(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
5071 cachefile);
5072 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5073 LOG(1, "Caching: %s", cachefile);
5074 if (system(cmd) != 0)
5075 WARN("Caching command failed!");
5076 }
5077 }
5078
5079 /* Check that grids are consistent... */
5080 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
5081 if ((*met0)->nx != (*met1)->nx
5082 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
5083 ERRMSG("Meteo grid dimensions do not match!");
5084 for (int ix = 0; ix < (*met0)->nx; ix++)
5085 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
5086 ERRMSG("Meteo grid longitudes do not match!");
5087 for (int iy = 0; iy < (*met0)->ny; iy++)
5088 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
5089 ERRMSG("Meteo grid latitudes do not match!");
5090 for (int ip = 0; ip < (*met0)->np; ip++)
5091 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
5092 ERRMSG("Meteo grid pressure levels do not match!");
5093 }
5094}
5095
5096/*****************************************************************************/
5097
5099 ctl_t *ctl,
5100 cache_t *cache,
5101 clim_t *clim,
5102 atm_t *atm,
5103 const int ntask) {
5104
5105 /* Initialize timesteps... */
5106 module_timesteps_init(ctl, atm);
5107
5108 /* Initialize random number generator... */
5109 module_rng_init(ntask);
5110
5111 /* Update GPU memory... */
5112 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
5113}
5114
5115/*****************************************************************************/
5116
5118 const char *filename,
5119 const ctl_t *ctl,
5120 atm_t *atm) {
5121
5122 int result;
5123
5124 /* Set timer... */
5125 SELECT_TIMER("READ_ATM", "INPUT");
5126
5127 /* Init... */
5128 atm->np = 0;
5129
5130 /* Write info... */
5131 LOG(1, "Read atmospheric data: %s", filename);
5132
5133 /* Read ASCII data... */
5134 if (ctl->atm_type == 0)
5135 result = read_atm_asc(filename, ctl, atm);
5136
5137 /* Read binary data... */
5138 else if (ctl->atm_type == 1)
5139 result = read_atm_bin(filename, ctl, atm);
5140
5141 /* Read netCDF data... */
5142 else if (ctl->atm_type == 2)
5143 result = read_atm_nc(filename, ctl, atm);
5144
5145 /* Read CLaMS data... */
5146 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
5147 result = read_atm_clams(filename, ctl, atm);
5148
5149 /* Error... */
5150 else
5151 ERRMSG("Atmospheric data type not supported!");
5152
5153 /* Check result... */
5154 if (result != 1)
5155 return 0;
5156
5157 /* Check number of air parcels... */
5158 if (atm->np < 1)
5159 ERRMSG("Can not read any data!");
5160
5161 /* Write info... */
5162 double mini, maxi;
5163 LOG(2, "Number of particles: %d", atm->np);
5164 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5165 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5166 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5167 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5168 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5169 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5170 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5171 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5172 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5173 for (int iq = 0; iq < ctl->nq; iq++) {
5174 char msg[5 * LEN];
5175 sprintf(msg, "Quantity %s range: %s ... %s %s",
5176 ctl->qnt_name[iq], ctl->qnt_format[iq],
5177 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5178 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5179 LOG(2, msg, mini, maxi);
5180 }
5181
5182 /* Return success... */
5183 return 1;
5184}
5185
5186/*****************************************************************************/
5187
5189 const ctl_t *ctl,
5190 clim_t *clim) {
5191
5192 /* Set timer... */
5193 SELECT_TIMER("READ_CLIM", "INPUT");
5194
5195 /* Init tropopause climatology... */
5196 clim_tropo_init(clim);
5197
5198 /* Read photolysis rates... */
5199 if (ctl->clim_photo[0] != '-')
5200 read_clim_photo(ctl->clim_photo, &clim->photo);
5201
5202 /* Read HNO3 climatology... */
5203 if (ctl->clim_hno3_filename[0] != '-')
5204 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
5205
5206 /* Read OH climatology... */
5207 if (ctl->clim_oh_filename[0] != '-') {
5208 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
5209 if (ctl->oh_chem_beta > 0)
5210 clim_oh_diurnal_correction(ctl, clim);
5211 }
5212
5213 /* Read H2O2 climatology... */
5214 if (ctl->clim_h2o2_filename[0] != '-')
5215 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
5216
5217 /* Read HO2 climatology... */
5218 if (ctl->clim_ho2_filename[0] != '-')
5219 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
5220
5221 /* Read O(1D) climatology... */
5222 if (ctl->clim_o1d_filename[0] != '-')
5223 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
5224
5225 /* Read CFC-10 time series... */
5226 if (ctl->clim_ccl4_timeseries[0] != '-')
5228
5229 /* Read CFC-11 time series... */
5230 if (ctl->clim_ccl3f_timeseries[0] != '-')
5232
5233 /* Read CFC-12 time series... */
5234 if (ctl->clim_ccl2f2_timeseries[0] != '-')
5236
5237 /* Read N2O time series... */
5238 if (ctl->clim_n2o_timeseries[0] != '-')
5239 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
5240
5241 /* Read SF6 time series... */
5242 if (ctl->clim_sf6_timeseries[0] != '-')
5243 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
5244}
5245
5246/*****************************************************************************/
5247
5249 const char *filename,
5250 int argc,
5251 char *argv[],
5252 ctl_t *ctl) {
5253
5254 /* Set timer... */
5255 SELECT_TIMER("READ_CTL", "INPUT");
5256
5257 /* Write info... */
5258 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
5259 "(executable: %s | version: %s | compiled: %s, %s)\n",
5260 argv[0], VERSION, __DATE__, __TIME__);
5261
5262 /* Initialize quantity indices... */
5263 ctl->qnt_idx = -1;
5264 ctl->qnt_ens = -1;
5265 ctl->qnt_stat = -1;
5266 ctl->qnt_m = -1;
5267 ctl->qnt_vmr = -1;
5268 ctl->qnt_rp = -1;
5269 ctl->qnt_rhop = -1;
5270 ctl->qnt_ps = -1;
5271 ctl->qnt_ts = -1;
5272 ctl->qnt_zs = -1;
5273 ctl->qnt_us = -1;
5274 ctl->qnt_vs = -1;
5275 ctl->qnt_ess = -1;
5276 ctl->qnt_nss = -1;
5277 ctl->qnt_shf = -1;
5278 ctl->qnt_lsm = -1;
5279 ctl->qnt_sst = -1;
5280 ctl->qnt_pbl = -1;
5281 ctl->qnt_pt = -1;
5282 ctl->qnt_tt = -1;
5283 ctl->qnt_zt = -1;
5284 ctl->qnt_h2ot = -1;
5285 ctl->qnt_zg = -1;
5286 ctl->qnt_p = -1;
5287 ctl->qnt_t = -1;
5288 ctl->qnt_rho = -1;
5289 ctl->qnt_u = -1;
5290 ctl->qnt_v = -1;
5291 ctl->qnt_w = -1;
5292 ctl->qnt_h2o = -1;
5293 ctl->qnt_o3 = -1;
5294 ctl->qnt_lwc = -1;
5295 ctl->qnt_rwc = -1;
5296 ctl->qnt_iwc = -1;
5297 ctl->qnt_swc = -1;
5298 ctl->qnt_cc = -1;
5299 ctl->qnt_pct = -1;
5300 ctl->qnt_pcb = -1;
5301 ctl->qnt_cl = -1;
5302 ctl->qnt_plcl = -1;
5303 ctl->qnt_plfc = -1;
5304 ctl->qnt_pel = -1;
5305 ctl->qnt_cape = -1;
5306 ctl->qnt_cin = -1;
5307 ctl->qnt_o3c = -1;
5308 ctl->qnt_hno3 = -1;
5309 ctl->qnt_oh = -1;
5310 ctl->qnt_h2o2 = -1;
5311 ctl->qnt_ho2 = -1;
5312 ctl->qnt_o1d = -1;
5313 ctl->qnt_mloss_oh = -1;
5314 ctl->qnt_mloss_h2o2 = -1;
5315 ctl->qnt_mloss_kpp = -1;
5316 ctl->qnt_mloss_wet = -1;
5317 ctl->qnt_mloss_dry = -1;
5318 ctl->qnt_mloss_decay = -1;
5319 ctl->qnt_loss_rate = -1;
5320 ctl->qnt_psat = -1;
5321 ctl->qnt_psice = -1;
5322 ctl->qnt_pw = -1;
5323 ctl->qnt_sh = -1;
5324 ctl->qnt_rh = -1;
5325 ctl->qnt_rhice = -1;
5326 ctl->qnt_theta = -1;
5327 ctl->qnt_zeta = -1;
5328 ctl->qnt_zeta_d = -1;
5329 ctl->qnt_zeta_dot = -1;
5330 ctl->qnt_eta = -1;
5331 ctl->qnt_eta_dot = -1;
5332 ctl->qnt_tvirt = -1;
5333 ctl->qnt_lapse = -1;
5334 ctl->qnt_vh = -1;
5335 ctl->qnt_vz = -1;
5336 ctl->qnt_pv = -1;
5337 ctl->qnt_tdew = -1;
5338 ctl->qnt_tice = -1;
5339 ctl->qnt_tsts = -1;
5340 ctl->qnt_tnat = -1;
5341 ctl->qnt_Cx = -1;
5342 ctl->qnt_Ch2o = -1;
5343 ctl->qnt_Co3 = -1;
5344 ctl->qnt_Cco = -1;
5345 ctl->qnt_Coh = -1;
5346 ctl->qnt_Ch = -1;
5347 ctl->qnt_Cho2 = -1;
5348 ctl->qnt_Ch2o2 = -1;
5349 ctl->qnt_Co1d = -1;
5350 ctl->qnt_Co3p = -1;
5351 ctl->qnt_Cccl4 = -1;
5352 ctl->qnt_Cccl3f = -1;
5353 ctl->qnt_Cccl2f2 = -1;
5354 ctl->qnt_Cn2o = -1;
5355 ctl->qnt_Csf6 = -1;
5356 ctl->qnt_aoa = -1;
5357 ctl->qnt_Arn222 = -1;
5358 ctl->qnt_Apb210 = -1;
5359 ctl->qnt_Abe7 = -1;
5360 ctl->qnt_Acs137 = -1;
5361 ctl->qnt_Ai131 = -1;
5362 ctl->qnt_Axe133 = -1;
5363 ctl->qnt_subdomain = -1;
5364 ctl->qnt_destination = -1;
5365
5366 /* Read quantities... */
5367 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
5368 if (ctl->nq > NQ)
5369 ERRMSG("Too many quantities!");
5370 for (int iq = 0; iq < ctl->nq; iq++) {
5371
5372 /* Read quantity name and format... */
5373 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
5374 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
5375 ctl->qnt_longname[iq]);
5376 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
5377 ctl->qnt_format[iq]);
5378 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
5379 sprintf(ctl->qnt_format[iq], "%%.2f");
5380
5381 /* Try to identify quantity... */
5382 SET_QNT(qnt_idx, "idx", "particle index", "-")
5383 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
5384 SET_QNT(qnt_stat, "stat", "station flag", "-")
5385 SET_QNT(qnt_m, "m", "mass", "kg")
5386 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
5387 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
5388 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
5389 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
5390 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
5391 SET_QNT(qnt_zs, "zs", "surface height", "km")
5392 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
5393 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
5394 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
5395 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
5396 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
5397 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
5398 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
5399 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
5400 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
5401 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
5402 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
5403 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
5404 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
5405 SET_QNT(qnt_p, "p", "pressure", "hPa")
5406 SET_QNT(qnt_t, "t", "temperature", "K")
5407 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
5408 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
5409 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
5410 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
5411 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
5412 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
5413 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
5414 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
5415 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
5416 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
5417 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
5418 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
5419 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
5420 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
5421 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
5422 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
5423 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
5424 SET_QNT(qnt_cape, "cape", "convective available potential energy",
5425 "J/kg")
5426 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
5427 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
5428 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
5429 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
5430 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
5431 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
5432 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
5433 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
5434 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
5435 "mass loss due to H2O2 chemistry", "kg")
5436 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
5437 "kg")
5438 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
5439 "kg")
5440 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
5441 "kg")
5442 SET_QNT(qnt_mloss_decay, "mloss_decay",
5443 "mass loss due to exponential decay", "kg")
5444 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
5445 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
5446 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
5447 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
5448 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
5449 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
5450 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
5451 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
5452 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
5453 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
5454 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
5455 "K/day")
5456 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
5457 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
5458 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
5459 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
5460 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
5461 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
5462 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
5463 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
5464 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
5465 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
5466 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
5467 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
5468 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
5469 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
5470 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
5471 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
5472 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
5473 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
5474 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
5475 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
5476 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
5477 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
5478 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
5479 "ppv")
5480 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
5481 "ppv")
5482 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
5483 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
5484 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
5485 SET_QNT(qnt_Arn222, "Arn222", "Rn-222 activity", "Bq")
5486 SET_QNT(qnt_Apb210, "Apb210", "Pb-210 activity", "Bq")
5487 SET_QNT(qnt_Abe7, "Abe7", "Be-7 activity", "Bq")
5488 SET_QNT(qnt_Acs137, "Acs137", "Cs-137 activity", "Bq")
5489 SET_QNT(qnt_Ai131, "Ai131", "I-131 activity", "Bq")
5490 SET_QNT(qnt_Axe133, "Axe133", "Xe-133 activity", "Bq")
5491 SET_QNT(qnt_subdomain, "subdomain", "current subdomain index", "-")
5492 SET_QNT(qnt_destination, "destination",
5493 "subdomain index of destination", "-")
5494 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
5495 }
5496
5497 /* Vertical coordinate and velocity... */
5498 ctl->advect_vert_coord =
5499 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
5500 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
5501 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
5502
5503 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
5504 ERRMSG("Add quantity zeta for diabatic advection!");
5505 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
5506 ERRMSG("Add quantity eta for etadot avection!");
5507
5508 ctl->met_vert_coord =
5509 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
5510 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
5511 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
5512
5513 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
5514 ERRMSG
5515 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
5516 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
5517 ERRMSG
5518 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
5519
5520 /* Time steps of simulation... */
5521 ctl->direction =
5522 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
5523 if (ctl->direction != -1 && ctl->direction != 1)
5524 ERRMSG("Set DIRECTION to -1 or 1!");
5525 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
5526 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
5527
5528 /* Meteo data... */
5529 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
5530 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
5531 ctl->met_convention =
5532 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
5533 ctl->met_type =
5534 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
5535 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
5536 ERRMSG
5537 ("Please use meteo files in netcdf format for diabatic calculations.");
5538 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
5539 ERRMSG
5540 ("Please use meteo files in netcdf format for etadot calculations.");
5541 ctl->met_clams =
5542 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
5543 ctl->met_nc_scale =
5544 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
5545 ctl->met_nc_level =
5546 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
5547 ctl->met_nc_quant =
5548 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
5549 ctl->met_zstd_level =
5550 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
5551 for (int i = 0; i < METVAR; i++) {
5552 char defprec[LEN] = "0", deftol[LEN] = "0.0";
5553 if (i == 0) /* geopotential height */
5554 sprintf(deftol, "0.5");
5555 else if (i == 1) /* temperature */
5556 sprintf(deftol, "5.0");
5557 else /* other variables */
5558 sprintf(defprec, "8");
5559 ctl->met_comp_prec[i] =
5560 (int) scan_ctl(filename, argc, argv, "MET_COMP_PREC", i, defprec, NULL);
5561 ctl->met_comp_tol[i] =
5562 scan_ctl(filename, argc, argv, "MET_COMP_TOL", i, deftol, NULL);
5563 }
5564 ctl->met_cms_batch =
5565 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
5566 ctl->met_cms_zstd =
5567 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
5568 ctl->met_cms_nd0x =
5569 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0X", -1, "48", NULL);
5570 ctl->met_cms_nd0y =
5571 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0Y", -1, "24", NULL);
5572 ctl->met_cms_maxlev =
5573 (int) scan_ctl(filename, argc, argv, "MET_CMS_MAXLEV", -1, "6", NULL);
5574 ctl->met_cms_eps_z =
5575 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
5576 ctl->met_cms_eps_t =
5577 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
5578 ctl->met_cms_eps_u =
5579 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
5580 ctl->met_cms_eps_v =
5581 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
5582 ctl->met_cms_eps_w =
5583 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
5584 ctl->met_cms_eps_pv =
5585 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
5586 ctl->met_cms_eps_h2o =
5587 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
5588 ctl->met_cms_eps_o3 =
5589 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
5590 ctl->met_cms_eps_lwc =
5591 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
5592 ctl->met_cms_eps_rwc =
5593 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
5594 ctl->met_cms_eps_iwc =
5595 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
5596 ctl->met_cms_eps_swc =
5597 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
5598 ctl->met_cms_eps_cc =
5599 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
5600 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
5601 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
5602 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
5603 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
5604 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
5605 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
5606 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
5607 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
5608 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
5609 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
5610 ctl->met_detrend =
5611 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
5612 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
5613 if (ctl->met_np > EP)
5614 ERRMSG("Too many pressure levels!");
5615 ctl->met_press_level_def =
5616 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
5617 NULL);
5618 if (ctl->met_press_level_def >= 0) {
5619 level_definitions(ctl);
5620 } else {
5621 if (ctl->met_np > 0) {
5622 for (int ip = 0; ip < ctl->met_np; ip++)
5623 ctl->met_p[ip] =
5624 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
5625 }
5626 }
5627 ctl->met_nlev =
5628 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
5629 if (ctl->met_nlev > EP)
5630 ERRMSG("Too many model levels!");
5631 for (int ip = 0; ip < ctl->met_nlev; ip++)
5632 ctl->met_lev_hyam[ip] =
5633 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
5634 for (int ip = 0; ip < ctl->met_nlev; ip++)
5635 ctl->met_lev_hybm[ip] =
5636 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
5637 ctl->met_geopot_sx =
5638 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
5639 ctl->met_geopot_sy =
5640 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
5641 ctl->met_relhum =
5642 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
5643 ctl->met_cape =
5644 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
5645 if (ctl->met_cape < 0 || ctl->met_cape > 1)
5646 ERRMSG("Set MET_CAPE to 0 or 1!");
5647 ctl->met_pbl =
5648 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
5649 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
5650 ERRMSG("Set MET_PBL to 0 ... 3!");
5651 ctl->met_pbl_min =
5652 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
5653 ctl->met_pbl_max =
5654 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
5655 ctl->met_tropo =
5656 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
5657 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
5658 ERRMSG("Set MET_TROPO to 0 ... 5!");
5659 ctl->met_tropo_pv =
5660 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
5661 ctl->met_tropo_theta =
5662 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
5663 ctl->met_tropo_spline =
5664 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
5665 ctl->met_dt_out =
5666 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
5667 ctl->met_cache =
5668 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
5669 ctl->met_mpi_share =
5670 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
5671
5672 /* Sorting... */
5673 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
5674
5675 /* Isosurface parameters... */
5676 ctl->isosurf =
5677 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
5678 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
5679
5680 /* Random number generator... */
5681 ctl->rng_type =
5682 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
5683 if (ctl->rng_type < 0 || ctl->rng_type > 2)
5684 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
5685
5686 /* Advection parameters... */
5687 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
5688 if (!
5689 (ctl->advect == 0 || ctl->advect == 1 || ctl->advect == 2
5690 || ctl->advect == 4))
5691 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
5692
5693 /* Diffusion parameters... */
5694 ctl->diffusion
5695 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
5696 if (ctl->diffusion < 0 || ctl->diffusion > 2)
5697 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
5698 ctl->turb_dx_pbl =
5699 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
5700 ctl->turb_dx_trop =
5701 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
5702 ctl->turb_dx_strat =
5703 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
5704 ctl->turb_dz_pbl =
5705 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
5706 ctl->turb_dz_trop =
5707 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
5708 ctl->turb_dz_strat =
5709 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
5710 ctl->turb_mesox =
5711 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
5712 ctl->turb_mesoz =
5713 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5714
5715 /* Convection... */
5716 ctl->conv_mix_pbl
5717 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
5718 ctl->conv_pbl_trans
5719 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
5720 ctl->conv_cape
5721 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5722 ctl->conv_cin
5723 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5724 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5725
5726 /* Boundary conditions... */
5727 ctl->bound_mass =
5728 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5729 ctl->bound_mass_trend =
5730 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5731 ctl->bound_vmr =
5732 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5733 ctl->bound_vmr_trend =
5734 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5735 ctl->bound_lat0 =
5736 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5737 ctl->bound_lat1 =
5738 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5739 ctl->bound_p0 =
5740 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5741 ctl->bound_p1 =
5742 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5743 ctl->bound_dps =
5744 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5745 ctl->bound_dzs =
5746 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
5747 ctl->bound_zetas =
5748 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
5749 ctl->bound_pbl =
5750 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
5751
5752 /* Species parameters... */
5753 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
5754 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
5755 ctl->molmass = 120.907;
5756 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
5757 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5758 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5759 ctl->molmass = 137.359;
5760 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5761 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5762 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5763 ctl->molmass = 16.043;
5764 ctl->oh_chem_reaction = 2;
5765 ctl->oh_chem[0] = 2.45e-12;
5766 ctl->oh_chem[1] = 1775;
5767 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5768 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5769 } else if (strcasecmp(ctl->species, "CO") == 0) {
5770 ctl->molmass = 28.01;
5771 ctl->oh_chem_reaction = 3;
5772 ctl->oh_chem[0] = 6.9e-33;
5773 ctl->oh_chem[1] = 2.1;
5774 ctl->oh_chem[2] = 1.1e-12;
5775 ctl->oh_chem[3] = -1.3;
5776 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5777 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5778 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5779 ctl->molmass = 44.009;
5780 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5781 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5782 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5783 ctl->molmass = 18.01528;
5784 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5785 ctl->molmass = 44.013;
5786 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5787 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5788 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5789 ctl->molmass = 17.031;
5790 ctl->oh_chem_reaction = 2;
5791 ctl->oh_chem[0] = 1.7e-12;
5792 ctl->oh_chem[1] = 710;
5793 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
5794 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
5795 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
5796 ctl->molmass = 63.012;
5797 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
5798 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
5799 } else if (strcasecmp(ctl->species, "NO") == 0) {
5800 ctl->molmass = 30.006;
5801 ctl->oh_chem_reaction = 3;
5802 ctl->oh_chem[0] = 7.1e-31;
5803 ctl->oh_chem[1] = 2.6;
5804 ctl->oh_chem[2] = 3.6e-11;
5805 ctl->oh_chem[3] = 0.1;
5806 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
5807 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5808 } else if (strcasecmp(ctl->species, "NO2") == 0) {
5809 ctl->molmass = 46.005;
5810 ctl->oh_chem_reaction = 3;
5811 ctl->oh_chem[0] = 1.8e-30;
5812 ctl->oh_chem[1] = 3.0;
5813 ctl->oh_chem[2] = 2.8e-11;
5814 ctl->oh_chem[3] = 0.0;
5815 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
5816 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5817 } else if (strcasecmp(ctl->species, "O3") == 0) {
5818 ctl->molmass = 47.997;
5819 ctl->oh_chem_reaction = 2;
5820 ctl->oh_chem[0] = 1.7e-12;
5821 ctl->oh_chem[1] = 940;
5822 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
5823 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
5824 } else if (strcasecmp(ctl->species, "SF6") == 0) {
5825 ctl->molmass = 146.048;
5826 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
5827 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
5828 } else if (strcasecmp(ctl->species, "SO2") == 0) {
5829 ctl->molmass = 64.066;
5830 ctl->oh_chem_reaction = 3;
5831 ctl->oh_chem[0] = 2.9e-31;
5832 ctl->oh_chem[1] = 4.1;
5833 ctl->oh_chem[2] = 1.7e-12;
5834 ctl->oh_chem[3] = -0.2;
5835 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
5836 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
5837 }
5838
5839 /* Molar mass... */
5840 char defstr[LEN];
5841 sprintf(defstr, "%g", ctl->molmass);
5842 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
5843
5844 /* OH chemistry... */
5845 sprintf(defstr, "%d", ctl->oh_chem_reaction);
5846 ctl->oh_chem_reaction =
5847 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
5848 NULL);
5849 for (int ip = 0; ip < 4; ip++) {
5850 sprintf(defstr, "%g", ctl->oh_chem[ip]);
5851 ctl->oh_chem[ip] =
5852 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
5853 }
5854 ctl->oh_chem_beta =
5855 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
5856
5857 /* H2O2 chemistry... */
5858 ctl->h2o2_chem_reaction =
5859 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
5860
5861 /* KPP chemistry... */
5862 ctl->kpp_chem =
5863 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
5864 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
5865
5866 /* First order tracer chemistry... */
5867 ctl->tracer_chem =
5868 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
5869
5870 /* Radioactive decay... */
5871 ctl->radio_decay =
5872 (int) scan_ctl(filename, argc, argv, "RADIO_DECAY", -1, "0", NULL);
5873
5874 /* Wet deposition... */
5875 for (int ip = 0; ip < 2; ip++) {
5876 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
5877 ctl->wet_depo_ic_h[ip] =
5878 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
5879 }
5880 for (int ip = 0; ip < 1; ip++) {
5881 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
5882 ctl->wet_depo_bc_h[ip] =
5883 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
5884 }
5885 ctl->wet_depo_so2_ph =
5886 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
5887 ctl->wet_depo_ic_a =
5888 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
5889 ctl->wet_depo_ic_b =
5890 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
5891 ctl->wet_depo_bc_a =
5892 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
5893 ctl->wet_depo_bc_b =
5894 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
5895 ctl->wet_depo_pre[0] =
5896 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
5897 ctl->wet_depo_pre[1] =
5898 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
5900 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
5902 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
5903
5904 /* Dry deposition... */
5905 ctl->dry_depo_vdep =
5906 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
5907 ctl->dry_depo_dp =
5908 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
5909
5910 /* Climatological data... */
5911 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
5912 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
5913 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
5914 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
5915 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
5916 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
5917 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
5918 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
5919 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
5920 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
5921 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
5922 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
5923 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
5924 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
5925 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
5926 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
5927 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
5928 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
5929 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
5930 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
5931 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
5932 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
5933
5934 /* Mixing... */
5935 ctl->mixing_dt =
5936 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
5937 ctl->mixing_trop =
5938 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
5939 ctl->mixing_strat =
5940 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
5941 ctl->mixing_z0 =
5942 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
5943 ctl->mixing_z1 =
5944 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
5945 ctl->mixing_nz =
5946 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
5947 ctl->mixing_lon0 =
5948 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
5949 ctl->mixing_lon1 =
5950 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
5951 ctl->mixing_nx =
5952 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
5953 ctl->mixing_lat0 =
5954 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
5955 ctl->mixing_lat1 =
5956 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
5957 ctl->mixing_ny =
5958 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
5959
5960 /* Chemistry grid... */
5961 ctl->chemgrid_z0 =
5962 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
5963 ctl->chemgrid_z1 =
5964 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
5965 ctl->chemgrid_nz =
5966 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
5967 ctl->chemgrid_lon0 =
5968 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
5969 ctl->chemgrid_lon1 =
5970 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
5971 ctl->chemgrid_nx =
5972 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
5973 ctl->chemgrid_lat0 =
5974 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
5975 ctl->chemgrid_lat1 =
5976 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
5977 ctl->chemgrid_ny =
5978 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
5979
5980 /* Exponential decay... */
5981 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
5982 ctl->tdec_strat =
5983 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
5984
5985 /* PSC analysis... */
5986 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
5987 ctl->psc_hno3 =
5988 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
5989
5990 /* Output of atmospheric data... */
5991 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
5992 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
5993 ctl->atm_dt_out =
5994 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
5995 ctl->atm_filter =
5996 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
5997 ctl->atm_stride =
5998 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
5999 ctl->atm_type =
6000 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
6001 ctl->atm_type_out =
6002 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
6003 if (ctl->atm_type_out == -1)
6004 ctl->atm_type_out = ctl->atm_type;
6005 ctl->atm_nc_level =
6006 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
6007 for (int iq = 0; iq < ctl->nq; iq++)
6008 ctl->atm_nc_quant[iq] =
6009 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
6010 ctl->obs_type =
6011 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
6012
6013 /* Output of CSI data... */
6014 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
6015 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
6016 ctl->csi_dt_out =
6017 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
6018 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
6019 ctl->csi_obsmin =
6020 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
6021 ctl->csi_modmin =
6022 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
6023 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
6024 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
6025 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
6026 ctl->csi_lon0 =
6027 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
6028 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
6029 ctl->csi_nx =
6030 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
6031 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
6032 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
6033 ctl->csi_ny =
6034 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
6035
6036 /* Output of ensemble data... */
6037 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
6038 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
6039 ctl->ens_dt_out =
6040 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
6041
6042 /* Output of grid data... */
6043 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
6044 ctl->grid_basename);
6045 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
6046 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
6047 ctl->grid_dt_out =
6048 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
6049 ctl->grid_sparse =
6050 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
6051 ctl->grid_nc_level =
6052 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
6053 for (int iq = 0; iq < ctl->nq; iq++)
6054 ctl->grid_nc_quant[iq] =
6055 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
6056 ctl->grid_stddev =
6057 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
6058 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
6059 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
6060 ctl->grid_nz =
6061 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
6062 ctl->grid_lon0 =
6063 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
6064 ctl->grid_lon1 =
6065 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
6066 ctl->grid_nx =
6067 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
6068 ctl->grid_lat0 =
6069 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
6070 ctl->grid_lat1 =
6071 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
6072 ctl->grid_ny =
6073 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
6074 ctl->grid_type =
6075 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
6076
6077 /* Output of profile data... */
6078 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
6079 ctl->prof_basename);
6080 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
6081 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
6082 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
6083 ctl->prof_nz =
6084 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
6085 ctl->prof_lon0 =
6086 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
6087 ctl->prof_lon1 =
6088 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
6089 ctl->prof_nx =
6090 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
6091 ctl->prof_lat0 =
6092 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
6093 ctl->prof_lat1 =
6094 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
6095 ctl->prof_ny =
6096 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
6097
6098 /* Output of sample data... */
6099 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
6100 ctl->sample_basename);
6101 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
6102 ctl->sample_kernel);
6103 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
6104 ctl->sample_obsfile);
6105 ctl->sample_dx =
6106 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
6107 ctl->sample_dz =
6108 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
6109
6110 /* Output of station data... */
6111 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
6112 ctl->stat_basename);
6113 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
6114 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
6115 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
6116 ctl->stat_t0 =
6117 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
6118 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
6119
6120 /* Output of VTK data... */
6121 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
6122 ctl->vtk_dt_out =
6123 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
6124 ctl->vtk_stride =
6125 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
6126 ctl->vtk_scale =
6127 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
6128 ctl->vtk_offset =
6129 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
6130 ctl->vtk_sphere =
6131 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
6132
6133 /* Domain decomposition... */
6134 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
6136 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
6137 (ctl->dd == 1) ? "2" : "1", NULL);
6138 ctl->dd_subdomains_zonal =
6139 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
6140 (ctl->dd == 1) ? "2" : "1", NULL);
6142 ctl->dd = 1;
6143 else if (ctl->dd == 1)
6144 ERRMSG("Please provide zonal and meridional subdomain numbers!");
6145 ctl->dd_halos_size =
6146 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
6147}
6148
6149/*****************************************************************************/
6150
6152 const char *filename,
6153 const ctl_t *ctl,
6154 const clim_t *clim,
6155 met_t *met,
6156 dd_t *dd) {
6157
6158 /* Write info... */
6159 LOG(1, "Read meteo data: %s", filename);
6160
6161 /* Set rank... */
6162 int rank = 0;
6163#ifdef MPI
6164 if (ctl->met_mpi_share)
6165 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
6166#endif
6167
6168 /* Check rank... */
6169 if (!ctl->met_mpi_share || rank == 0) {
6170
6171 /* Read netCDF data... */
6172 if (ctl->met_type == 0) {
6173 if (read_met_nc(filename, ctl, met, dd) != 1)
6174 return 0;
6175 }
6176
6177 /* Read binary data... */
6178 else if ((ctl->met_type >= 1 && ctl->met_type <= 5) || ctl->met_type == 7) {
6179 if (read_met_bin(filename, ctl, met) != 1)
6180 return 0;
6181 }
6182
6183#ifdef ECCODES
6184 /* Read grib data... */
6185 else if (ctl->met_type == 6) {
6186 if (read_met_grib(filename, ctl, met) != 1)
6187 return 0;
6188 }
6189#endif
6190
6191 /* Not implemented... */
6192 else
6193 ERRMSG("MET_TYPE not implemented!");
6194
6195 /* Preprocessing for netCDF and grib files... */
6196 if (ctl->met_type == 0 || ctl->met_type == 6) {
6197
6198 /* Extrapolate data for lower boundary... */
6200
6201 /* Fix polar winds... */
6203
6204 /* Create periodic boundary conditions... */
6205#ifndef DD
6206 read_met_periodic(met);
6207#endif
6208
6209 /* Downsampling... */
6210 read_met_sample(ctl, met);
6211
6212 /* Calculate geopotential heights... */
6213 read_met_geopot(ctl, met);
6214
6215 /* Calculate potential vorticity... */
6216 read_met_pv(met);
6217
6218 /* Calculate boundary layer data... */
6219 read_met_pbl(ctl, met);
6220
6221 /* Calculate tropopause data... */
6222 read_met_tropo(ctl, clim, met);
6223
6224 /* Calculate cloud properties... */
6225 read_met_cloud(met);
6226
6227 /* Calculate convective available potential energy... */
6228 read_met_cape(ctl, clim, met);
6229
6230 /* Calculate total column ozone... */
6231 read_met_ozone(met);
6232
6233 /* Detrending... */
6234 read_met_detrend(ctl, met);
6235
6236 /* Check meteo data and smooth zeta profiles ... */
6237 read_met_monotonize(ctl, met);
6238 }
6239 }
6240
6241 /* Broadcast data via MPI... */
6242#ifdef MPI
6243 if (ctl->met_mpi_share) {
6244
6245 /* Set timer... */
6246 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM");
6247 LOG(2, "Broadcast data on rank %d...", rank);
6248
6249 /* Broadcast... */
6250 broadcast_large_data(met, sizeof(met_t));
6251 }
6252#endif
6253
6254 /* Return success... */
6255 return 1;
6256}
6257
6258/*****************************************************************************/
6259
6261 ctl_t *ctl,
6262 cache_t *cache,
6263 clim_t *clim,
6264 met_t **met0,
6265 met_t **met1,
6266 atm_t *atm,
6267 double t,
6268 dd_t *dd) {
6269
6270 /* Initialize modules... */
6271 if (t == ctl->t_start) {
6272
6273 /* Initialize isosurface data... */
6274 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6275 module_isosurf_init(ctl, cache, *met0, *met1, atm);
6276
6277 /* Initialize advection... */
6278 module_advect_init(ctl, cache, *met0, *met1, atm);
6279
6280 /* Initialize chemistry... */
6281 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
6282 }
6283
6284 /* Set time steps of air parcels... */
6285 module_timesteps(ctl, cache, *met0, atm, t);
6286
6287 /* Sort particles... */
6288 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
6289 module_sort(ctl, *met0, atm);
6290
6291 /* Check positions (initial)... */
6292 module_position(cache, *met0, *met1, atm);
6293
6294 /* Advection... */
6295 if (ctl->advect > 0)
6296 module_advect(ctl, cache, *met0, *met1, atm);
6297
6298 /* Turbulent diffusion... */
6299 if (ctl->diffusion == 1
6300 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
6301 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
6302 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
6303 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
6304
6305 /* Mesoscale diffusion... */
6306 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
6307 module_diff_meso(ctl, cache, *met0, *met1, atm);
6308
6309 /* Diffusion... */
6310 if (ctl->diffusion == 2)
6311 module_diff_pbl(ctl, cache, *met0, *met1, atm);
6312
6313 /* Convection... */
6314 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
6315 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
6316 module_convection(ctl, cache, *met0, *met1, atm);
6317
6318 /* Sedimentation... */
6319 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
6320 module_sedi(ctl, cache, *met0, *met1, atm);
6321
6322 /* Isosurface... */
6323 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6324 module_isosurf(ctl, cache, *met0, *met1, atm);
6325
6326 /* Check positions (final)... */
6327 module_position(cache, *met0, *met1, atm);
6328
6329 /* Interpolate meteo data... */
6330 if (ctl->met_dt_out > 0
6331 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
6332 module_meteo(ctl, cache, clim, *met0, *met1, atm);
6333
6334 /* Check boundary conditions (initial)... */
6335 if ((ctl->bound_lat0 < ctl->bound_lat1)
6336 && (ctl->bound_p0 > ctl->bound_p1))
6337 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6338
6339 /* Initialize quantity of total loss rate... */
6340 if (ctl->qnt_loss_rate >= 0) {
6341 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
6342 atm->q[ctl->qnt_loss_rate][ip] = 0;
6343 }
6344 }
6345
6346 /* Decay of particle mass... */
6347 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
6348 module_decay(ctl, cache, clim, atm);
6349
6350 /* Interparcel mixing... */
6351 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
6352 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
6353 module_mixing(ctl, clim, atm, t);
6354
6355 /* Calculate the tracer vmr in the chemistry grid... */
6356 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
6357 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
6358 module_chem_grid(ctl, *met0, *met1, atm, t);
6359
6360 /* OH chemistry... */
6361 if (ctl->oh_chem_reaction != 0)
6362 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
6363
6364 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
6365 if (ctl->h2o2_chem_reaction != 0)
6366 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
6367
6368 /* First-order tracer chemistry... */
6369 if (ctl->tracer_chem)
6370 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
6371
6372 /* Radioactive decay... */
6373 if (ctl->radio_decay)
6374 module_radio_decay(ctl, cache, atm);
6375
6376 /* Domain decomposition... */
6377 if (ctl->dd) {
6378#ifdef DD
6379 module_dd(ctl, cache, dd, atm, met0);
6380#else
6381 ERRMSG("Code was compiled without DD!");
6382
6383 /* This will never execute, hack to avoid compilation error... */
6384 LOG(3, "%d", dd->nx_glob);
6385#endif
6386 }
6387
6388 /* KPP chemistry... */
6389 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
6390#ifdef KPP
6391 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
6392#else
6393 ERRMSG("Code was compiled without KPP!");
6394#endif
6395 }
6396
6397 /* Wet deposition... */
6398 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
6399 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
6400 module_wet_depo(ctl, cache, *met0, *met1, atm);
6401
6402 /* Dry deposition... */
6403 if (ctl->dry_depo_vdep > 0)
6404 module_dry_depo(ctl, cache, *met0, *met1, atm);
6405
6406 /* Check boundary conditions (final)... */
6407 if ((ctl->bound_lat0 < ctl->bound_lat1)
6408 && (ctl->bound_p0 > ctl->bound_p1))
6409 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6410}
6411
6412/*****************************************************************************/
6413
6415 const ctl_t *ctl,
6416 const cache_t *cache,
6417 const clim_t *clim,
6418 met_t **met0,
6419 met_t **met1,
6420 const atm_t *atm) {
6421
6422 /* Update GPU... */
6423 if (ctl != NULL) {
6424#ifdef _OPENACC
6425 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6426#pragma acc update device(ctl[:1])
6427#endif
6428 }
6429
6430 if (cache != NULL) {
6431#ifdef _OPENACC
6432 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6433#pragma acc update device(cache[:1])
6434#endif
6435 }
6436
6437 if (clim != NULL) {
6438#ifdef _OPENACC
6439 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6440#pragma acc update device(clim[:1])
6441#endif
6442 }
6443
6444 if (met0 != NULL) {
6445#ifdef _OPENACC
6446 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6447 met_t *met0up = *met0;
6448#pragma acc update device(met0up[:1])
6449#endif
6450 }
6451
6452 if (met1 != NULL) {
6453#ifdef _OPENACC
6454 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6455 met_t *met1up = *met1;
6456#pragma acc update device(met1up[:1])
6457#endif
6458 }
6459
6460 if (atm != NULL) {
6461#ifdef _OPENACC
6462 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6463#pragma acc update device(atm[:1])
6464#endif
6465 }
6466}
6467
6468/*****************************************************************************/
6469
6471 const ctl_t *ctl,
6472 const cache_t *cache,
6473 const clim_t *clim,
6474 met_t **met0,
6475 met_t **met1,
6476 const atm_t *atm) {
6477
6478 /* Update GPU... */
6479 if (ctl != NULL) {
6480#ifdef _OPENACC
6481 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6482#pragma acc update host(ctl[:1])
6483#endif
6484 }
6485
6486 if (cache != NULL) {
6487#ifdef _OPENACC
6488 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6489#pragma acc update host(cache[:1])
6490#endif
6491 }
6492
6493 if (clim != NULL) {
6494#ifdef _OPENACC
6495 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6496#pragma acc update host(clim[:1])
6497#endif
6498 }
6499
6500 if (met0 != NULL) {
6501#ifdef _OPENACC
6502 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6503 met_t *met0up = *met0;
6504#pragma acc update host(met0up[:1])
6505#endif
6506 }
6507
6508 if (met1 != NULL) {
6509#ifdef _OPENACC
6510 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6511 met_t *met1up = *met1;
6512#pragma acc update host(met1up[:1])
6513#endif
6514 }
6515
6516 if (atm != NULL) {
6517#ifdef _OPENACC
6518 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6519#pragma acc update host(atm[:1])
6520#endif
6521 }
6522}
6523
6524/*****************************************************************************/
6525
6527 const char *filename,
6528 const ctl_t *ctl,
6529 const atm_t *atm,
6530 const double t) {
6531
6532 /* Set timer... */
6533 SELECT_TIMER("WRITE_ATM", "OUTPUT");
6534
6535 /* Write info... */
6536 LOG(1, "Write atmospheric data: %s", filename);
6537
6538 /* Write ASCII data... */
6539 if (ctl->atm_type_out == 0)
6540 write_atm_asc(filename, ctl, atm, t);
6541
6542 /* Write binary data... */
6543 else if (ctl->atm_type_out == 1)
6544 write_atm_bin(filename, ctl, atm);
6545
6546 /* Write netCDF data... */
6547 else if (ctl->atm_type_out == 2)
6548 write_atm_nc(filename, ctl, atm);
6549
6550 /* Write CLaMS trajectory data... */
6551 else if (ctl->atm_type_out == 3)
6552 write_atm_clams_traj(filename, ctl, atm, t);
6553
6554 /* Write CLaMS pos data... */
6555 else if (ctl->atm_type_out == 4)
6556 write_atm_clams(filename, ctl, atm);
6557
6558 /* Error... */
6559 else
6560 ERRMSG("Atmospheric data type not supported!");
6561
6562 /* Write info... */
6563 double mini, maxi;
6564 LOG(2, "Number of particles: %d", atm->np);
6565 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6566 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6567 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6568 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6569 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6570 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6571 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
6572 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6573 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
6574 for (int iq = 0; iq < ctl->nq; iq++) {
6575 char msg[5 * LEN];
6576 sprintf(msg, "Quantity %s range: %s ... %s %s",
6577 ctl->qnt_name[iq], ctl->qnt_format[iq],
6578 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6579 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6580 LOG(2, msg, mini, maxi);
6581 }
6582}
6583
6584/*****************************************************************************/
6585
6587 const char *filename,
6588 const ctl_t *ctl,
6589 met_t *met) {
6590
6591 /* Set timer... */
6592 SELECT_TIMER("WRITE_MET", "OUTPUT");
6593
6594 /* Write info... */
6595 LOG(1, "Write meteo data: %s", filename);
6596
6597 /* Check compression flags... */
6598#ifndef ZFP
6599 if (ctl->met_type == 3)
6600 ERRMSG("MPTRAC was compiled without ZFP compression!");
6601#endif
6602#ifndef ZSTD
6603 if (ctl->met_type == 4)
6604 ERRMSG("MPTRAC was compiled without ZSTD compression!");
6605#endif
6606#ifndef CMS
6607 if (ctl->met_type == 5)
6608 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6609#endif
6610#ifndef SZ3
6611 if (ctl->met_type == 7)
6612 ERRMSG("MPTRAC was compiled without SZ3 compression!");
6613#endif
6614
6615 /* Write netCDF data... */
6616 if (ctl->met_type == 0)
6617 write_met_nc(filename, ctl, met);
6618
6619 /* Write binary data... */
6620 else if (ctl->met_type >= 1 && ctl->met_type <= 7)
6621 write_met_bin(filename, ctl, met);
6622
6623 /* Not implemented... */
6624 else
6625 ERRMSG("MET_TYPE not implemented!");
6626}
6627
6628/*****************************************************************************/
6629
6631 const char *dirname,
6632 const ctl_t *ctl,
6633 met_t *met0,
6634 met_t *met1,
6635 atm_t *atm,
6636 const double t) {
6637
6638 char ext[10], filename[2 * LEN];
6639
6640 double r;
6641
6642 int year, mon, day, hour, min, sec;
6643
6644 /* Get time... */
6645 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
6646
6647 /* Update host... */
6648 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
6649 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
6650 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
6651 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
6652 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
6653 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
6654 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
6655
6656 /* Write atmospheric data... */
6657 if (ctl->atm_basename[0] != '-' &&
6658 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
6659 if (ctl->atm_type_out == 0)
6660 sprintf(ext, "tab");
6661 else if (ctl->atm_type_out == 1)
6662 sprintf(ext, "bin");
6663 else if (ctl->atm_type_out == 2)
6664 sprintf(ext, "nc");
6665 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6666 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
6667 mptrac_write_atm(filename, ctl, atm, t);
6668 }
6669
6670 /* Write gridded data... */
6671 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
6672 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6673 dirname, ctl->grid_basename, year, mon, day, hour, min,
6674 ctl->grid_type == 0 ? "tab" : "nc");
6675 write_grid(filename, ctl, met0, met1, atm, t);
6676 }
6677
6678 /* Write CSI data... */
6679 if (ctl->csi_basename[0] != '-') {
6680 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
6681 write_csi(filename, ctl, atm, t);
6682 }
6683
6684 /* Write ensemble data... */
6685 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
6686 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
6687 dirname, ctl->ens_basename, year, mon, day, hour, min);
6688 write_ens(filename, ctl, atm, t);
6689 }
6690
6691 /* Write profile data... */
6692 if (ctl->prof_basename[0] != '-') {
6693 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
6694 write_prof(filename, ctl, met0, met1, atm, t);
6695 }
6696
6697 /* Write sample data... */
6698 if (ctl->sample_basename[0] != '-') {
6699 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
6700 write_sample(filename, ctl, met0, met1, atm, t);
6701 }
6702
6703 /* Write station data... */
6704 if (ctl->stat_basename[0] != '-') {
6705 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
6706 write_station(filename, ctl, atm, t);
6707 }
6708
6709 /* Write VTK data... */
6710 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
6711 static int nvtk;
6712 if (t == ctl->t_start)
6713 nvtk = 0;
6714 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
6715 write_vtk(filename, ctl, atm, t);
6716 }
6717}
6718
6719/*****************************************************************************/
6720
6722 const double p,
6723 const double h2o,
6724 const double hno3) {
6725
6726 /* Check water vapor volume mixing ratio... */
6727 const double h2o_help = MAX(h2o, 0.1e-6);
6728
6729 /* Calculate T_NAT... */
6730 const double p_hno3 = hno3 * p / 1.333224;
6731 const double p_h2o = h2o_help * p / 1.333224;
6732 const double a = 0.009179 - 0.00088 * log10(p_h2o);
6733 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
6734 const double c = -11397.0 / a;
6735 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
6736 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
6737 if (x2 > 0)
6738 tnat = x2;
6739
6740 return tnat;
6741}
6742
6743/*****************************************************************************/
6744
6746 const ctl_t *ctl,
6747 const atm_t *atm,
6748 const int ip,
6749 const double pbl,
6750 const double ps) {
6751
6752 /* Get pressure range... */
6753 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
6754 const double p0 = pbl;
6755
6756 /* Get weighting factor... */
6757 if (atm->p[ip] > p0)
6758 return 1;
6759 else if (atm->p[ip] < p1)
6760 return 0;
6761 else
6762 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
6763}
6764
6765/*****************************************************************************/
6766
6768 const char *filename,
6769 const ctl_t *ctl,
6770 atm_t *atm) {
6771
6772 /* Open file... */
6773 FILE *in;
6774 if (!(in = fopen(filename, "r"))) {
6775 WARN("Cannot open file!");
6776 return 0;
6777 }
6778
6779 /* Read line... */
6780 char line[LEN];
6781 while (fgets(line, LEN, in)) {
6782
6783 /* Read data... */
6784 char *tok;
6785 TOK(line, tok, "%lg", atm->time[atm->np]);
6786 TOK(NULL, tok, "%lg", atm->p[atm->np]);
6787 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
6788 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
6789 for (int iq = 0; iq < ctl->nq; iq++)
6790 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
6791
6792 /* Convert altitude to pressure... */
6793 atm->p[atm->np] = P(atm->p[atm->np]);
6794
6795 /* Increment data point counter... */
6796 if ((++atm->np) > NP)
6797 ERRMSG("Too many data points!");
6798 }
6799
6800 /* Close file... */
6801 fclose(in);
6802
6803 /* Return success... */
6804 return 1;
6805}
6806
6807/*****************************************************************************/
6808
6810 const char *filename,
6811 const ctl_t *ctl,
6812 atm_t *atm) {
6813
6814 /* Open file... */
6815 FILE *in;
6816 if (!(in = fopen(filename, "r")))
6817 return 0;
6818
6819 /* Check version of binary data... */
6820 int version;
6821 FREAD(&version, int,
6822 1,
6823 in);
6824 if (version != 100)
6825 ERRMSG("Wrong version of binary data!");
6826
6827 /* Read data... */
6828 FREAD(&atm->np, int,
6829 1,
6830 in);
6831 FREAD(atm->time, double,
6832 (size_t) atm->np,
6833 in);
6834 FREAD(atm->p, double,
6835 (size_t) atm->np,
6836 in);
6837 FREAD(atm->lon, double,
6838 (size_t) atm->np,
6839 in);
6840 FREAD(atm->lat, double,
6841 (size_t) atm->np,
6842 in);
6843 for (int iq = 0; iq < ctl->nq; iq++)
6844 FREAD(atm->q[iq], double,
6845 (size_t) atm->np,
6846 in);
6847
6848 /* Read final flag... */
6849 int final;
6850 FREAD(&final, int,
6851 1,
6852 in);
6853 if (final != 999)
6854 ERRMSG("Error while reading binary data!");
6855
6856 /* Close file... */
6857 fclose(in);
6858
6859 /* Return success... */
6860 return 1;
6861}
6862
6863/*****************************************************************************/
6864
6866 const char *filename,
6867 const ctl_t *ctl,
6868 atm_t *atm) {
6869
6870 int ncid, varid;
6871
6872 /* Open file... */
6873 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6874 return 0;
6875
6876 /* Get dimensions... */
6877 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
6878
6879 /* Get time... */
6880 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
6881 NC(nc_get_var_double(ncid, varid, atm->time));
6882 } else {
6883 WARN("TIME_INIT not found use time instead!");
6884 double time_init;
6885 NC_GET_DOUBLE("time", &time_init, 1);
6886 for (int ip = 0; ip < atm->np; ip++) {
6887 atm->time[ip] = time_init;
6888 }
6889 }
6890
6891 /* Read zeta coordinate, pressure is optional... */
6892 if (ctl->advect_vert_coord == 1) {
6893 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
6894 NC_GET_DOUBLE("PRESS", atm->p, 0);
6895 }
6896
6897 /* Read pressure, zeta coordinate is optional... */
6898 else {
6899 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
6900 NC(nc_get_var_double(ncid, varid, atm->p));
6901 } else {
6902 WARN("PRESS_INIT not found use PRESS instead!");
6903 nc_inq_varid(ncid, "PRESS", &varid);
6904 NC(nc_get_var_double(ncid, varid, atm->p));
6905 }
6906 }
6907
6908 /* Read further quantities if requested... */
6909 for (int iq = 0; iq < ctl->nq; iq++)
6910 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6911
6912 /* Read longitude and latitude... */
6913 NC_GET_DOUBLE("LON", atm->lon, 1);
6914 NC_GET_DOUBLE("LAT", atm->lat, 1);
6915
6916 /* Close file... */
6917 NC(nc_close(ncid));
6918
6919 /* Return success... */
6920 return 1;
6921}
6922
6923/*****************************************************************************/
6924
6926 const char *filename,
6927 const ctl_t *ctl,
6928 atm_t *atm) {
6929
6930 int ncid, varid;
6931
6932 /* Open file... */
6933 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6934 return 0;
6935
6936 /* Get dimensions... */
6937 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
6938
6939 /* Read geolocations... */
6940 NC_GET_DOUBLE("time", atm->time, 1);
6941 NC_GET_DOUBLE("press", atm->p, 1);
6942 NC_GET_DOUBLE("lon", atm->lon, 1);
6943 NC_GET_DOUBLE("lat", atm->lat, 1);
6944
6945 /* Read variables... */
6946 for (int iq = 0; iq < ctl->nq; iq++)
6947 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6948
6949 /* Close file... */
6950 NC(nc_close(ncid));
6951
6952 /* Return success... */
6953 return 1;
6954}
6955
6956/*****************************************************************************/
6957
6959 const char *filename,
6960 clim_photo_t *photo) {
6961
6962 int ncid, varid;
6963
6964 /* Write info... */
6965 LOG(1, "Read photolysis rates: %s", filename);
6966
6967 /* Open netCDF file... */
6968 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6969 WARN("Photolysis rate data are missing!");
6970 return;
6971 }
6972
6973 /* Read pressure data... */
6974 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
6975 NC_GET_DOUBLE("press", photo->p, 1);
6976 if (photo->p[0] < photo->p[1])
6977 ERRMSG("Pressure data are not descending!");
6978
6979 /* Read total column ozone data... */
6980 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
6981 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
6982 if (photo->o3c[0] > photo->o3c[1])
6983 ERRMSG("Total column ozone data are not ascending!");
6984
6985 /* Read solar zenith angle data... */
6986 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
6987 NC_GET_DOUBLE("sza", photo->sza, 1);
6988 if (photo->sza[0] > photo->sza[1])
6989 ERRMSG("Solar zenith angle data are not ascending!");
6990
6991 /* Read data... */
6992 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
6993 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
6994 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
6995 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
6996 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
6997 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
6998 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
6999 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
7000 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
7001
7002 /* Close netCDF file... */
7003 NC(nc_close(ncid));
7004
7005 /* Write info... */
7006 LOG(2, "Number of pressure levels: %d", photo->np);
7007 LOG(2, "Altitude levels: %g, %g ... %g km",
7008 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
7009 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7010 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
7011 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
7012 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
7013 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
7014 RAD2DEG(photo->sza[photo->nsza - 1]));
7015 LOG(2, "Number of total column ozone values: %d", photo->no3c);
7016 LOG(2, "Total column ozone: %g, %g ... %g DU",
7017 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
7018 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
7019 photo->n2o[0][0][0], photo->n2o[1][0][0],
7020 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7021 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
7022 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
7023 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7024 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
7025 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
7026 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7027 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
7028 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
7029 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7030 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
7031 photo->o2[0][0][0], photo->o2[1][0][0],
7032 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7033 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
7034 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
7035 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7036 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
7037 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
7038 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7039 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
7040 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
7041 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7042 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
7043 photo->h2o[0][0][0], photo->h2o[1][0][0],
7044 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7045}
7046
7047/*****************************************************************************/
7048
7050 const int ncid,
7051 const char *varname,
7052 const clim_photo_t *photo,
7053 double var[CP][CSZA][CO3]) {
7054
7055 /* Allocate... */
7056 double *help;
7057 ALLOC(help, double,
7058 photo->np * photo->nsza * photo->no3c);
7059
7060 /* Read varible... */
7061 int varid;
7062 NC_GET_DOUBLE(varname, help, 1);
7063
7064 /* Copy data... */
7065 for (int ip = 0; ip < photo->np; ip++)
7066 for (int is = 0; is < photo->nsza; is++)
7067 for (int io = 0; io < photo->no3c; io++)
7068 var[ip][is][io] =
7069 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
7070
7071 /* Free... */
7072 free(help);
7073}
7074
7075/*****************************************************************************/
7076
7078 const char *filename,
7079 clim_ts_t *ts) {
7080
7081 /* Write info... */
7082 LOG(1, "Read climatological time series: %s", filename);
7083
7084 /* Open file... */
7085 FILE *in;
7086 if (!(in = fopen(filename, "r"))) {
7087 WARN("Cannot open file!");
7088 return 0;
7089 }
7090
7091 /* Read data... */
7092 char line[LEN];
7093 int nh = 0;
7094 while (fgets(line, LEN, in))
7095 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
7096
7097 /* Convert years to seconds... */
7098 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
7099
7100 /* Check data... */
7101 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
7102 ERRMSG("Time series must be ascending!");
7103
7104 /* Count time steps... */
7105 if ((++nh) >= CTS)
7106 ERRMSG("Too many data points!");
7107 }
7108
7109 /* Close file... */
7110 fclose(in);
7111
7112 /* Check number of data points... */
7113 ts->ntime = nh;
7114 if (nh < 2)
7115 ERRMSG("Not enough data points!");
7116
7117 /* Write info... */
7118 LOG(2, "Number of time steps: %d", ts->ntime);
7119 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
7120 ts->time[nh - 1]);
7121 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
7122 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
7123 (size_t) nh));
7124
7125 /* Exit success... */
7126 return 1;
7127}
7128
7129/*****************************************************************************/
7130
7132 const char *filename,
7133 const char *varname,
7134 clim_zm_t *zm) {
7135
7136 int ncid, varid, it, iy, iz, iz2, nt;
7137
7138 double *help, varmin = 1e99, varmax = -1e99;
7139
7140 /* Write info... */
7141 LOG(1, "Read %s data: %s", varname, filename);
7142
7143 /* Open netCDF file... */
7144 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7145 WARN("%s climatology data are missing!", varname);
7146 return;
7147 }
7148
7149 /* Read pressure data... */
7150 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
7151 NC_GET_DOUBLE("press", zm->p, 1);
7152 if (zm->p[0] < zm->p[1])
7153 ERRMSG("Pressure data are not descending!");
7154
7155 /* Read latitudes... */
7156 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
7157 NC_GET_DOUBLE("lat", zm->lat, 1);
7158 if (zm->lat[0] > zm->lat[1])
7159 ERRMSG("Latitude data are not ascending!");
7160
7161 /* Set time data (for monthly means)... */
7162 zm->ntime = 12;
7163 zm->time[0] = 1209600.00;
7164 zm->time[1] = 3888000.00;
7165 zm->time[2] = 6393600.00;
7166 zm->time[3] = 9072000.00;
7167 zm->time[4] = 11664000.00;
7168 zm->time[5] = 14342400.00;
7169 zm->time[6] = 16934400.00;
7170 zm->time[7] = 19612800.00;
7171 zm->time[8] = 22291200.00;
7172 zm->time[9] = 24883200.00;
7173 zm->time[10] = 27561600.00;
7174 zm->time[11] = 30153600.00;
7175
7176 /* Check number of timesteps... */
7177 NC_INQ_DIM("time", &nt, 12, 12, 1);
7178
7179 /* Read data... */
7180 ALLOC(help, double,
7181 zm->nlat * zm->np * zm->ntime);
7182 NC_GET_DOUBLE(varname, help, 1);
7183 for (it = 0; it < zm->ntime; it++)
7184 for (iz = 0; iz < zm->np; iz++)
7185 for (iy = 0; iy < zm->nlat; iy++)
7186 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
7187 free(help);
7188
7189 /* Fix data gaps... */
7190 for (it = 0; it < zm->ntime; it++)
7191 for (iy = 0; iy < zm->nlat; iy++)
7192 for (iz = 0; iz < zm->np; iz++) {
7193 if (zm->vmr[it][iz][iy] < 0) {
7194 for (iz2 = 0; iz2 < zm->np; iz2++)
7195 if (zm->vmr[it][iz2][iy] >= 0) {
7196 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7197 break;
7198 }
7199 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
7200 if (zm->vmr[it][iz2][iy] >= 0) {
7201 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7202 break;
7203 }
7204 }
7205 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
7206 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
7207 }
7208
7209 /* Close netCDF file... */
7210 NC(nc_close(ncid));
7211
7212 /* Write info... */
7213 LOG(2, "Number of time steps: %d", zm->ntime);
7214 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
7215 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
7216 LOG(2, "Number of pressure levels: %d", zm->np);
7217 LOG(2, "Altitude levels: %g, %g ... %g km",
7218 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
7219 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
7220 zm->p[1], zm->p[zm->np - 1]);
7221 LOG(2, "Number of latitudes: %d", zm->nlat);
7222 LOG(2, "Latitudes: %g, %g ... %g deg",
7223 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
7224 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
7225 varmax);
7226}
7227
7228/*****************************************************************************/
7229
7231 const char *filename,
7232 double kz[EP],
7233 double kw[EP],
7234 int *nk) {
7235
7236 /* Write info... */
7237 LOG(1, "Read kernel function: %s", filename);
7238
7239 /* Open file... */
7240 FILE *in;
7241 if (!(in = fopen(filename, "r")))
7242 ERRMSG("Cannot open file!");
7243
7244 /* Read data... */
7245 char line[LEN];
7246 int n = 0;
7247 while (fgets(line, LEN, in))
7248 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
7249 if (n > 0 && kz[n] < kz[n - 1])
7250 ERRMSG("Height levels must be ascending!");
7251 if ((++n) >= EP)
7252 ERRMSG("Too many height levels!");
7253 }
7254
7255 /* Close file... */
7256 fclose(in);
7257
7258 /* Check number of data points... */
7259 *nk = n;
7260 if (n < 2)
7261 ERRMSG("Not enough height levels!");
7262
7263 /* Normalize kernel function... */
7264 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
7265 for (int iz = 0; iz < n; iz++)
7266 kw[iz] /= kmax;
7267}
7268
7269/*****************************************************************************/
7270
7272 const char *filename,
7273 const ctl_t *ctl,
7274 met_t *met) {
7275
7276 FILE *in;
7277
7278 double r;
7279
7280 int year, mon, day, hour, min, sec;
7281
7282 /* Set timer... */
7283 SELECT_TIMER("READ_MET_BIN", "INPUT");
7284
7285 /* Open file... */
7286 if (!(in = fopen(filename, "r"))) {
7287 WARN("Cannot open file!");
7288 return 0;
7289 }
7290
7291 /* Check type of binary data... */
7292 int met_type;
7293 FREAD(&met_type, int,
7294 1,
7295 in);
7296 if (met_type != ctl->met_type)
7297 ERRMSG("Wrong MET_TYPE of binary data!");
7298
7299 /* Check version of binary data... */
7300 int version;
7301 FREAD(&version, int,
7302 1,
7303 in);
7304 if (version != 103)
7305 ERRMSG("Wrong version of binary data!");
7306
7307 /* Read time... */
7308 FREAD(&met->time, double,
7309 1,
7310 in);
7311 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7312 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7313 met->time, year, mon, day, hour, min);
7314 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7315 || day < 1 || day > 31 || hour < 0 || hour > 23)
7316 ERRMSG("Error while reading time!");
7317
7318 /* Read dimensions... */
7319 FREAD(&met->nx, int,
7320 1,
7321 in);
7322 LOG(2, "Number of longitudes: %d", met->nx);
7323 if (met->nx < 2 || met->nx > EX)
7324 ERRMSG("Number of longitudes out of range!");
7325
7326 FREAD(&met->ny, int,
7327 1,
7328 in);
7329 LOG(2, "Number of latitudes: %d", met->ny);
7330 if (met->ny < 2 || met->ny > EY)
7331 ERRMSG("Number of latitudes out of range!");
7332
7333 FREAD(&met->np, int,
7334 1,
7335 in);
7336 LOG(2, "Number of levels: %d", met->np);
7337 if (met->np < 2 || met->np > EP)
7338 ERRMSG("Number of levels out of range!");
7339
7340 /* Read grid... */
7341 FREAD(met->lon, double,
7342 (size_t) met->nx,
7343 in);
7344 LOG(2, "Longitudes: %g, %g ... %g deg",
7345 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7346
7347 FREAD(met->lat, double,
7348 (size_t) met->ny,
7349 in);
7350 LOG(2, "Latitudes: %g, %g ... %g deg",
7351 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7352
7353 FREAD(met->p, double,
7354 (size_t) met->np,
7355 in);
7356 LOG(2, "Altitude levels: %g, %g ... %g km",
7357 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7358 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7359 met->p[0], met->p[1], met->p[met->np - 1]);
7360
7361 /* Read surface data... */
7362 read_met_bin_2d(in, met, met->ps, "PS");
7363 read_met_bin_2d(in, met, met->ts, "TS");
7364 read_met_bin_2d(in, met, met->zs, "ZS");
7365 read_met_bin_2d(in, met, met->us, "US");
7366 read_met_bin_2d(in, met, met->vs, "VS");
7367 read_met_bin_2d(in, met, met->ess, "ESS");
7368 read_met_bin_2d(in, met, met->nss, "NSS");
7369 read_met_bin_2d(in, met, met->shf, "SHF");
7370 read_met_bin_2d(in, met, met->lsm, "LSM");
7371 read_met_bin_2d(in, met, met->sst, "SST");
7372 read_met_bin_2d(in, met, met->pbl, "PBL");
7373 read_met_bin_2d(in, met, met->pt, "PT");
7374 read_met_bin_2d(in, met, met->tt, "TT");
7375 read_met_bin_2d(in, met, met->zt, "ZT");
7376 read_met_bin_2d(in, met, met->h2ot, "H2OT");
7377 read_met_bin_2d(in, met, met->pct, "PCT");
7378 read_met_bin_2d(in, met, met->pcb, "PCB");
7379 read_met_bin_2d(in, met, met->cl, "CL");
7380 read_met_bin_2d(in, met, met->plcl, "PLCL");
7381 read_met_bin_2d(in, met, met->plfc, "PLFC");
7382 read_met_bin_2d(in, met, met->pel, "PEL");
7383 read_met_bin_2d(in, met, met->cape, "CAPE");
7384 read_met_bin_2d(in, met, met->cin, "CIN");
7385 read_met_bin_2d(in, met, met->o3c, "O3C");
7386
7387 /* Read level data... */
7388 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
7389 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
7390 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
7391 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
7392 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
7393 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
7394 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
7395 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
7396 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
7397 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
7398 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
7399 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
7400 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
7401
7402 /* Read final flag... */
7403 int final;
7404 FREAD(&final, int,
7405 1,
7406 in);
7407 if (final != 999)
7408 ERRMSG("Error while reading binary data!");
7409
7410 /* Close file... */
7411 fclose(in);
7412
7413 /* Return success... */
7414 return 1;
7415}
7416
7417/*****************************************************************************/
7418
7420 FILE *in,
7421 const met_t *met,
7422 float var[EX][EY],
7423 const char *varname) {
7424
7425 float *help;
7426
7427 /* Allocate... */
7428 ALLOC(help, float,
7429 EX * EY);
7430
7431 /* Read uncompressed... */
7432 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
7433 FREAD(help, float,
7434 (size_t) (met->nx * met->ny),
7435 in);
7436
7437 /* Copy data... */
7438 for (int ix = 0; ix < met->nx; ix++)
7439 for (int iy = 0; iy < met->ny; iy++)
7440 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
7441
7442 /* Free... */
7443 free(help);
7444}
7445
7446/*****************************************************************************/
7447
7449 FILE *in,
7450 const ctl_t *ctl,
7451 const met_t *met,
7452 float var[EX][EY][EP],
7453 const char *varname,
7454 const float bound_min,
7455 const float bound_max) {
7456
7457 float *help;
7458
7459 /* Allocate... */
7460 ALLOC(help, float,
7461 EX * EY * EP);
7462
7463 /* Read uncompressed data... */
7464 if (ctl->met_type == 1) {
7465 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
7466 FREAD(help, float,
7467 (size_t) (met->nx * met->ny * met->np),
7468 in);
7469 }
7470
7471 /* Read packed data... */
7472 else if (ctl->met_type == 2)
7473 compress_pck(varname, help, (size_t) (met->ny * met->nx),
7474 (size_t) met->np, 1, in);
7475
7476 /* Read ZFP data... */
7477 else if (ctl->met_type == 3) {
7478#ifdef ZFP
7479 int precision;
7480 FREAD(&precision, int,
7481 1,
7482 in);
7483
7484 double tolerance;
7485 FREAD(&tolerance, double,
7486 1,
7487 in);
7488
7489 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
7490 tolerance, 1, in);
7491#else
7492 ERRMSG("MPTRAC was compiled without ZFP compression!");
7493#endif
7494 }
7495
7496 /* Read zstd data... */
7497 else if (ctl->met_type == 4) {
7498#ifdef ZSTD
7499 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
7500 ctl->met_zstd_level, in);
7501#else
7502 ERRMSG("MPTRAC was compiled without ZSTD compression!");
7503#endif
7504 }
7505
7506 /* Read cmultiscale data... */
7507 else if (ctl->met_type == 5) {
7508#ifdef CMS
7509 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
7510 (size_t) met->np, met->p, 1, in);
7511#else
7512 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
7513#endif
7514 }
7515
7516 /* Read SZ3 data... */
7517 else if (ctl->met_type == 7) {
7518#ifdef SZ3
7519 int precision;
7520 FREAD(&precision, int,
7521 1,
7522 in);
7523
7524 double tolerance;
7525 FREAD(&tolerance, double,
7526 1,
7527 in);
7528
7529 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
7530 tolerance, 1, in);
7531#else
7532 ERRMSG("MPTRAC was compiled without sz3 compression!");
7533#endif
7534 }
7535
7536 /* Copy data... */
7537#pragma omp parallel for default(shared) collapse(2)
7538 for (int ix = 0; ix < met->nx; ix++)
7539 for (int iy = 0; iy < met->ny; iy++)
7540 for (int ip = 0; ip < met->np; ip++) {
7541 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7542 if (var[ix][iy][ip] < bound_min)
7543 var[ix][iy][ip] = bound_min;
7544 else if (var[ix][iy][ip] > bound_max)
7545 var[ix][iy][ip] = bound_max;
7546 }
7547
7548 /* Free... */
7549 free(help);
7550}
7551
7552/*****************************************************************************/
7553
7555 const ctl_t *ctl,
7556 const clim_t *clim,
7557 met_t *met) {
7558
7559 /* Check parameters... */
7560 if (ctl->met_cape != 1)
7561 return;
7562
7563 /* Set timer... */
7564 SELECT_TIMER("READ_MET_CAPE", "METPROC");
7565 LOG(2, "Calculate CAPE...");
7566
7567 /* Vertical spacing (about 100 m)... */
7568 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
7569
7570 /* Loop over columns... */
7571#pragma omp parallel for default(shared) collapse(2)
7572 for (int ix = 0; ix < met->nx; ix++)
7573 for (int iy = 0; iy < met->ny; iy++) {
7574
7575 /* Get potential temperature and water vapor at lowest 50 hPa... */
7576 int n = 0;
7577 double h2o = 0, t, theta = 0;
7578 double pbot = MIN(met->ps[ix][iy], met->p[0]);
7579 double ptop = pbot - 50.;
7580 for (int ip = 0; ip < met->np; ip++) {
7581 if (met->p[ip] <= pbot) {
7582 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
7583 h2o += met->h2o[ix][iy][ip];
7584 n++;
7585 }
7586 if (met->p[ip] < ptop && n > 0)
7587 break;
7588 }
7589 theta /= n;
7590 h2o /= n;
7591
7592 /* Cannot compute anything if water vapor is missing... */
7593 met->plcl[ix][iy] = NAN;
7594 met->plfc[ix][iy] = NAN;
7595 met->pel[ix][iy] = NAN;
7596 met->cape[ix][iy] = NAN;
7597 met->cin[ix][iy] = NAN;
7598 if (h2o <= 0)
7599 continue;
7600
7601 /* Find lifted condensation level (LCL)... */
7602 ptop = P(20.);
7603 pbot = met->ps[ix][iy];
7604 do {
7605 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
7606 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
7607 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
7608 ptop = met->plcl[ix][iy];
7609 else
7610 pbot = met->plcl[ix][iy];
7611 } while (pbot - ptop > 0.1);
7612
7613 /* Calculate CIN up to LCL... */
7615 double dcape, dz, h2o_env, t_env;
7616 double p = met->ps[ix][iy];
7617 met->cape[ix][iy] = met->cin[ix][iy] = 0;
7618 do {
7619 dz = dz0 * TVIRT(t, h2o);
7620 p /= pfac;
7621 t = theta / pow(1000. / p, 0.286);
7622 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7623 &t_env, ci, cw, 1);
7624 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7625 &h2o_env, ci, cw, 0);
7626 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7627 TVIRT(t_env, h2o_env) * dz;
7628 if (dcape < 0)
7629 met->cin[ix][iy] += fabsf((float) dcape);
7630 } while (p > met->plcl[ix][iy]);
7631
7632 /* Calculate level of free convection (LFC), equilibrium level (EL),
7633 and convective available potential energy (CAPE)... */
7634 dcape = 0;
7635 p = met->plcl[ix][iy];
7636 t = theta / pow(1000. / p, 0.286);
7637 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
7638 do {
7639 dz = dz0 * TVIRT(t, h2o);
7640 p /= pfac;
7641 t -= lapse_rate(t, h2o) * dz;
7642 double psat = PSAT(t);
7643 h2o = psat / (p - (1. - EPS) * psat);
7644 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7645 &t_env, ci, cw, 1);
7646 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7647 &h2o_env, ci, cw, 0);
7648 double dcape_old = dcape;
7649 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7650 TVIRT(t_env, h2o_env) * dz;
7651 if (dcape > 0) {
7652 met->cape[ix][iy] += (float) dcape;
7653 if (!isfinite(met->plfc[ix][iy]))
7654 met->plfc[ix][iy] = (float) p;
7655 } else if (dcape_old > 0)
7656 met->pel[ix][iy] = (float) p;
7657 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
7658 met->cin[ix][iy] += fabsf((float) dcape);
7659 } while (p > ptop);
7660
7661 /* Check results... */
7662 if (!isfinite(met->plfc[ix][iy]))
7663 met->cin[ix][iy] = NAN;
7664 }
7665}
7666
7667/*****************************************************************************/
7668
7670 met_t *met) {
7671
7672 /* Set timer... */
7673 SELECT_TIMER("READ_MET_CLOUD", "METPROC");
7674 LOG(2, "Calculate cloud data...");
7675
7676 /* Thresholds for cloud detection... */
7677 const double ccmin = 0.01, cwmin = 1e-6;
7678
7679 /* Loop over columns... */
7680#pragma omp parallel for default(shared) collapse(2)
7681 for (int ix = 0; ix < met->nx; ix++)
7682 for (int iy = 0; iy < met->ny; iy++) {
7683
7684 /* Init... */
7685 met->pct[ix][iy] = NAN;
7686 met->pcb[ix][iy] = NAN;
7687 met->cl[ix][iy] = 0;
7688
7689 /* Loop over pressure levels... */
7690 for (int ip = 0; ip < met->np - 1; ip++) {
7691
7692 /* Check pressure... */
7693 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
7694 continue;
7695
7696 /* Check ice water and liquid water content... */
7697 if (met->cc[ix][iy][ip] > ccmin
7698 && (met->lwc[ix][iy][ip] > cwmin
7699 || met->rwc[ix][iy][ip] > cwmin
7700 || met->iwc[ix][iy][ip] > cwmin
7701 || met->swc[ix][iy][ip] > cwmin)) {
7702
7703 /* Get cloud top pressure ... */
7704 met->pct[ix][iy]
7705 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
7706
7707 /* Get cloud bottom pressure ... */
7708 if (!isfinite(met->pcb[ix][iy]))
7709 met->pcb[ix][iy]
7710 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
7711 }
7712
7713 /* Get cloud water... */
7714 met->cl[ix][iy] += (float)
7715 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
7716 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
7717 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
7718 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
7719 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
7720 }
7721 }
7722}
7723
7724/*****************************************************************************/
7725
7727 const ctl_t *ctl,
7728 met_t *met) {
7729
7730 met_t *help;
7731
7732 /* Check parameters... */
7733 if (ctl->met_detrend <= 0)
7734 return;
7735
7736 /* Set timer... */
7737 SELECT_TIMER("READ_MET_DETREND", "METPROC");
7738 LOG(2, "Detrend meteo data...");
7739
7740 /* Allocate... */
7741 ALLOC(help, met_t, 1);
7742
7743 /* Calculate standard deviation... */
7744 const double sigma = ctl->met_detrend / 2.355;
7745 const double tssq = 2. * SQR(sigma);
7746
7747 /* Calculate box size in latitude... */
7748 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
7749 sy = MIN(MAX(1, sy), met->ny / 2);
7750
7751 /* Calculate background... */
7752#pragma omp parallel for default(shared) collapse(2)
7753 for (int ix = 0; ix < met->nx; ix++) {
7754 for (int iy = 0; iy < met->ny; iy++) {
7755
7756 /* Calculate Cartesian coordinates... */
7757 double x0[3];
7758 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
7759
7760 /* Calculate box size in longitude... */
7761 int sx =
7762 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
7763 fabs(met->lon[1] - met->lon[0]));
7764 sx = MIN(MAX(1, sx), met->nx / 2);
7765
7766 /* Init... */
7767 float wsum = 0;
7768 for (int ip = 0; ip < met->np; ip++) {
7769 help->t[ix][iy][ip] = 0;
7770 help->u[ix][iy][ip] = 0;
7771 help->v[ix][iy][ip] = 0;
7772 help->w[ix][iy][ip] = 0;
7773 }
7774
7775 /* Loop over neighboring grid points... */
7776 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
7777 int ix3 = ix2;
7778 if (ix3 < 0)
7779 ix3 += met->nx;
7780 else if (ix3 >= met->nx)
7781 ix3 -= met->nx;
7782 for (int iy2 = MAX(iy - sy, 0);
7783 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
7784
7785 /* Calculate Cartesian coordinates... */
7786 double x1[3];
7787 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
7788
7789 /* Calculate weighting factor... */
7790 const float w = (float) exp(-DIST2(x0, x1) / tssq);
7791
7792 /* Add data... */
7793 wsum += w;
7794 for (int ip = 0; ip < met->np; ip++) {
7795 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
7796 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
7797 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
7798 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
7799 }
7800 }
7801 }
7802
7803 /* Normalize... */
7804 for (int ip = 0; ip < met->np; ip++) {
7805 help->t[ix][iy][ip] /= wsum;
7806 help->u[ix][iy][ip] /= wsum;
7807 help->v[ix][iy][ip] /= wsum;
7808 help->w[ix][iy][ip] /= wsum;
7809 }
7810 }
7811 }
7812
7813 /* Subtract background... */
7814#pragma omp parallel for default(shared) collapse(3)
7815 for (int ix = 0; ix < met->nx; ix++)
7816 for (int iy = 0; iy < met->ny; iy++)
7817 for (int ip = 0; ip < met->np; ip++) {
7818 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
7819 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
7820 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
7821 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
7822 }
7823
7824 /* Free... */
7825 free(help);
7826}
7827
7828/*****************************************************************************/
7829
7831 met_t *met) {
7832
7833 /* Set timer... */
7834 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC");
7835 LOG(2, "Extrapolate meteo data...");
7836
7837 /* Loop over columns... */
7838#pragma omp parallel for default(shared) collapse(2)
7839 for (int ix = 0; ix < met->nx; ix++)
7840 for (int iy = 0; iy < met->ny; iy++) {
7841
7842 /* Find lowest valid data point... */
7843 int ip0;
7844 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
7845 if (!isfinite(met->t[ix][iy][ip0])
7846 || !isfinite(met->u[ix][iy][ip0])
7847 || !isfinite(met->v[ix][iy][ip0])
7848 || !isfinite(met->w[ix][iy][ip0]))
7849 break;
7850
7851 /* Extrapolate... */
7852 for (int ip = ip0; ip >= 0; ip--) {
7853 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
7854 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
7855 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
7856 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
7857 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
7858 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
7859 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
7860 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
7861 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
7862 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
7863 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
7864 }
7865 }
7866}
7867
7868/*****************************************************************************/
7869
7871 const ctl_t *ctl,
7872 met_t *met) {
7873
7874 float *help;
7875
7876 double logp[EP];
7877
7878 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
7879
7880 /* Set timer... */
7881 SELECT_TIMER("READ_MET_GEOPOT", "METPROC");
7882 LOG(2, "Calculate geopotential heights...");
7883
7884 /* Allocate... */
7885 ALLOC(help, float,
7886 EX * EY * EP);
7887
7888 /* Calculate log pressure... */
7889#pragma omp parallel for default(shared)
7890 for (int ip = 0; ip < met->np; ip++)
7891 logp[ip] = log(met->p[ip]);
7892
7893 /* Apply hydrostatic equation to calculate geopotential heights... */
7894#pragma omp parallel for default(shared) collapse(2)
7895 for (int ix = 0; ix < met->nx; ix++)
7896 for (int iy = 0; iy < met->ny; iy++) {
7897
7898 /* Get surface height and pressure... */
7899 const double zs = met->zs[ix][iy];
7900 const double lnps = log(met->ps[ix][iy]);
7901
7902 /* Get temperature and water vapor at the surface... */
7903 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
7904 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
7905 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
7906 const double h2os =
7907 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
7908 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
7909
7910 /* Upper part of profile... */
7911 met->z[ix][iy][ip0 + 1]
7912 = (float) (zs +
7913 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
7914 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
7915 for (int ip = ip0 + 2; ip < met->np; ip++)
7916 met->z[ix][iy][ip]
7917 = (float) (met->z[ix][iy][ip - 1] +
7918 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
7919 met->h2o[ix][iy][ip - 1], logp[ip],
7920 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7921
7922 /* Lower part of profile... */
7923 met->z[ix][iy][ip0]
7924 = (float) (zs +
7925 ZDIFF(lnps, ts, h2os, logp[ip0],
7926 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
7927 for (int ip = ip0 - 1; ip >= 0; ip--)
7928 met->z[ix][iy][ip]
7929 = (float) (met->z[ix][iy][ip + 1] +
7930 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
7931 met->h2o[ix][iy][ip + 1], logp[ip],
7932 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7933 }
7934
7935 /* Check control parameters... */
7936 if (dx == 0 || dy == 0)
7937 return;
7938
7939 /* Default smoothing parameters... */
7940 if (dx < 0 || dy < 0) {
7941 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
7942 dx = 3;
7943 dy = 2;
7944 } else {
7945 dx = 6;
7946 dy = 4;
7947 }
7948 }
7949
7950 /* Calculate weights for smoothing... */
7951 float ws[dx + 1][dy + 1];
7952#pragma omp parallel for default(shared) collapse(2)
7953 for (int ix = 0; ix <= dx; ix++)
7954 for (int iy = 0; iy < dy; iy++)
7955 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
7956 * (1.0f - (float) iy / (float) dy);
7957
7958 /* Copy data... */
7959#pragma omp parallel for default(shared) collapse(3)
7960 for (int ix = 0; ix < met->nx; ix++)
7961 for (int iy = 0; iy < met->ny; iy++)
7962 for (int ip = 0; ip < met->np; ip++)
7963 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
7964
7965 /* Horizontal smoothing... */
7966#pragma omp parallel for default(shared) collapse(3)
7967 for (int ip = 0; ip < met->np; ip++)
7968 for (int ix = 0; ix < met->nx; ix++)
7969 for (int iy = 0; iy < met->ny; iy++) {
7970 float res = 0, wsum = 0;
7971 int iy0 = MAX(iy - dy + 1, 0);
7972 int iy1 = MIN(iy + dy - 1, met->ny - 1);
7973 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
7974 int ix3 = ix2;
7975 if (ix3 < 0)
7976 ix3 += met->nx;
7977 else if (ix3 >= met->nx)
7978 ix3 -= met->nx;
7979 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
7980 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
7981 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
7982 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
7983 wsum += w;
7984 }
7985 }
7986 if (wsum > 0)
7987 met->z[ix][iy][ip] = res / wsum;
7988 else
7989 met->z[ix][iy][ip] = NAN;
7990 }
7991
7992 /* Free... */
7993 free(help);
7994}
7995
7996/*****************************************************************************/
7997
7999 const char *filename,
8000 const int ncid,
8001 const ctl_t *ctl,
8002 met_t *met,
8003 dd_t *dd) {
8004
8005 char levname[LEN], tstr[10];
8006
8007 double rtime = 0, r, r2;
8008
8009 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
8010 year, mon, day, hour, min, sec;
8011
8012 size_t dimlen;
8013
8014 /* Set timer... */
8015 SELECT_TIMER("READ_MET_NC_GRID", "INPUT");
8016 LOG(2, "Read meteo grid information...");
8017
8018 /* MPTRAC meteo files... */
8019 if (!ctl->met_clams) {
8020
8021 /* Get time from filename... */
8022 met->time = time_from_filename(filename, 16);
8023
8024 /* Check time information from data file... */
8025 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8026 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
8027 NC(nc_get_var_double(ncid, varid, &rtime));
8028 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
8029 WARN("Time information in meteo file does not match filename!");
8030 } else
8031 WARN("Time information in meteo file is missing!");
8032 }
8033
8034 /* CLaMS meteo files... */
8035 else {
8036
8037 /* Read time from file... */
8038 NC_GET_DOUBLE("time", &rtime, 0);
8039
8040 /* Get time from filename (considering the century)... */
8041 if (rtime < 0)
8042 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
8043 else
8044 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
8045 year = atoi(tstr);
8046 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
8047 mon = atoi(tstr);
8048 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
8049 day = atoi(tstr);
8050 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
8051 hour = atoi(tstr);
8052 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
8053 }
8054
8055 /* Check time... */
8056 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8057 || day < 1 || day > 31 || hour < 0 || hour > 23)
8058 ERRMSG("Cannot read time from filename!");
8059 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
8060 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8061 met->time, year2, mon2, day2, hour2, min2);
8062
8063 /* Get vertical dimension... */
8064 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
8065 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
8066 ERRMSG
8067 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
8068
8069 NC(nc_inq_varndims(ncid, varid, &ndims));
8070 NC(nc_inq_vardimid(ncid, varid, dimids));
8071
8072 if (ndims == 4) {
8073 NC(nc_inq_dim
8074 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
8075 } else if (ndims == 3) {
8076 NC(nc_inq_dim
8077 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
8078 } else
8079 ERRMSG("Cannot determine vertical dimension!")
8080 met->np = (int) dimlen;
8081
8082 LOG(2, "Number of levels: %d", met->np);
8083 if (met->np < 2 || met->np > EP)
8084 ERRMSG("Number of levels out of range!");
8085
8086 if (!ctl->dd) {
8087
8088 /* Get grid dimensions... */
8089 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
8090 LOG(2, "Number of longitudes: %d", met->nx);
8091
8092 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
8093 LOG(2, "Number of latitudes: %d", met->ny);
8094
8095 /* Read longitudes and latitudes... */
8096 NC_GET_DOUBLE("lon", met->lon, 1);
8097 LOG(2, "Longitudes: %g, %g ... %g deg",
8098 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
8099 NC_GET_DOUBLE("lat", met->lat, 1);
8100 LOG(2, "Latitudes: %g, %g ... %g deg",
8101 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
8102
8103 } else {
8104
8105 /* Use 'naive', i.e. equidistant lat-lon domain decomposition... */
8106 read_met_nc_grid_dd_naive(dd, ctl, met, ncid);
8107
8108 }
8109
8110 /* Read pressure levels... */
8111 if (ctl->met_np <= 0) {
8112 NC_GET_DOUBLE(levname, met->p, 1);
8113 for (int ip = 0; ip < met->np; ip++)
8114 met->p[ip] /= 100.;
8115 LOG(2, "Altitude levels: %g, %g ... %g km",
8116 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
8117 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8118 met->p[0], met->p[1], met->p[met->np - 1]);
8119 }
8120
8121 /* Read hybrid levels... */
8122 if (strcasecmp(levname, "hybrid") == 0)
8123 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
8124
8125 /* Read model level coefficients from file... */
8126 if (ctl->met_vert_coord == 2) {
8127 NC_GET_DOUBLE("hyam", met->hyam, 1);
8128 NC_GET_DOUBLE("hybm", met->hybm, 1);
8129 }
8130
8131 /* Copy model level coefficients from control parameters... */
8132 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
8133 if (ctl->met_nlev <= 0)
8134 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
8135 for (int ip = 0; ip < ctl->met_nlev; ip++) {
8136 met->hyam[ip] = ctl->met_lev_hyam[ip];
8137 met->hybm[ip] = ctl->met_lev_hybm[ip];
8138 }
8139 }
8140
8141 /* Calculate eta levels... */
8142 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
8143 met->eta[k] = met->hyam[k] / 100000.0 + met->hybm[k];
8144 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
8145 ERRMSG("Eta levels must be ascending!");
8146 }
8147
8148 /* Check horizontal grid spacing... */
8149 for (int ix = 2; ix < met->nx; ix++)
8150 if (fabs
8151 (fabs(met->lon[ix] - met->lon[ix - 1]) -
8152 fabs(met->lon[1] - met->lon[0])) > 0.001)
8153 ERRMSG("No regular grid spacing in longitudes!");
8154 for (int iy = 2; iy < met->ny; iy++)
8155 if (fabs
8156 (fabs(met->lat[iy] - met->lat[iy - 1]) -
8157 fabs(met->lat[1] - met->lat[0])) > 0.001) {
8158 WARN("No regular grid spacing in latitudes!");
8159 break;
8160 }
8161}
8162
8163/*****************************************************************************/
8164
8166 const int ncid,
8167 const ctl_t *ctl,
8168 met_t *met,
8169 dd_t *dd) {
8170
8171 /* Set timer... */
8172 SELECT_TIMER("READ_MET_SURFACE", "INPUT");
8173 LOG(2, "Read surface data...");
8174
8175 /* Read surface pressure... */
8176 if (read_met_nc_2d
8177 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
8178 1.0f, 1)) {
8179 for (int ix = 0; ix < met->nx; ix++)
8180 for (int iy = 0; iy < met->ny; iy++)
8181 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8182 } else
8183 if (!read_met_nc_2d
8184 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
8185 0.01f, 1)) {
8186 WARN("Cannot not read surface pressure data (use lowest level)!");
8187 for (int ix = 0; ix < met->nx; ix++)
8188 for (int iy = 0; iy < met->ny; iy++)
8189 met->ps[ix][iy]
8190 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
8191 }
8192
8193 /* MPTRAC meteo data... */
8194 if (ctl->met_clams == 0) {
8195
8196 /* Read geopotential height at the surface... */
8197 if (!read_met_nc_2d
8198 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8199 (float) (1. / (1000. * G0)), 1))
8200 if (!read_met_nc_2d
8201 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8202 (float) (1. / 1000.), 1))
8203 WARN("Cannot read surface geopotential height!");
8204 }
8205
8206 /* CLaMS meteo data... */
8207 else {
8208
8209 /* Read geopotential height at the surface
8210 (use lowermost level of 3-D data field)... */
8211 float *help;
8212 ALLOC(help, float,
8213 EX * EY * EP);
8214 memcpy(help, met->pl, sizeof(met->pl));
8215 if (!read_met_nc_3d
8216 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
8217 (float) (1e-3 / G0)))
8218 ERRMSG("Cannot read geopotential height!");
8219 for (int ix = 0; ix < met->nx; ix++)
8220 for (int iy = 0; iy < met->ny; iy++)
8221 met->zs[ix][iy] = met->pl[ix][iy][0];
8222 memcpy(met->pl, help, sizeof(met->pl));
8223 free(help);
8224 }
8225
8226 /* Read temperature at the surface... */
8227 if (!read_met_nc_2d
8228 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
8229 1))
8230 WARN("Cannot read surface temperature!");
8231
8232 /* Read zonal wind at the surface... */
8233 if (!read_met_nc_2d
8234 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
8235 met->us, 1.0, 1))
8236 WARN("Cannot read surface zonal wind!");
8237
8238 /* Read meridional wind at the surface... */
8239 if (!read_met_nc_2d
8240 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
8241 met->vs, 1.0, 1))
8242 WARN("Cannot read surface meridional wind!");
8243
8244 /* Read eastward turbulent surface stress... */
8245 if (!read_met_nc_2d
8246 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
8247 1.0, 1))
8248 WARN("Cannot read eastward turbulent surface stress!");
8249
8250 /* Read northward turbulent surface stress... */
8251 if (!read_met_nc_2d
8252 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
8253 1.0, 1))
8254 WARN("Cannot read nothward turbulent surface stress!");
8255
8256 /* Read surface sensible heat flux... */
8257 if (!read_met_nc_2d
8258 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
8259 1.0, 1))
8260 WARN("Cannot read surface sensible heat flux!");
8261
8262 /* Read land-sea mask... */
8263 if (!read_met_nc_2d
8264 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
8265 1.0, 1))
8266 WARN("Cannot read land-sea mask!");
8267
8268 /* Read sea surface temperature... */
8269 if (!read_met_nc_2d
8270 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
8271 1.0, 1))
8272 WARN("Cannot read sea surface temperature!");
8273
8274 /* Read PBL... */
8275 if (ctl->met_pbl == 0)
8276 if (!read_met_nc_2d
8277 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8278 0.01f, 1))
8279 WARN("Cannot read planetary boundary layer pressure!");
8280 if (ctl->met_pbl == 1)
8281 if (!read_met_nc_2d
8282 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8283 0.001f, 1))
8284 WARN("Cannot read planetary boundary layer height!");
8285
8286 /* Read CAPE... */
8287 if (ctl->met_cape == 0)
8288 if (!read_met_nc_2d
8289 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
8290 met->cape, 1.0, 1))
8291 WARN("Cannot read CAPE!");
8292
8293 /* Read CIN... */
8294 if (ctl->met_cape == 0)
8295 if (!read_met_nc_2d
8296 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
8297 1.0, 1))
8298 WARN("Cannot read convective inhibition!");
8299}
8300
8301/*****************************************************************************/
8302
8304 const int ncid,
8305 const ctl_t *ctl,
8306 met_t *met,
8307 dd_t *dd) {
8308
8309 /* Set timer... */
8310 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT");
8311 LOG(2, "Read level data...");
8312
8313 /* Read temperature... */
8314 if (!read_met_nc_3d
8315 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
8316 ERRMSG("Cannot read temperature!");
8317
8318 /* Read horizontal wind and vertical velocity... */
8319 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
8320 ERRMSG("Cannot read zonal wind!");
8321 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
8322 ERRMSG("Cannot read meridional wind!");
8323 if (!read_met_nc_3d
8324 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
8325 WARN("Cannot read vertical velocity!");
8326
8327 /* Read water vapor... */
8328 if (!ctl->met_relhum) {
8329 if (!read_met_nc_3d
8330 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
8331 (float) (MA / MH2O)))
8332 WARN("Cannot read specific humidity!");
8333 } else {
8334 if (!read_met_nc_3d
8335 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
8336 WARN("Cannot read relative humidity!");
8337#pragma omp parallel for default(shared) collapse(2)
8338 for (int ix = 0; ix < met->nx; ix++)
8339 for (int iy = 0; iy < met->ny; iy++)
8340 for (int ip = 0; ip < met->np; ip++) {
8341 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
8342 met->h2o[ix][iy][ip] =
8343 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
8344 }
8345 }
8346
8347 /* Read ozone... */
8348 if (!read_met_nc_3d
8349 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
8350 (float) (MA / MO3)))
8351 WARN("Cannot read ozone data!");
8352
8353 /* Read cloud data... */
8354 if (!read_met_nc_3d
8355 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
8356 WARN("Cannot read cloud liquid water content!");
8357 if (!read_met_nc_3d
8358 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
8359 WARN("Cannot read cloud rain water content!");
8360 if (!read_met_nc_3d
8361 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
8362 WARN("Cannot read cloud ice water content!");
8363 if (!read_met_nc_3d
8364 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
8365 WARN("Cannot read cloud snow water content!");
8366 if (!read_met_nc_3d
8367 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
8368 WARN("Cannot read cloud cover!");
8369
8370 /* Read zeta and zeta_dot... */
8371 if (ctl->advect_vert_coord == 1) {
8372 if (!read_met_nc_3d
8373 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
8374 WARN("Cannot read ZETA!");
8375 if (!read_met_nc_3d
8376 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
8377 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
8378 WARN("Cannot read ZETA_DOT!");
8379 }
8380
8381 /* Read eta and eta_dot... */
8382 else if (ctl->advect_vert_coord == 3) {
8383#pragma omp parallel for default(shared)
8384 for (int ix = 0; ix < met->nx; ix++)
8385 for (int iy = 0; iy < met->ny; iy++)
8386 for (int ip = 0; ip < met->np; ip++)
8387 met->zetal[ix][iy][ip] =
8388 (float) (met->hyam[ip] / 100000.0 + met->hybm[ip]);
8389 if (!read_met_nc_3d
8390 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
8391 1.0))
8392 WARN("Cannot read eta vertical velocity!");
8393 }
8394
8395 /* Store velocities on model levels... */
8396 if (ctl->met_vert_coord != 0) {
8397#pragma omp parallel for default(shared)
8398 for (int ix = 0; ix < met->nx; ix++)
8399 for (int iy = 0; iy < met->ny; iy++)
8400 for (int ip = 0; ip < met->np; ip++) {
8401 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
8402 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
8403 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
8404 }
8405
8406 /* Save number of model levels... */
8407 met->npl = met->np;
8408 }
8409
8410 /* Get pressure on model levels... */
8411 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
8412
8413 /* Read 3-D pressure field... */
8414 if (ctl->met_vert_coord == 1) {
8415 if (!read_met_nc_3d
8416 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
8417 0.01f))
8418 if (!read_met_nc_3d
8419 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
8420 ERRMSG("Cannot read pressure on model levels!");
8421 }
8422
8423 /* Use a and b coefficients for full levels (at layer midpoints)... */
8424 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
8425
8426 /* Check number of levels... */
8427 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
8428 ERRMSG("Mismatch in number of model levels!");
8429
8430 /* Calculate pressure... */
8431 for (int ix = 0; ix < met->nx; ix++)
8432 for (int iy = 0; iy < met->ny; iy++)
8433 for (int ip = 0; ip < met->np; ip++)
8434 met->pl[ix][iy][ip] =
8435 (float) (met->hyam[ip] / 100. +
8436 met->hybm[ip] * met->ps[ix][iy]);
8437 }
8438
8439 /* Use a and b coefficients for half levels (at layer interfaces)... */
8440 else if (ctl->met_vert_coord == 4) {
8441
8442 /* Check number of levels... */
8443 if (met->np + 1 != ctl->met_nlev)
8444 ERRMSG("Mismatch in number of model levels!");
8445
8446 /* Calculate pressure... */
8447#pragma omp parallel for default(shared) collapse(2)
8448 for (int ix = 0; ix < met->nx; ix++)
8449 for (int iy = 0; iy < met->ny; iy++)
8450 for (int ip = 0; ip < met->np; ip++) {
8451 const double p0 =
8452 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
8453 const double p1 =
8454 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
8455 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
8456 }
8457 }
8458
8459 /* Check ordering of pressure levels... */
8460 for (int ix = 0; ix < met->nx; ix++)
8461 for (int iy = 0; iy < met->ny; iy++)
8462 for (int ip = 1; ip < met->np; ip++)
8463 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
8464 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
8465 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
8466 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
8467 ERRMSG("Pressure profiles are not monotonic!");
8468 }
8469
8470 /* Interpolate from model levels to pressure levels... */
8471 if (ctl->met_np > 0) {
8472
8473 /* Interpolate variables... */
8474 read_met_ml2pl(ctl, met, met->t, "T");
8475 read_met_ml2pl(ctl, met, met->u, "U");
8476 read_met_ml2pl(ctl, met, met->v, "V");
8477 read_met_ml2pl(ctl, met, met->w, "W");
8478 read_met_ml2pl(ctl, met, met->h2o, "H2O");
8479 read_met_ml2pl(ctl, met, met->o3, "O3");
8480 read_met_ml2pl(ctl, met, met->lwc, "LWC");
8481 read_met_ml2pl(ctl, met, met->rwc, "RWC");
8482 read_met_ml2pl(ctl, met, met->iwc, "IWC");
8483 read_met_ml2pl(ctl, met, met->swc, "SWC");
8484 read_met_ml2pl(ctl, met, met->cc, "CC");
8485
8486 /* Set new pressure levels... */
8487 met->np = ctl->met_np;
8488 for (int ip = 0; ip < met->np; ip++)
8489 met->p[ip] = ctl->met_p[ip];
8490 }
8491
8492 /* Check ordering of pressure levels... */
8493 for (int ip = 1; ip < met->np; ip++)
8494 if (met->p[ip - 1] < met->p[ip])
8495 ERRMSG("Pressure levels must be descending!");
8496}
8497
8498/*****************************************************************************/
8499
8501 const int ncid,
8502 const char *varname,
8503 const char *varname2,
8504 const char *varname3,
8505 const char *varname4,
8506 const char *varname5,
8507 const char *varname6,
8508 const ctl_t *ctl,
8509 const met_t *met,
8510 dd_t *dd,
8511 float dest[EX][EY],
8512 const float scl,
8513 const int init) {
8514
8515 char varsel[LEN];
8516
8517 float offset, scalfac;
8518
8519 int varid;
8520
8521 /* Check if variable exists... */
8522 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8523 sprintf(varsel, "%s", varname);
8524 else if (varname2 != NULL
8525 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8526 sprintf(varsel, "%s", varname2);
8527 else if (varname3 != NULL
8528 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8529 sprintf(varsel, "%s", varname3);
8530 else if (varname4 != NULL
8531 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8532 sprintf(varsel, "%s", varname4);
8533 else if (varname5 != NULL
8534 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
8535 sprintf(varsel, "%s", varname5);
8536 else if (varname6 != NULL
8537 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
8538 sprintf(varsel, "%s", varname6);
8539 else
8540 return 0;
8541
8542 /* Read packed data... */
8543 if (ctl->met_nc_scale && !ctl->dd
8544 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8545 && nc_get_att_float(ncid, varid, "scale_factor",
8546 &scalfac) == NC_NOERR) {
8547
8548 /* Allocate... */
8549 short *help;
8550 ALLOC(help, short,
8551 EX * EY * EP);
8552
8553 /* Read fill value and missing value... */
8554 short fillval, missval;
8555 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8556 fillval = 0;
8557 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
8558 missval = 0;
8559
8560 /* Write info... */
8561 LOG(2, "Read 2-D variable: %s"
8562 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
8563 varsel, fillval, missval, scalfac, offset);
8564
8565 /* Read data... */
8566 NC(nc_get_var_short(ncid, varid, help));
8567
8568 /* Check meteo data layout... */
8569 if (ctl->met_convention != 0)
8570 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
8571
8572 /* Copy and check data... */
8573 omp_set_dynamic(1);
8574#pragma omp parallel for default(shared)
8575 for (int ix = 0; ix < met->nx; ix++)
8576 for (int iy = 0; iy < met->ny; iy++) {
8577 if (init)
8578 dest[ix][iy] = 0;
8579 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
8580 if ((fillval == 0 || aux != fillval)
8581 && (missval == 0 || aux != missval)
8582 && fabsf(aux * scalfac + offset) < 1e14f)
8583 dest[ix][iy] += scl * (aux * scalfac + offset);
8584 else
8585 dest[ix][iy] = NAN;
8586 }
8587 omp_set_dynamic(0);
8588
8589 /* Free... */
8590 free(help);
8591 }
8592
8593 /* Unpacked data... */
8594 else if (!ctl->dd) {
8595
8596 /* Allocate... */
8597 float *help;
8598 ALLOC(help, float,
8599 EX * EY);
8600
8601 /* Read fill value and missing value... */
8602 float fillval, missval;
8603 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8604 fillval = 0;
8605 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8606 missval = 0;
8607
8608 /* Write info... */
8609 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8610 varsel, fillval, missval);
8611
8612 /* Read data... */
8613 NC(nc_get_var_float(ncid, varid, help));
8614
8615 /* Check meteo data layout... */
8616 if (ctl->met_convention == 0) {
8617
8618 /* Copy and check data (ordering: lat, lon)... */
8619 omp_set_dynamic(1);
8620#pragma omp parallel for default(shared)
8621 for (int ix = 0; ix < met->nx; ix++)
8622 for (int iy = 0; iy < met->ny; iy++) {
8623 if (init)
8624 dest[ix][iy] = 0;
8625 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
8626 if ((fillval == 0 || aux != fillval)
8627 && (missval == 0 || aux != missval)
8628 && fabsf(aux) < 1e14f)
8629 dest[ix][iy] += scl * aux;
8630 else
8631 dest[ix][iy] = NAN;
8632 }
8633 omp_set_dynamic(0);
8634
8635 } else {
8636
8637 /* Copy and check data (ordering: lon, lat)... */
8638 omp_set_dynamic(1);
8639#pragma omp parallel for default(shared)
8640 for (int iy = 0; iy < met->ny; iy++)
8641 for (int ix = 0; ix < met->nx; ix++) {
8642 if (init)
8643 dest[ix][iy] = 0;
8644 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
8645 if ((fillval == 0 || aux != fillval)
8646 && (missval == 0 || aux != missval)
8647 && fabsf(aux) < 1e14f)
8648 dest[ix][iy] += scl * aux;
8649 else
8650 dest[ix][iy] = NAN;
8651 }
8652 omp_set_dynamic(0);
8653 }
8654
8655 /* Free... */
8656 free(help);
8657 }
8658
8659 /* Domain decomposed data... */
8660 else {
8661
8662 /* Read fill value and missing value... */
8663 float fillval, missval;
8664 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8665 fillval = 0;
8666 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8667 missval = 0;
8668
8669 /* Write info... */
8670 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8671 varsel, fillval, missval);
8672
8673 /* Define hyperslab... */
8674 float *help;
8675 size_t help_subdomain_start[3];
8676 size_t help_subdomain_count[3];
8677
8678 help_subdomain_start[0] = 0;
8679 if (ctl->met_convention == 0) {
8680 help_subdomain_start[1] = dd->subdomain_start[2];
8681 help_subdomain_start[2] = dd->subdomain_start[3];
8682 } else {
8683 help_subdomain_start[1] = dd->subdomain_start[3];
8684 help_subdomain_start[2] = dd->subdomain_start[2];
8685 }
8686
8687 help_subdomain_count[0] = 1;
8688 if (ctl->met_convention == 0) {
8689 help_subdomain_count[1] = dd->subdomain_count[2]; //y
8690 help_subdomain_count[2] = dd->subdomain_count[3]; //x
8691 } else {
8692 help_subdomain_count[1] = dd->subdomain_count[3]; //x
8693 help_subdomain_count[2] = dd->subdomain_count[2]; //y
8694 }
8695
8696 ALLOC(help, float,
8697 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
8698
8699 /* Read data... */
8700#ifdef DD
8701 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
8702#endif
8703 NC(nc_get_vara_float
8704 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
8705
8706 /* Read halos at boundaries... */
8707 size_t help_halo_bnd_start[3];
8708 size_t help_halo_bnd_count[3];
8709
8710 help_halo_bnd_start[0] = 0;
8711 if (ctl->met_convention == 0) {
8712 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
8713 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
8714 } else {
8715 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
8716 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
8717 }
8718
8719 help_halo_bnd_count[0] = 1;
8720 if (ctl->met_convention == 0) {
8721 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
8722 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
8723 } else {
8724 help_halo_bnd_count[1] = dd->halo_bnd_count[3]; //x
8725 help_halo_bnd_count[2] = dd->halo_bnd_count[2]; //y
8726 }
8727
8728 float *help_halo;
8729 ALLOC(help_halo, float,
8730 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
8731
8732#ifdef DD
8733 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
8734#endif
8735 NC(nc_get_vara_float
8736 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
8737
8738 /* Check meteo data layout... */
8739 if (ctl->met_convention == 0) {
8740
8741 /* Copy and check data (ordering: lat, lon)... */
8742 omp_set_dynamic(1);
8743#pragma omp parallel for default(shared)
8744 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
8745 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
8746 if (init == 1)
8747 dest[ix + dd->halo_offset_start][iy] = 0;
8748 const float aux =
8749 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
8750 if ((fillval == 0 || aux != fillval)
8751 && (missval == 0 || aux != missval)
8752 && fabsf(aux) < 1e14f) {
8753 dest[ix + dd->halo_offset_start][iy] += scl * aux;
8754 } else
8755 dest[ix + dd->halo_offset_start][iy] = NAN;
8756 }
8757
8758#pragma omp parallel for default(shared)
8759 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
8760 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
8761 if (init == 1)
8762 dest[ix + dd->halo_offset_end][iy] = 0;
8763 const float aux =
8764 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
8765 if ((fillval == 0 || aux != fillval)
8766 && (missval == 0 || aux != missval)
8767 && fabsf(aux) < 1e14f)
8768 dest[ix + dd->halo_offset_end][iy] += scl * aux;
8769 else {
8770 dest[ix + dd->halo_offset_end][iy] = NAN;
8771 }
8772 }
8773 omp_set_dynamic(0);
8774
8775 } else {
8776
8777 /* Copy and check data (ordering: lon, lat)... */
8778 omp_set_dynamic(1);
8779#pragma omp parallel for default(shared)
8780 for (int ix = 0; ix < (int) help_subdomain_count[1]; ix++)
8781 for (int iy = 0; iy < (int) help_subdomain_count[2]; iy++) {
8782 if (init == 1)
8783 dest[ix + dd->halo_offset_start][iy] = 0;
8784 const float aux =
8785 help[ARRAY_2D(ix, iy, (int) help_subdomain_count[1])];
8786 if ((fillval == 0 || aux != fillval)
8787 && (missval == 0 || aux != missval)
8788 && fabsf(aux) < 1e14f)
8789 dest[ix + dd->halo_offset_start][iy] += scl * aux;
8790 else
8791 dest[ix + dd->halo_offset_start][iy] = NAN;
8792 }
8793
8794#pragma omp parallel for default(shared)
8795 for (int ix = 0; ix < (int) help_halo_bnd_count[1]; ix++)
8796 for (int iy = 0; iy < (int) help_halo_bnd_count[2]; iy++) {
8797 if (init == 1)
8798 dest[ix + dd->halo_offset_end][iy] = 0;
8799 const float aux =
8800 help_halo[ARRAY_2D(ix, iy, (int) help_halo_bnd_count[1])];
8801 if ((fillval == 0 || aux != fillval)
8802 && (missval == 0 || aux != missval)
8803 && fabsf(aux) < 1e14f)
8804 dest[ix + dd->halo_offset_end][iy] += scl * aux;
8805 else
8806 dest[ix + dd->halo_offset_end][iy] = NAN;
8807 }
8808 omp_set_dynamic(0);
8809 }
8810
8811 /* Free... */
8812 free(help);
8813 free(help_halo);
8814 }
8815
8816 /* Return... */
8817 return 1;
8818}
8819
8820/*****************************************************************************/
8821
8823 const int ncid,
8824 const char *varname,
8825 const char *varname2,
8826 const char *varname3,
8827 const char *varname4,
8828 const ctl_t *ctl,
8829 const met_t *met,
8830 dd_t *dd,
8831 float dest[EX][EY][EP],
8832 const float scl) {
8833
8834 SELECT_TIMER("read_met_nc_3d", "INPUT");
8835
8836 char varsel[LEN];
8837
8838 float offset, scalfac;
8839
8840 int varid;
8841
8842 /* Check if variable exists... */
8843 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8844 sprintf(varsel, "%s", varname);
8845 else if (varname2 != NULL
8846 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8847 sprintf(varsel, "%s", varname2);
8848 else if (varname3 != NULL
8849 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8850 sprintf(varsel, "%s", varname3);
8851 else if (varname4 != NULL
8852 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8853 sprintf(varsel, "%s", varname4);
8854 else
8855 return 0;
8856
8857 /* Read packed data... */
8858 if (ctl->met_nc_scale && !ctl->dd
8859 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8860 && nc_get_att_float(ncid, varid, "scale_factor",
8861 &scalfac) == NC_NOERR) {
8862
8863 /* Allocate... */
8864 short *help;
8865 ALLOC(help, short,
8866 EX * EY * EP);
8867
8868 /* Read fill value and missing value... */
8869 short fillval, missval;
8870 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8871 fillval = 0;
8872 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
8873 missval = 0;
8874
8875 /* Write info... */
8876 LOG(2, "Read 3-D variable: %s "
8877 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
8878 varsel, fillval, missval, scalfac, offset);
8879
8880 /* Read data... */
8881 NC(nc_get_var_short(ncid, varid, help));
8882
8883 /* Check meteo data layout... */
8884 if (ctl->met_convention != 0)
8885 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
8886
8887 /* Copy and check data... */
8888 omp_set_dynamic(1);
8889#pragma omp parallel for default(shared)
8890 for (int ix = 0; ix < met->nx; ix++)
8891 for (int iy = 0; iy < met->ny; iy++)
8892 for (int ip = 0; ip < met->np; ip++) {
8893 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
8894 if ((fillval == 0 || aux != fillval)
8895 && (missval == 0 || aux != missval)
8896 && fabsf(aux * scalfac + offset) < 1e14f)
8897 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
8898 else
8899 dest[ix][iy][ip] = NAN;
8900 }
8901 omp_set_dynamic(0);
8902
8903 /* Free... */
8904 free(help);
8905 }
8906
8907 /* Unpacked data... */
8908 else if (!ctl->dd) {
8909
8910 /* Allocate... */
8911 float *help;
8912 ALLOC(help, float,
8913 EX * EY * EP);
8914
8915 /* Read fill value and missing value... */
8916 float fillval, missval;
8917 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8918 fillval = 0;
8919 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8920 missval = 0;
8921
8922 /* Write info... */
8923 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
8924 varsel, fillval, missval);
8925
8926 /* Read data... */
8927 NC(nc_get_var_float(ncid, varid, help));
8928
8929 /* Check meteo data layout... */
8930 if (ctl->met_convention == 0) {
8931
8932 /* Copy and check data (ordering: lev, lat, lon)... */
8933 omp_set_dynamic(1);
8934#pragma omp parallel for default(shared)
8935 for (int ix = 0; ix < met->nx; ix++)
8936 for (int iy = 0; iy < met->ny; iy++)
8937 for (int ip = 0; ip < met->np; ip++) {
8938 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
8939 if ((fillval == 0 || aux != fillval)
8940 && (missval == 0 || aux != missval)
8941 && fabsf(aux) < 1e14f)
8942 dest[ix][iy][ip] = scl * aux;
8943 else
8944 dest[ix][iy][ip] = NAN;
8945 }
8946 omp_set_dynamic(0);
8947
8948 } else {
8949
8950 /* Copy and check data (ordering: lon, lat, lev)... */
8951 omp_set_dynamic(1);
8952#pragma omp parallel for default(shared)
8953 for (int ip = 0; ip < met->np; ip++)
8954 for (int iy = 0; iy < met->ny; iy++)
8955 for (int ix = 0; ix < met->nx; ix++) {
8956 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
8957 if ((fillval == 0 || aux != fillval)
8958 && (missval == 0 || aux != missval)
8959 && fabsf(aux) < 1e14f)
8960 dest[ix][iy][ip] = scl * aux;
8961 else
8962 dest[ix][iy][ip] = NAN;
8963 }
8964 omp_set_dynamic(0);
8965 }
8966
8967 /* Free... */
8968 free(help);
8969 }
8970
8971 /* Domain decomposed data... */
8972 else {
8973
8974 /* Read fill value and missing value... */
8975 float fillval, missval;
8976 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8977 fillval = 0;
8978 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8979 missval = 0;
8980
8981 /* Write info... */
8982 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
8983 varsel, fillval, missval);
8984
8985 SELECT_TIMER("read_met_nc_3d_CP1", "INPUT");
8986
8987 /* Define hyperslab... */
8988 size_t help_subdomain_start[4];
8989 size_t help_subdomain_count[4];
8990 size_t help_halo_bnd_start[4];
8991 size_t help_halo_bnd_count[4];
8992
8993 if (ctl->met_convention == 0) {
8994 for (int i = 0; i < 4; i++) {
8995 help_subdomain_start[i] = dd->subdomain_start[i];
8996 help_subdomain_count[i] = dd->subdomain_count[i];
8997 help_halo_bnd_start[i] = dd->halo_bnd_start[i];
8998 help_halo_bnd_count[i] = dd->halo_bnd_count[i];
8999 }
9000 } else {
9001 help_subdomain_start[0] = dd->subdomain_start[0];
9002 help_subdomain_start[1] = dd->subdomain_start[3];
9003 help_subdomain_start[2] = dd->subdomain_start[2];
9004 help_subdomain_start[3] = dd->subdomain_start[1];
9005
9006 help_subdomain_count[0] = dd->subdomain_count[0];
9007 help_subdomain_count[1] = dd->subdomain_count[3];
9008 help_subdomain_count[2] = dd->subdomain_count[2];
9009 help_subdomain_count[3] = dd->subdomain_count[1];
9010
9011 help_halo_bnd_start[0] = dd->halo_bnd_start[0];
9012 help_halo_bnd_start[1] = dd->halo_bnd_start[3];
9013 help_halo_bnd_start[2] = dd->halo_bnd_start[2];
9014 help_halo_bnd_start[3] = dd->halo_bnd_start[1];
9015
9016 help_halo_bnd_count[0] = dd->halo_bnd_count[0];
9017 help_halo_bnd_count[1] = dd->halo_bnd_count[3];
9018 help_halo_bnd_count[2] = dd->halo_bnd_count[2];
9019 help_halo_bnd_count[3] = dd->halo_bnd_count[1];
9020 }
9021
9022 /* Allocate... */
9023 float *help;
9024 ALLOC(help, float,
9025 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
9026 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
9027
9028 SELECT_TIMER("read_met_nc_3d_CP2", "INPUT");
9029
9030 /* Use default NetCDF parallel I/O behavior */
9031#ifdef DD
9032 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
9033#endif
9034 NC(nc_get_vara_float
9035 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
9036
9037 /* Read halos separately at boundaries... */
9038 float *help_halo;
9039 ALLOC(help_halo, float,
9040 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
9041 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
9042
9043 SELECT_TIMER("read_met_nc_3d_CP3", "INPUT");
9044
9045 /* Halo read also uses independent access */
9046#ifdef DD
9047 nc_var_par_access(ncid, varid, NC_COLLECTIVE);
9048#endif
9049 NC(nc_get_vara_float(ncid,
9050 varid,
9051 help_halo_bnd_start, help_halo_bnd_count,
9052 help_halo));
9053
9054 SELECT_TIMER("read_met_nc_3d_CP4", "INPUT");
9055
9056 /* Check meteo data layout... */
9057 if (ctl->met_convention == 0) {
9058
9059 /* Copy and check data (ordering: lev, lat, lon)... */
9060 omp_set_dynamic(1);
9061#pragma omp parallel for default(shared)
9062 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
9063 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9064 for (int ip = 0; ip < met->np; ip++) {
9065 const float aux =
9066 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
9067 (int) dd->subdomain_count[3])];
9068 if ((fillval == 0 || aux != fillval)
9069 && (missval == 0 || aux != missval)
9070 && fabsf(aux) < 1e14f)
9071 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9072 else
9073 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9074 }
9075
9076#pragma omp parallel for default(shared)
9077 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
9078 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9079 for (int ip = 0; ip < met->np; ip++) {
9080 const float aux =
9081 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
9082 (int) dd->halo_bnd_count[3])];
9083 if ((fillval == 0 || aux != fillval)
9084 && (missval == 0 || aux != missval)
9085 && fabsf(aux) < 1e14f)
9086 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9087 else
9088 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9089 }
9090 omp_set_dynamic(0);
9091
9092 } else {
9093
9094 /* Copy and check data (ordering: lon, lat, lev)... */
9095 omp_set_dynamic(1);
9096#pragma omp parallel for default(shared)
9097 for (int ip = 0; ip < met->np; ip++)
9098 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9099 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
9100 const float aux =
9101 help[ARRAY_3D
9102 (ix, iy, (int) dd->subdomain_count[2], ip, met->np)];
9103 if ((fillval == 0 || aux != fillval)
9104 && (missval == 0 || aux != missval)
9105 && fabsf(aux) < 1e14f)
9106 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9107 else
9108 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9109 }
9110
9111#pragma omp parallel for default(shared)
9112 for (int ip = 0; ip < met->np; ip++)
9113 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9114 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
9115 const float aux =
9116 help_halo[ARRAY_3D(ix, iy, (int) dd->halo_bnd_count[2], ip,
9117 met->np)];
9118 if ((fillval == 0 || aux != fillval)
9119 && (missval == 0 || aux != missval)
9120 && fabsf(aux) < 1e14f)
9121 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9122 else
9123 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9124 }
9125 omp_set_dynamic(0);
9126 }
9127
9128 /* Free... */
9129 free(help);
9130 free(help_halo);
9131 }
9132
9133 /* Return... */
9134 return 1;
9135}
9136
9137/*****************************************************************************/
9138
9139#ifdef ECCODES
9140int read_met_grib(
9141 const char *filename,
9142 const ctl_t *ctl,
9143 met_t *met) {
9144
9145 /* Set filenames... */
9146 size_t filename_len = strlen(filename) + 1;
9147 char sf_filename[filename_len];
9148 char ml_filename[filename_len];
9149 strcpy(sf_filename, filename);
9150 strcpy(ml_filename, filename);
9151 get_met_replace(ml_filename, "XX", "ml");
9152 get_met_replace(sf_filename, "XX", "sf");
9153
9154 /* Open files... */
9155 FILE *ml_file = fopen(ml_filename, "rb");
9156 FILE *sf_file = fopen(sf_filename, "rb");
9157 if (ml_file == NULL || sf_file == NULL) {
9158 if (ml_file != NULL) {
9159 fclose(ml_file);
9160 WARN("Cannot open file: %s", sf_filename);
9161 }
9162 if (sf_file != NULL) {
9163 fclose(sf_file);
9164 WARN("Cannot open file: %s", ml_filename);
9165 }
9166 return 0;
9167 }
9168
9169 /* Get handles for model level data... */
9170 int ml_num_messages = 0, err = 0;
9171 ECC(codes_count_in_file(0, ml_file, &ml_num_messages));
9172 codes_handle **ml_handles =
9173 (codes_handle **) malloc(sizeof(codes_handle *) *
9174 (size_t) ml_num_messages);
9175 for (int i = 0; i < ml_num_messages; i++) {
9176 codes_handle *h = NULL;
9177 if ((h = codes_grib_handle_new_from_file(0, ml_file, &err)) != NULL)
9178 ml_handles[i] = h;
9179 }
9180
9181 /* Get handles for surface data... */
9182 int sf_num_messages = 0;
9183 ECC(codes_count_in_file(0, sf_file, &sf_num_messages));
9184 codes_handle **sf_handles =
9185 (codes_handle **) malloc(sizeof(codes_handle *) *
9186 (size_t) sf_num_messages);
9187 for (int i = 0; i < sf_num_messages; i++) {
9188 codes_handle *h = NULL;
9189 if ((h = codes_grib_handle_new_from_file(0, sf_file, &err)) != NULL)
9190 sf_handles[i] = h;
9191 }
9192
9193 /* Close files... */
9194 fclose(ml_file);
9195 fclose(sf_file);
9196
9197 /* Read grid data... */
9198 read_met_grib_grid(ml_handles, ml_num_messages, met);
9199
9200 /* Read surface data... */
9201 read_met_grib_surface(sf_handles, sf_num_messages, ctl, met);
9202 for (int i = 0; i < sf_num_messages; i++)
9203 codes_handle_delete(sf_handles[i]);
9204 free(sf_handles);
9205
9206 /* Compute 3D pressure field... */
9207 size_t value_count = 0;
9208 ECC(codes_get_size(ml_handles[0], "pv", &value_count));
9209 if (value_count % 2 != 0)
9210 ERRMSG("Unexpected pv array length!");
9211 size_t nlevels = value_count / 2 - 1; /* number of full model levels */
9212 double *values;
9213 ALLOC(values, double,
9214 value_count);
9215 ECC(codes_get_double_array(ml_handles[0], "pv", values, &value_count));
9216 double *a_vals = values;
9217 double *b_vals = values + nlevels;
9218 if (met->npl > (int) nlevels)
9219 ERRMSG("met->npl exceeds number of pressure levels in GRIB!");
9220 for (int nx = 0; nx < met->nx; nx++)
9221 for (int ny = 0; ny < met->ny; ny++)
9222 for (int level = 0; level <= met->npl; level++) {
9223 const float p1 = (float) (a_vals[level] * 0.01f +
9224 met->ps[nx][ny] * b_vals[level]);
9225 const float p2 = (float) (a_vals[level + 1] * 0.01f +
9226 met->ps[nx][ny] * b_vals[level + 1]);
9227 met->pl[nx][ny][level] = 0.5f * (p1 + p2);
9228 }
9229 free(values);
9230
9231 /* Read model level data... */
9232 read_met_grib_levels(ml_handles, ml_num_messages, ctl, met);
9233 for (int i = 0; i < ml_num_messages; i++)
9234 codes_handle_delete(ml_handles[i]);
9235 free(ml_handles);
9236
9237 /* Return success... */
9238 return 1;
9239}
9240#endif
9241
9242/*****************************************************************************/
9243
9244#ifdef ECCODES
9246 codes_handle **handles,
9247 int count_handles,
9248 met_t *met) {
9249
9250 /* Set timer... */
9251 SELECT_TIMER("READ_MET_GRIB_GRID", "INPUT");
9252 LOG(2, "Read meteo grid information...");
9253
9254 /* Read date and time... */
9255 char datestr[LEN], timestr[LEN];
9256 size_t s_date = sizeof(datestr);
9257 ECC(codes_get_string(handles[0], "dataDate", datestr, &s_date));
9258 size_t s_time = sizeof(timestr);
9259 ECC(codes_get_string(handles[0], "dataTime", timestr, &s_time));
9260 int year, month, day, hour;
9261 if (sscanf(datestr, "%4d%2d%2d", &year, &month, &day) != 3)
9262 ERRMSG("Failed to parse dataDate: %s", datestr);
9263 if (sscanf(timestr, "%2d", &hour) != 1)
9264 ERRMSG("Failed to parse dataTime: %s", timestr);
9265 time2jsec(year, month, day, hour, 0, 0, 0, &(met->time));
9266 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)", met->time, year, month,
9267 day, hour, 0);
9268
9269 /* Read grid information... */
9270 long count_lat = 0, count_lon = 0;
9271 ECC(codes_get_long(handles[0], "Nj", &count_lat));
9272 ECC(codes_get_long(handles[0], "Ni", &count_lon));
9273 met->ny = (int) count_lat;
9274 met->nx = (int) count_lon;
9275
9276 /* Check grid dimensions... */
9277 LOG(2, "Number of longitudes: %d", met->nx);
9278 if (met->nx < 2 || met->nx > EX)
9279 ERRMSG("Number of longitudes out of range!");
9280 LOG(2, "Number of latitudes: %d", met->ny);
9281 if (met->ny < 2 || met->ny > EY)
9282 ERRMSG("Number of latitudes out of range!");
9283
9284 double first_lon, last_lon, first_lat, last_lat, inc_lon, inc_lat;
9285 ECC(codes_get_double
9286 (handles[0], "longitudeOfFirstGridPointInDegrees", &first_lon));
9287 ECC(codes_get_double
9288 (handles[0], "latitudeOfFirstGridPointInDegrees", &first_lat));
9289 ECC(codes_get_double
9290 (handles[0], "longitudeOfLastGridPointInDegrees", &last_lon));
9291 ECC(codes_get_double
9292 (handles[0], "latitudeOfLastGridPointInDegrees", &last_lat));
9293 ECC(codes_get_double(handles[0], "iDirectionIncrementInDegrees", &inc_lon));
9294 ECC(codes_get_double(handles[0], "jDirectionIncrementInDegrees", &inc_lat));
9295
9296 long jscanpos, iscanneg;
9297 ECC(codes_get_long(handles[0], "iScansNegatively", &iscanneg));
9298 ECC(codes_get_long(handles[0], "jScansPositively", &jscanpos));
9299
9300 /* Compute longitude-latitude grid... */
9301 int counter = 0;
9302 if (iscanneg == 0)
9303 for (double i = first_lon; i <= last_lon + 1e-6; i += inc_lon) {
9304 met->lon[counter] = i;
9305 counter++;
9306 } else
9307 for (double i = first_lon; i > last_lon - 1e-6; i -= inc_lon) {
9308 met->lon[counter] = i;
9309 counter++;
9310 }
9311
9312 counter = 0;
9313 if (jscanpos == 0)
9314 for (double i = first_lat; i > last_lat - 1e-6; i -= inc_lat) {
9315 met->lat[counter] = i;
9316 counter++;
9317 } else
9318 for (double i = first_lat; i <= last_lat + 1e-6; i += inc_lat) {
9319 met->lat[counter] = i;
9320 counter++;
9321 }
9322
9323 /* Write info... */
9324 LOG(2, "Longitudes: %g, %g ... %g deg",
9325 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9326 LOG(2, "Latitudes: %g, %g ... %g deg",
9327 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9328
9329 /* Read vertical levels... */
9330 int max_level = 0;
9331 for (int i = 0; i < count_handles; i++) {
9332 long level;
9333 ECC(codes_get_long(handles[i], "level", &level));
9334 if (level > max_level)
9335 max_level = (int) level;
9336 }
9337 met->npl = max_level;
9338
9339 /* Check number of levels... */
9340 LOG(2, "Number of levels: %d", met->npl);
9341 if (met->npl < 2 || met->npl > EP)
9342 ERRMSG("Number of levels out of range!");
9343}
9344#endif
9345
9346/*****************************************************************************/
9347
9348#ifdef ECCODES
9350 codes_handle **handles,
9351 const int num_messages,
9352 const ctl_t *ctl,
9353 met_t *met) {
9354
9355 /* Set timer... */
9356 SELECT_TIMER("READ_MET_GRIB_LEVELS", "INPUT");
9357 LOG(2, "Read level data...");
9358
9359 /* Init... */
9360 int t_flag = 0, u_flag = 0, v_flag = 0, w_flag = 0, o3_flag = 0, h2o_flag =
9361 0, lwc_flag = 0, rwc_flag = 0, iwc_flag = 0, swc_flag = 0, cc_flag = 0;
9362
9363 /* Iterate over all messages... */
9364 for (int i = 0; i < num_messages; i++) {
9365
9366 size_t max_size = LEN;
9367 char short_name[max_size];
9368 size_t value_count;
9369 double *values;
9370
9371 /* Get the current level */
9372 long current_level;
9373 ECC(codes_get_long(handles[i], "level", &current_level));
9374 current_level -= 1;
9375
9376 /* Retrieve data from current message */
9377 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
9378 ECC(codes_get_size(handles[i], "values", &value_count));
9379 ALLOC(values, double,
9380 value_count);
9381 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
9382
9383 /* Read temperature... */
9384 ECC_READ_3D("t", current_level, met->t, 1.0, t_flag);
9385
9386 /* Read horizontal wind and vertical velocity... */
9387 ECC_READ_3D("u", current_level, met->u, 1.0, u_flag);
9388 ECC_READ_3D("v", current_level, met->v, 1.0, v_flag);
9389 ECC_READ_3D("w", current_level, met->w, 0.01f, w_flag);
9390
9391 /* Read water vapor and ozone... */
9392 ECC_READ_3D("q", current_level, met->h2o, (float) (MA / MH2O), h2o_flag);
9393 ECC_READ_3D("o3", current_level, met->o3, (float) (MA / MO3), o3_flag);
9394
9395 /* Read cloud data... */
9396 ECC_READ_3D("clwc", current_level, met->lwc, 1.0, lwc_flag);
9397 ECC_READ_3D("crwc", current_level, met->rwc, 1.0, rwc_flag);
9398 ECC_READ_3D("ciwc", current_level, met->iwc, 1.0, iwc_flag);
9399 ECC_READ_3D("cswc", current_level, met->swc, 1.0, swc_flag);
9400 ECC_READ_3D("cc", current_level, met->cc, 1.0, cc_flag);
9401
9402 /*Free allocated array */
9403 free(values);
9404 }
9405
9406 /* Check whether data were found... */
9407 if (t_flag != met->npl)
9408 ERRMSG("Cannot read temperature!");
9409 if (u_flag != met->npl)
9410 ERRMSG("Cannot read zonal wind!");
9411 if (v_flag != met->npl)
9412 ERRMSG("Cannot read meridional wind!");
9413 if (w_flag != met->npl)
9414 WARN("Cannot read vertical velocity!");
9415 if (h2o_flag != met->npl)
9416 WARN("Cannot read specific humidity!");
9417 if (o3_flag != met->npl)
9418 WARN("Cannot read ozone data!");
9419 if (lwc_flag != met->npl)
9420 WARN("Cannot read cloud liquid water content!");
9421 if (rwc_flag != met->npl)
9422 WARN("Cannot read cloud rain water content!");
9423 if (iwc_flag != met->npl)
9424 WARN("Cannot read cloud ice water content!");
9425 if (swc_flag != met->npl)
9426 WARN("Cannot read cloud snow water content!");
9427 if (cc_flag != met->npl)
9428 WARN("Cannot read cloud cover!");
9429
9430 /* Check ordering of pressure levels... */
9431 for (int ix = 0; ix < met->nx; ix++)
9432 for (int iy = 0; iy < met->ny; iy++)
9433 for (int ip = 1; ip < met->np; ip++)
9434 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
9435 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
9436 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
9437 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip])) {
9438 LOG(1, "%f %f %f %f", met->pl[ix][iy][0], met->pl[ix][iy][1],
9439 met->pl[ix][iy][ip - 1], met->pl[ix][iy][ip]);
9440 ERRMSG("Pressure profiles are not monotonic!");
9441 }
9442
9443 /* Interpolate from model levels to pressure levels... */
9444 if (ctl->met_np > 0) {
9445 met->np = ctl->met_np;
9446
9447 /* Interpolate variables... */
9448 read_met_ml2pl(ctl, met, met->t, "T");
9449 read_met_ml2pl(ctl, met, met->u, "U");
9450 read_met_ml2pl(ctl, met, met->v, "V");
9451 read_met_ml2pl(ctl, met, met->w, "W");
9452 read_met_ml2pl(ctl, met, met->h2o, "H2O");
9453 read_met_ml2pl(ctl, met, met->o3, "O3");
9454 read_met_ml2pl(ctl, met, met->lwc, "LWC");
9455 read_met_ml2pl(ctl, met, met->rwc, "RWC");
9456 read_met_ml2pl(ctl, met, met->iwc, "IWC");
9457 read_met_ml2pl(ctl, met, met->swc, "SWC");
9458 read_met_ml2pl(ctl, met, met->cc, "CC");
9459
9460 /* Set new pressure levels... */
9461 for (int ip = 0; ip < met->np; ip++)
9462 met->p[ip] = ctl->met_p[ip];
9463 }
9464
9465 /* Check ordering of pressure levels... */
9466 for (int ip = 1; ip < met->np; ip++)
9467 if (met->p[ip - 1] < met->p[ip])
9468 ERRMSG("Pressure levels must be descending!");
9469}
9470#endif
9471
9472/*****************************************************************************/
9473
9474#ifdef ECCODES
9476 codes_handle **handles,
9477 const int num_messages,
9478 const ctl_t *ctl,
9479 met_t *met) {
9480
9481 /* Set timer... */
9482 SELECT_TIMER("READ_MET_GRIB_SURFACE", "INPUT");
9483 LOG(2, "Read surface data...");
9484
9485 /* Init... */
9486 int sp_flag = 0, z_flag = 0, t_flag = 0, u_flag = 0, v_flag = 0, lsm_flag =
9487 0, sst_flag = 0, cape_flag = 0, cin_flag = 0, pbl_flag = 0;
9488
9489 /* Iterate over all messages... */
9490 for (int i = 0; i < num_messages; i++) {
9491
9492 size_t max_size = LEN, value_count;
9493
9494 char short_name[max_size];
9495
9496 /* Store values with shortname... */
9497 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
9498 ECC(codes_get_size(handles[i], "values", &value_count));
9499 double *values = (double *) malloc(value_count * sizeof(double));
9500 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
9501
9502 /*Read surface pressure... */
9503 ECC_READ_2D("sp", met->ps, 0.01f, sp_flag);
9504
9505 /*Read geopotential height at the surface... */
9506 ECC_READ_2D("z", met->zs, (float) (1. / (1000. * G0)), z_flag);
9507
9508 /* Read temperature at the surface... */
9509 ECC_READ_2D("2t", met->ts, 1.0f, t_flag);
9510
9511 /* Read zonal wind at the surface... */
9512 ECC_READ_2D("10u", met->us, 1.0f, u_flag);
9513
9514 /* Read meridional wind at the surface... */
9515 ECC_READ_2D("10v", met->vs, 1.0f, v_flag);
9516
9517 /* Read land-sea mask... */
9518 ECC_READ_2D("lsm", met->lsm, 1.0f, lsm_flag);
9519
9520 /* Read sea surface temperature... */
9521 ECC_READ_2D("sst", met->sst, 1.0f, sst_flag);
9522 if (ctl->met_cape == 0) {
9523
9524 /* Read CAPE... */
9525 ECC_READ_2D("cape", met->cape, 1.0f, cape_flag);
9526
9527 /* Read CIN... */
9528 ECC_READ_2D("cin", met->cin, 1.0f, cin_flag);
9529 }
9530
9531 /* Read PBL... */
9532 if (ctl->met_pbl == 0)
9533 ECC_READ_2D("blh", met->pbl, 0.0001f, pbl_flag);
9534 }
9535
9536 /* Check whether data have been read... */
9537 if (sp_flag == 0)
9538 WARN("Cannot read surface pressure data!");
9539 if (z_flag == 0)
9540 WARN("Cannot read surface geopotential height!");
9541 if (t_flag == 0)
9542 WARN("Cannot read surface temperature!");
9543 if (u_flag == 0)
9544 WARN("Cannot read surface zonal wind!");
9545 if (v_flag == 0)
9546 WARN("Cannot read surface meridional wind!");
9547 if (lsm_flag == 0)
9548 WARN("Cannot read land-sea mask!");
9549 if (sst_flag == 0)
9550 WARN("Cannot read sea surface temperature!");
9551 if (ctl->met_cape == 0) {
9552 if (cape_flag == 0)
9553 WARN("Cannot read CAPE!");
9554 if (cin_flag == 0)
9555 WARN("Cannot read convective inhibition!");
9556 }
9557 if (ctl->met_pbl == 0 && pbl_flag == 0)
9558 WARN("Cannot read planetary boundary layer!");
9559}
9560#endif
9561
9562/*****************************************************************************/
9563
9565 const ctl_t *ctl,
9566 const met_t *met,
9567 float var[EX][EY][EP],
9568 const char *varname) {
9569
9570 double aux[EP], p[EP];
9571
9572 /* Set timer... */
9573 SELECT_TIMER("READ_MET_ML2PL", "METPROC");
9574 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
9575
9576 /* Loop over columns... */
9577#pragma omp parallel for default(shared) private(aux,p) collapse(2)
9578 for (int ix = 0; ix < met->nx; ix++)
9579 for (int iy = 0; iy < met->ny; iy++) {
9580
9581 /* Copy pressure profile... */
9582 for (int ip = 0; ip < met->np; ip++)
9583 p[ip] = met->pl[ix][iy][ip];
9584
9585 /* Interpolate... */
9586 for (int ip = 0; ip < ctl->met_np; ip++) {
9587 double pt = ctl->met_p[ip];
9588 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
9589 pt = p[0];
9590 else if ((pt > p[met->np - 1] && p[1] > p[0])
9591 || (pt < p[met->np - 1] && p[1] < p[0]))
9592 pt = p[met->np - 1];
9593 const int ip2 = locate_irr(p, met->np, pt);
9594 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
9595 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
9596 }
9597
9598 /* Copy data... */
9599 for (int ip = 0; ip < ctl->met_np; ip++)
9600 var[ix][iy][ip] = (float) aux[ip];
9601 }
9602}
9603
9604/*****************************************************************************/
9605
9607 const ctl_t *ctl,
9608 met_t *met) {
9609
9610 /* Check parameters... */
9611 if (ctl->advect_vert_coord != 1)
9612 return;
9613
9614 /* Set timer... */
9615 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC");
9616 LOG(2, "Make zeta profiles monotone...");
9617
9618 /* Create monotone zeta profiles... */
9619#pragma omp parallel for default(shared) collapse(2)
9620 for (int i = 0; i < met->nx; i++)
9621 for (int j = 0; j < met->ny; j++) {
9622 int k = 1;
9623
9624 while (k < met->npl) { /* Check if there is an inversion at level k... */
9625 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
9626 /* Find the upper level k+l over the inversion... */
9627 int l = 0;
9628 do {
9629 l++;
9630 }
9631 while ((met->zetal[i][j][k - 1] >=
9632 met->zetal[i][j][k + l]) & (k + l < met->npl));
9633
9634 /* Interpolate linear between the top and bottom
9635 of the inversion... */
9636 float s =
9637 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
9638 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9639
9640 for (int m = k; m < k + l; m++) {
9641 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9642 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
9643 }
9644
9645 /* Search for more inversions above the last inversion ... */
9646 k = k + l;
9647 } else {
9648 k++;
9649 }
9650 }
9651 }
9652
9653 /* Create monotone pressure profiles... */
9654#pragma omp parallel for default(shared) collapse(2)
9655 for (int i = 0; i < met->nx; i++)
9656 for (int j = 0; j < met->ny; j++) {
9657 int k = 1;
9658
9659 while (k < met->npl) { /* Check if there is an inversion at level k... */
9660 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
9661
9662 /* Find the upper level k+l over the inversion... */
9663 int l = 0;
9664 do {
9665 l++;
9666 }
9667 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
9668 met->npl));
9669
9670 /* Interpolate linear between the top and bottom
9671 of the inversion... */
9672 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
9673 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9674
9675 for (int m = k; m < k + l; m++) {
9676 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9677 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
9678 }
9679
9680 /* Search for more inversions above the last inversion ... */
9681 k += l;
9682 } else {
9683 k++;
9684 }
9685 }
9686 }
9687}
9688
9689/*****************************************************************************/
9690
9692 const char *filename,
9693 const ctl_t *ctl,
9694 met_t *met,
9695 dd_t *dd) {
9696
9697 int ncid;
9698
9699 /* Open file... */
9700#ifdef DD
9701 if (ctl->dd) {
9702 NC(nc_open_par
9703 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
9704 &ncid))
9705 }
9706#else
9707 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
9708 WARN("Cannot open file!");
9709 return 0;
9710 }
9711#endif
9712
9713 /* Read coordinates of meteo data... */
9714 read_met_nc_grid(filename, ncid, ctl, met, dd);
9715
9716 /* Read surface data... */
9717 read_met_nc_surface(ncid, ctl, met, dd);
9718
9719 /* Read meteo data on vertical levels... */
9720 read_met_nc_levels(ncid, ctl, met, dd);
9721
9722 /* Close file... */
9723 NC(nc_close(ncid));
9724
9725 /* Return success... */
9726 return 1;
9727}
9728
9729/*****************************************************************************/
9730
9732 dd_t *dd,
9733 const ctl_t *ctl,
9734 met_t *met,
9735 const int ncid) {
9736
9737 int varid;
9738
9739 /* Get the MPI information... */
9740 int rank = 0, size = 1;
9741#ifdef MPI
9742 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
9743 MPI_Comm_size(MPI_COMM_WORLD, &size);
9744#endif
9745
9746 /* Get grid dimensions... */
9747 NC_INQ_DIM("lon", &dd->nx_glob, 0, 0, 0);
9748 NC_INQ_DIM("lat", &dd->ny_glob, 0, 0, 0);
9749
9750 LOG(2, "Number of longitudes: %d", dd->nx_glob);
9751 LOG(2, "Number of latitudes: %d", dd->ny_glob);
9752
9753 /* Check grid... */
9754 if (dd->nx_glob > DD_EX_GLOB || dd->ny_glob > DD_EY_GLOB)
9755 ERRMSG("Global grid is too large!");
9756
9757 if (ctl->dd_subdomains_zonal > dd->nx_glob)
9758 ERRMSG("Too many zonal subdomains for global x grid!");
9759
9760 if (ctl->dd_subdomains_meridional > dd->ny_glob)
9761 ERRMSG("Too many meridional subdomains for global y grid!");
9762
9763 /* Read global longitudes and latitudes... */
9764 NC_GET_DOUBLE("lon", dd->lon_glob, 1);
9765 NC_GET_DOUBLE("lat", dd->lat_glob, 1);
9766
9767 LOG(2, "Longitudes: %g, %g ... %g deg",
9768 dd->lon_glob[0], dd->lon_glob[1], dd->lon_glob[dd->nx_glob - 1]);
9769 LOG(2, "Latitudes: %g, %g ... %g deg",
9770 dd->lat_glob[0], dd->lat_glob[1], dd->lat_glob[dd->ny_glob - 1]);
9771
9772 /* Rank coordinates in DD layout... */
9773 const int zonal_rank = rank / ctl->dd_subdomains_meridional;
9774 const int merid_rank = rank % ctl->dd_subdomains_meridional;
9775
9776 /* Check for edge cases... */
9777 const int left = (zonal_rank == 0);
9778 const int right = (zonal_rank == ctl->dd_subdomains_zonal - 1);
9779 const int top = (merid_rank == 0);
9780 const int bottom = (merid_rank == ctl->dd_subdomains_meridional - 1);
9781
9782 /* Core owned block (without halos)... */
9783 const int nx_block = dd->nx_glob / ctl->dd_subdomains_zonal;
9784 const int ny_block = dd->ny_glob / ctl->dd_subdomains_meridional;
9785
9786 const int ix0 = zonal_rank * nx_block;
9787 const int iy0 = merid_rank * ny_block;
9788
9789 int nx_core = nx_block;
9790 int ny_core = ny_block;
9791
9792 if (right)
9793 nx_core += dd->nx_glob - ctl->dd_subdomains_zonal * nx_block;
9794 if (bottom)
9795 ny_core += dd->ny_glob - ctl->dd_subdomains_meridional * ny_block;
9796
9797 /* Store core met size first... */
9798 met->nx = nx_core;
9799 met->ny = ny_core;
9800
9801 /* Set hyperslab for core subdomain... */
9802 dd->subdomain_start[0] = 0;
9803 dd->subdomain_start[1] = 0;
9804 dd->subdomain_start[2] = (size_t) iy0;
9805 dd->subdomain_start[3] = (size_t) ix0;
9806
9807 dd->subdomain_count[0] = 1;
9808 dd->subdomain_count[1] = (size_t) met->np;
9809 dd->subdomain_count[2] = (size_t) ny_core;
9810 dd->subdomain_count[3] = (size_t) nx_core;
9811
9812 /* Add inner halos to read window... */
9813 if (!left && !right) {
9814 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
9815 dd->subdomain_count[3] += (size_t) (2 * ctl->dd_halos_size);
9816 } else if (left ^ right) {
9817 dd->subdomain_count[3] += (size_t) ctl->dd_halos_size;
9818 if (!left)
9819 dd->subdomain_start[3] -= (size_t) ctl->dd_halos_size;
9820 }
9821
9822 if (!top && !bottom) {
9823 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
9824 dd->subdomain_count[2] += (size_t) (2 * ctl->dd_halos_size);
9825 } else if (top ^ bottom) {
9826 dd->subdomain_count[2] += (size_t) ctl->dd_halos_size;
9827 if (!top)
9828 dd->subdomain_start[2] -= (size_t) ctl->dd_halos_size;
9829 }
9830
9831 /* Set boundary halo hyperslabs... */
9832 double lon_shift = 0.0;
9833
9834 if (left ^ right) {
9835 dd->halo_bnd_start[0] = 0;
9836 dd->halo_bnd_start[1] = 0;
9837 dd->halo_bnd_start[2] = dd->subdomain_start[2];
9838 dd->halo_bnd_start[3] =
9839 (size_t) (left ? (dd->nx_glob - ctl->dd_halos_size) : 0);
9840
9841 dd->halo_bnd_count[0] = 1;
9842 dd->halo_bnd_count[1] = (size_t) met->np;
9843 dd->halo_bnd_count[2] =
9844 (size_t) met->ny +
9845 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
9846 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
9847
9848 dd->halo_offset_start = left ? (int) dd->halo_bnd_count[3] : 0;
9849 dd->halo_offset_end = left ? 0 : (int) dd->subdomain_count[3];
9850 lon_shift = left ? -360.0 : 360.0;
9851 } else {
9852 dd->halo_bnd_start[0] = 0;
9853 dd->halo_bnd_start[1] = 0;
9854 dd->halo_bnd_start[2] = 0;
9855 dd->halo_bnd_start[3] = 0;
9856
9857 dd->halo_bnd_count[0] = 0;
9858 dd->halo_bnd_count[1] = 0;
9859 dd->halo_bnd_count[2] = 0;
9860 dd->halo_bnd_count[3] = 0;
9861
9862 dd->halo_offset_start = 0;
9863 dd->halo_offset_end = 0;
9864 }
9865
9866 /* Focus on subdomain latitudes... */
9867 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9868 met->lat[iy] = dd->lat_glob[(int) dd->subdomain_start[2] + iy];
9869
9870 /* Focus on subdomain longitudes... */
9871 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
9872 met->lon[ix + dd->halo_offset_start] =
9873 dd->lon_glob[(int) dd->subdomain_start[3] + ix];
9874
9875 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
9876 met->lon[ix + dd->halo_offset_end] =
9877 dd->lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
9878
9879 /* Reset halo-extended grid dimensions... */
9880 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
9881 met->ny = (int) dd->subdomain_count[2];
9882
9883 LOG(2, "Define subdomain properties.");
9884 LOG(2, "MPI information: Rank %d, Size %d", rank, size);
9885 LOG(2, "Edge position: l=%d,r=%d,t=%d,b=%d", left, right, top, bottom);
9886 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d",
9887 met->nx, met->ny, met->np);
9888 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
9889 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
9890 (int) dd->halo_bnd_count[1]);
9891 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
9892 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
9893 (int) dd->subdomain_count[1]);
9894 LOG(2, "Subdomain start: nx %ld ny %ld np %ld",
9895 dd->subdomain_start[3], dd->subdomain_start[2], dd->subdomain_start[1]);
9896 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld",
9897 dd->halo_bnd_start[3], dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
9898 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
9899 LOG(2, "%d Subdomain longitudes: %g, %g ... %g deg",
9900 rank, met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9901 LOG(2, "%d Subdomain latitudes: %g, %g ... %g deg",
9902 rank, met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9903}
9904
9905/*****************************************************************************/
9906
9908 const ctl_t *ctl,
9909 met_t *met) {
9910
9911 /* Set timer... */
9912 SELECT_TIMER("READ_MET_PBL", "METPROC");
9913 LOG(2, "Calculate planetary boundary layer...");
9914
9915 /* Convert PBL height from meteo file to pressure... */
9916 if (ctl->met_pbl == 1) {
9917
9918 /* Loop over grid points... */
9919#pragma omp parallel for default(shared) collapse(2)
9920 for (int ix = 0; ix < met->nx; ix++)
9921 for (int iy = 0; iy < met->ny; iy++) {
9922
9923 /* Get pressure at top of PBL... */
9924 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
9925 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
9926 met->pbl[ix][iy] =
9927 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
9928 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
9929 }
9930 }
9931
9932 /* Determine PBL based on Richardson number... */
9933 else if (ctl->met_pbl == 2) {
9934
9935 /* Parameters used to estimate the height of the PBL
9936 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
9937 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
9938
9939 /* Loop over grid points... */
9940#pragma omp parallel for default(shared) collapse(2)
9941 for (int ix = 0; ix < met->nx; ix++)
9942 for (int iy = 0; iy < met->ny; iy++) {
9943
9944 /* Set bottom level of PBL... */
9945 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
9946
9947 /* Find lowest level near the bottom... */
9948 int ip;
9949 for (ip = 1; ip < met->np; ip++)
9950 if (met->p[ip] < pbl_bot)
9951 break;
9952
9953 /* Get near surface data... */
9954 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
9955 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
9956 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
9957
9958 /* Init... */
9959 double rib_old = 0;
9960
9961 /* Loop over levels... */
9962 for (; ip < met->np; ip++) {
9963
9964 /* Get squared horizontal wind speed... */
9965 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
9966 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
9967 vh2 = MAX(vh2, SQR(umin));
9968
9969 /* Calculate bulk Richardson number... */
9970 const double rib =
9971 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
9972 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
9973 met->h2o[ix][iy][ip]) - tvs) / vh2;
9974
9975 /* Check for critical value... */
9976 if (rib >= rib_crit) {
9977 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
9978 rib, met->p[ip], rib_crit));
9979 if (met->pbl[ix][iy] > pbl_bot)
9980 met->pbl[ix][iy] = (float) pbl_bot;
9981 break;
9982 }
9983
9984 /* Save Richardson number... */
9985 rib_old = rib;
9986 }
9987 }
9988 }
9989
9990 /* Determine PBL based on potential temperature... */
9991 if (ctl->met_pbl == 3) {
9992
9993 /* Parameters used to estimate the height of the PBL
9994 (following HYSPLIT model)... */
9995 const double dtheta = 2.0, zmin = 0.1;
9996
9997 /* Loop over grid points... */
9998#pragma omp parallel for default(shared) collapse(2)
9999 for (int ix = 0; ix < met->nx; ix++)
10000 for (int iy = 0; iy < met->ny; iy++) {
10001
10002 /* Potential temperature at the surface... */
10003 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
10004
10005 /* Find topmost level where theta exceeds surface value by 2 K... */
10006 int ip;
10007 for (ip = met->np - 2; ip > 0; ip--)
10008 if (met->p[ip] >= 300.)
10009 if (met->p[ip] > met->ps[ix][iy]
10010 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
10011 break;
10012
10013 /* Interpolate... */
10014 met->pbl[ix][iy]
10015 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
10016 met->p[ip + 1],
10017 THETA(met->p[ip], met->t[ix][iy][ip]),
10018 met->p[ip], theta0 + dtheta));
10019
10020 /* Check minimum value... */
10021 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
10022 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
10023 met->pbl[ix][iy] = (float) pbl_min;
10024 }
10025 }
10026
10027 /* Loop over grid points... */
10028#pragma omp parallel for default(shared) collapse(2)
10029 for (int ix = 0; ix < met->nx; ix++)
10030 for (int iy = 0; iy < met->ny; iy++) {
10031
10032 /* Check minimum value... */
10033 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
10034 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
10035
10036 /* Check maximum value... */
10037 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
10038 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
10039 }
10040}
10041
10042/*****************************************************************************/
10043
10045 met_t *met) {
10046
10047 /* Set timer... */
10048 SELECT_TIMER("READ_MET_PERIODIC", "METPROC");
10049 LOG(2, "Apply periodic boundary conditions...");
10050
10051 /* Check longitudes... */
10052 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
10053 + met->lon[1] - met->lon[0] - 360) < 0.01))
10054 return;
10055
10056 /* Increase longitude counter... */
10057 if ((++met->nx) >= EX)
10058 ERRMSG("Cannot create periodic boundary conditions!");
10059
10060 /* Set longitude... */
10061 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
10062
10063 /* Loop over latitudes and pressure levels... */
10064#pragma omp parallel for default(shared)
10065 for (int iy = 0; iy < met->ny; iy++) {
10066 met->ps[met->nx - 1][iy] = met->ps[0][iy];
10067 met->zs[met->nx - 1][iy] = met->zs[0][iy];
10068 met->ts[met->nx - 1][iy] = met->ts[0][iy];
10069 met->us[met->nx - 1][iy] = met->us[0][iy];
10070 met->vs[met->nx - 1][iy] = met->vs[0][iy];
10071 met->ess[met->nx - 1][iy] = met->ess[0][iy];
10072 met->nss[met->nx - 1][iy] = met->nss[0][iy];
10073 met->shf[met->nx - 1][iy] = met->shf[0][iy];
10074 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
10075 met->sst[met->nx - 1][iy] = met->sst[0][iy];
10076 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
10077 met->cape[met->nx - 1][iy] = met->cape[0][iy];
10078 met->cin[met->nx - 1][iy] = met->cin[0][iy];
10079 for (int ip = 0; ip < met->np; ip++) {
10080 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
10081 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
10082 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
10083 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
10084 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
10085 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
10086 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
10087 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
10088 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
10089 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
10090 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
10091 }
10092 for (int ip = 0; ip < met->npl; ip++) {
10093 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
10094 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
10095 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
10096 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
10097 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
10098 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
10099 }
10100 }
10101}
10102
10103/*****************************************************************************/
10104
10106 met_t *met) {
10107
10108 /* Set timer... */
10109 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC");
10110 LOG(2, "Apply fix for polar winds...");
10111
10112 /* Check latitudes... */
10113 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
10114 return;
10115
10116 /* Loop over hemispheres... */
10117 for (int ihem = 0; ihem < 2; ihem++) {
10118
10119 /* Set latitude indices... */
10120 int i89 = 1, i90 = 0, sign = 1;
10121 if (ihem == 1) {
10122 i89 = met->ny - 2;
10123 i90 = met->ny - 1;
10124 }
10125 if (met->lat[i90] < 0)
10126 sign = -1;
10127
10128 /* Look-up table of cosinus and sinus... */
10129 double clon[EX], slon[EX];
10130#pragma omp parallel for default(shared)
10131 for (int ix = 0; ix < met->nx; ix++) {
10132 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
10133 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
10134 }
10135
10136 /* Loop over levels... */
10137#pragma omp parallel for default(shared)
10138 for (int ip = 0; ip < met->np; ip++) {
10139
10140 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
10141 double vel89x = 0, vel89y = 0;
10142 for (int ix = 0; ix < met->nx; ix++) {
10143 vel89x +=
10144 (met->u[ix][i89][ip] * clon[ix] -
10145 met->v[ix][i89][ip] * slon[ix]) / met->nx;
10146 vel89y +=
10147 (met->u[ix][i89][ip] * slon[ix] +
10148 met->v[ix][i89][ip] * clon[ix]) / met->nx;
10149 }
10150
10151 /* Replace 90 degree winds by 89 degree mean... */
10152 for (int ix = 0; ix < met->nx; ix++) {
10153 met->u[ix][i90][ip]
10154 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
10155 met->v[ix][i90][ip]
10156 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
10157 }
10158 }
10159 }
10160}
10161
10162/*****************************************************************************/
10163
10165 met_t *met) {
10166
10167 double pows[EP];
10168
10169 /* Set timer... */
10170 SELECT_TIMER("READ_MET_PV", "METPROC");
10171 LOG(2, "Calculate potential vorticity...");
10172
10173 /* Set powers... */
10174#pragma omp parallel for default(shared)
10175 for (int ip = 0; ip < met->np; ip++)
10176 pows[ip] = pow(1000. / met->p[ip], 0.286);
10177
10178 /* Loop over grid points... */
10179#pragma omp parallel for default(shared)
10180 for (int ix = 0; ix < met->nx; ix++) {
10181
10182 /* Set indices... */
10183 const int ix0 = MAX(ix - 1, 0);
10184 const int ix1 = MIN(ix + 1, met->nx - 1);
10185
10186 /* Loop over grid points... */
10187 for (int iy = 0; iy < met->ny; iy++) {
10188
10189 /* Set indices... */
10190 const int iy0 = MAX(iy - 1, 0);
10191 const int iy1 = MIN(iy + 1, met->ny - 1);
10192
10193 /* Set auxiliary variables... */
10194 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
10195 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
10196 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
10197 const double c0 = cos(DEG2RAD(met->lat[iy0]));
10198 const double c1 = cos(DEG2RAD(met->lat[iy1]));
10199 const double cr = cos(DEG2RAD(latr));
10200 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
10201
10202 /* Loop over grid points... */
10203 for (int ip = 0; ip < met->np; ip++) {
10204
10205 /* Get gradients in longitude... */
10206 const double dtdx
10207 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
10208 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
10209
10210 /* Get gradients in latitude... */
10211 const double dtdy
10212 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
10213 const double dudy
10214 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
10215
10216 /* Set indices... */
10217 const int ip0 = MAX(ip - 1, 0);
10218 const int ip1 = MIN(ip + 1, met->np - 1);
10219
10220 /* Get gradients in pressure... */
10221 double dtdp, dudp, dvdp;
10222 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
10223 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
10224 if (ip != ip0 && ip != ip1) {
10225 double denom = dp0 * dp1 * (dp0 + dp1);
10226 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
10227 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
10228 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
10229 / denom;
10230 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
10231 - dp1 * dp1 * met->u[ix][iy][ip0]
10232 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
10233 / denom;
10234 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
10235 - dp1 * dp1 * met->v[ix][iy][ip0]
10236 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
10237 / denom;
10238 } else {
10239 const double denom = dp0 + dp1;
10240 dtdp =
10241 (met->t[ix][iy][ip1] * pows[ip1] -
10242 met->t[ix][iy][ip0] * pows[ip0]) / denom;
10243 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
10244 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
10245 }
10246
10247 /* Calculate PV... */
10248 met->pv[ix][iy][ip] = (float)
10249 (1e6 * G0 *
10250 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
10251 }
10252 }
10253 }
10254
10255 /* Fix for polar regions... */
10256#pragma omp parallel for default(shared)
10257 for (int ix = 0; ix < met->nx; ix++)
10258 for (int ip = 0; ip < met->np; ip++) {
10259 met->pv[ix][0][ip]
10260 = met->pv[ix][1][ip]
10261 = met->pv[ix][2][ip];
10262 met->pv[ix][met->ny - 1][ip]
10263 = met->pv[ix][met->ny - 2][ip]
10264 = met->pv[ix][met->ny - 3][ip];
10265 }
10266}
10267
10268/*****************************************************************************/
10269
10271 met_t *met) {
10272
10273 /* Set timer... */
10274 SELECT_TIMER("READ_MET_OZONE", "METPROC");
10275 LOG(2, "Calculate total column ozone...");
10276
10277 /* Loop over columns... */
10278#pragma omp parallel for default(shared) collapse(2)
10279 for (int ix = 0; ix < met->nx; ix++)
10280 for (int iy = 0; iy < met->ny; iy++) {
10281
10282 /* Integrate... */
10283 double cd = 0;
10284 for (int ip = 1; ip < met->np; ip++)
10285 if (met->p[ip - 1] <= met->ps[ix][iy]) {
10286 const double vmr =
10287 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
10288 const double dp = met->p[ip - 1] - met->p[ip];
10289 cd += vmr * MO3 / MA * dp * 1e2 / G0;
10290 }
10291
10292 /* Convert to Dobson units... */
10293 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
10294 }
10295}
10296
10297/*****************************************************************************/
10298
10300 const ctl_t *ctl,
10301 met_t *met) {
10302
10303 met_t *help;
10304
10305 /* Check parameters... */
10306 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
10307 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
10308 return;
10309
10310 /* Set timer... */
10311 SELECT_TIMER("READ_MET_SAMPLE", "METPROC");
10312 LOG(2, "Downsampling of meteo data...");
10313
10314 /* Allocate... */
10315 ALLOC(help, met_t, 1);
10316
10317 /* Copy data... */
10318 help->nx = met->nx;
10319 help->ny = met->ny;
10320 help->np = met->np;
10321 memcpy(help->lon, met->lon, sizeof(met->lon));
10322 memcpy(help->lat, met->lat, sizeof(met->lat));
10323 memcpy(help->p, met->p, sizeof(met->p));
10324
10325 /* Smoothing... */
10326 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
10327 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
10328 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
10329 help->ps[ix][iy] = 0;
10330 help->zs[ix][iy] = 0;
10331 help->ts[ix][iy] = 0;
10332 help->us[ix][iy] = 0;
10333 help->vs[ix][iy] = 0;
10334 help->ess[ix][iy] = 0;
10335 help->nss[ix][iy] = 0;
10336 help->shf[ix][iy] = 0;
10337 help->lsm[ix][iy] = 0;
10338 help->sst[ix][iy] = 0;
10339 help->pbl[ix][iy] = 0;
10340 help->cape[ix][iy] = 0;
10341 help->cin[ix][iy] = 0;
10342 help->t[ix][iy][ip] = 0;
10343 help->u[ix][iy][ip] = 0;
10344 help->v[ix][iy][ip] = 0;
10345 help->w[ix][iy][ip] = 0;
10346 help->h2o[ix][iy][ip] = 0;
10347 help->o3[ix][iy][ip] = 0;
10348 help->lwc[ix][iy][ip] = 0;
10349 help->rwc[ix][iy][ip] = 0;
10350 help->iwc[ix][iy][ip] = 0;
10351 help->swc[ix][iy][ip] = 0;
10352 help->cc[ix][iy][ip] = 0;
10353 float wsum = 0;
10354 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
10355 ix2++) {
10356 int ix3 = ix2;
10357 if (ix3 < 0)
10358 ix3 += met->nx;
10359 else if (ix3 >= met->nx)
10360 ix3 -= met->nx;
10361
10362 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
10363 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
10364 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
10365 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
10366 const float w =
10367 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
10368 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
10369 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
10370 help->ps[ix][iy] += w * met->ps[ix3][iy2];
10371 help->zs[ix][iy] += w * met->zs[ix3][iy2];
10372 help->ts[ix][iy] += w * met->ts[ix3][iy2];
10373 help->us[ix][iy] += w * met->us[ix3][iy2];
10374 help->vs[ix][iy] += w * met->vs[ix3][iy2];
10375 help->ess[ix][iy] += w * met->ess[ix3][iy2];
10376 help->nss[ix][iy] += w * met->nss[ix3][iy2];
10377 help->shf[ix][iy] += w * met->shf[ix3][iy2];
10378 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
10379 help->sst[ix][iy] += w * met->sst[ix3][iy2];
10380 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
10381 help->cape[ix][iy] += w * met->cape[ix3][iy2];
10382 help->cin[ix][iy] += w * met->cin[ix3][iy2];
10383 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
10384 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
10385 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
10386 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
10387 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
10388 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
10389 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
10390 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
10391 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
10392 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
10393 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
10394 wsum += w;
10395 }
10396 }
10397 help->ps[ix][iy] /= wsum;
10398 help->zs[ix][iy] /= wsum;
10399 help->ts[ix][iy] /= wsum;
10400 help->us[ix][iy] /= wsum;
10401 help->vs[ix][iy] /= wsum;
10402 help->ess[ix][iy] /= wsum;
10403 help->nss[ix][iy] /= wsum;
10404 help->shf[ix][iy] /= wsum;
10405 help->lsm[ix][iy] /= wsum;
10406 help->sst[ix][iy] /= wsum;
10407 help->pbl[ix][iy] /= wsum;
10408 help->cape[ix][iy] /= wsum;
10409 help->cin[ix][iy] /= wsum;
10410 help->t[ix][iy][ip] /= wsum;
10411 help->u[ix][iy][ip] /= wsum;
10412 help->v[ix][iy][ip] /= wsum;
10413 help->w[ix][iy][ip] /= wsum;
10414 help->h2o[ix][iy][ip] /= wsum;
10415 help->o3[ix][iy][ip] /= wsum;
10416 help->lwc[ix][iy][ip] /= wsum;
10417 help->rwc[ix][iy][ip] /= wsum;
10418 help->iwc[ix][iy][ip] /= wsum;
10419 help->swc[ix][iy][ip] /= wsum;
10420 help->cc[ix][iy][ip] /= wsum;
10421 }
10422 }
10423 }
10424
10425 /* Downsampling... */
10426 met->nx = 0;
10427 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
10428 met->lon[met->nx] = help->lon[ix];
10429 met->ny = 0;
10430 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
10431 met->lat[met->ny] = help->lat[iy];
10432 met->ps[met->nx][met->ny] = help->ps[ix][iy];
10433 met->zs[met->nx][met->ny] = help->zs[ix][iy];
10434 met->ts[met->nx][met->ny] = help->ts[ix][iy];
10435 met->us[met->nx][met->ny] = help->us[ix][iy];
10436 met->vs[met->nx][met->ny] = help->vs[ix][iy];
10437 met->ess[met->nx][met->ny] = help->ess[ix][iy];
10438 met->nss[met->nx][met->ny] = help->nss[ix][iy];
10439 met->shf[met->nx][met->ny] = help->shf[ix][iy];
10440 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
10441 met->sst[met->nx][met->ny] = help->sst[ix][iy];
10442 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
10443 met->cape[met->nx][met->ny] = help->cape[ix][iy];
10444 met->cin[met->nx][met->ny] = help->cin[ix][iy];
10445 met->np = 0;
10446 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
10447 met->p[met->np] = help->p[ip];
10448 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
10449 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
10450 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
10451 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
10452 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
10453 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
10454 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
10455 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
10456 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
10457 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
10458 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
10459 met->np++;
10460 }
10461 met->ny++;
10462 }
10463 met->nx++;
10464 }
10465
10466 /* Free... */
10467 free(help);
10468}
10469
10470/*****************************************************************************/
10471
10473 const ctl_t *ctl,
10474 const clim_t *clim,
10475 met_t *met) {
10476
10477 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
10478 th2[200], z[EP], z2[200];
10479
10480 /* Set timer... */
10481 SELECT_TIMER("READ_MET_TROPO", "METPROC");
10482 LOG(2, "Calculate tropopause...");
10483
10484 /* Get altitude and pressure profiles... */
10485#pragma omp parallel for default(shared)
10486 for (int iz = 0; iz < met->np; iz++)
10487 z[iz] = Z(met->p[iz]);
10488#pragma omp parallel for default(shared)
10489 for (int iz = 0; iz <= 190; iz++) {
10490 z2[iz] = 4.5 + 0.1 * iz;
10491 p2[iz] = P(z2[iz]);
10492 }
10493
10494 /* Do not calculate tropopause... */
10495 if (ctl->met_tropo == 0)
10496#pragma omp parallel for default(shared) collapse(2)
10497 for (int ix = 0; ix < met->nx; ix++)
10498 for (int iy = 0; iy < met->ny; iy++)
10499 met->pt[ix][iy] = NAN;
10500
10501 /* Use tropopause climatology... */
10502 else if (ctl->met_tropo == 1) {
10503#pragma omp parallel for default(shared) collapse(2)
10504 for (int ix = 0; ix < met->nx; ix++)
10505 for (int iy = 0; iy < met->ny; iy++)
10506 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
10507 }
10508
10509 /* Use cold point... */
10510 else if (ctl->met_tropo == 2) {
10511
10512 /* Loop over grid points... */
10513#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10514 for (int ix = 0; ix < met->nx; ix++)
10515 for (int iy = 0; iy < met->ny; iy++) {
10516
10517 /* Interpolate temperature profile... */
10518 for (int iz = 0; iz < met->np; iz++)
10519 t[iz] = met->t[ix][iy][iz];
10520 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
10521
10522 /* Find minimum... */
10523 int iz = (int) gsl_stats_min_index(t2, 1, 171);
10524 if (iz > 0 && iz < 170)
10525 met->pt[ix][iy] = (float) p2[iz];
10526 else
10527 met->pt[ix][iy] = NAN;
10528 }
10529 }
10530
10531 /* Use WMO definition... */
10532 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
10533
10534 /* Loop over grid points... */
10535#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10536 for (int ix = 0; ix < met->nx; ix++)
10537 for (int iy = 0; iy < met->ny; iy++) {
10538
10539 /* Interpolate temperature profile... */
10540 int iz;
10541 for (iz = 0; iz < met->np; iz++)
10542 t[iz] = met->t[ix][iy][iz];
10543 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
10544
10545 /* Find 1st tropopause... */
10546 met->pt[ix][iy] = NAN;
10547 for (iz = 0; iz <= 170; iz++) {
10548 int found = 1;
10549 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10550 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10551 found = 0;
10552 break;
10553 }
10554 if (found) {
10555 if (iz > 0 && iz < 170)
10556 met->pt[ix][iy] = (float) p2[iz];
10557 break;
10558 }
10559 }
10560
10561 /* Find 2nd tropopause... */
10562 if (ctl->met_tropo == 4) {
10563 met->pt[ix][iy] = NAN;
10564 for (; iz <= 170; iz++) {
10565 int found = 1;
10566 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
10567 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
10568 found = 0;
10569 break;
10570 }
10571 if (found)
10572 break;
10573 }
10574 for (; iz <= 170; iz++) {
10575 int found = 1;
10576 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10577 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10578 found = 0;
10579 break;
10580 }
10581 if (found) {
10582 if (iz > 0 && iz < 170)
10583 met->pt[ix][iy] = (float) p2[iz];
10584 break;
10585 }
10586 }
10587 }
10588 }
10589 }
10590
10591 /* Use dynamical tropopause... */
10592 else if (ctl->met_tropo == 5) {
10593
10594 /* Loop over grid points... */
10595#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
10596 for (int ix = 0; ix < met->nx; ix++)
10597 for (int iy = 0; iy < met->ny; iy++) {
10598
10599 /* Interpolate potential vorticity profile... */
10600 for (int iz = 0; iz < met->np; iz++)
10601 pv[iz] = met->pv[ix][iy][iz];
10602 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
10603
10604 /* Interpolate potential temperature profile... */
10605 for (int iz = 0; iz < met->np; iz++)
10606 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
10607 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
10608
10609 /* Find dynamical tropopause... */
10610 met->pt[ix][iy] = NAN;
10611 for (int iz = 0; iz <= 170; iz++)
10612 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
10613 || th2[iz] >= ctl->met_tropo_theta) {
10614 if (iz > 0 && iz < 170)
10615 met->pt[ix][iy] = (float) p2[iz];
10616 break;
10617 }
10618 }
10619 }
10620
10621 else
10622 ERRMSG("Cannot calculate tropopause!");
10623
10624 /* Interpolate temperature, geopotential height, and water vapor... */
10625#pragma omp parallel for default(shared) collapse(2)
10626 for (int ix = 0; ix < met->nx; ix++)
10627 for (int iy = 0; iy < met->ny; iy++) {
10628 double h2ot, tt, zt;
10630 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
10631 met->lat[iy], &tt, ci, cw, 1);
10632 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
10633 met->lat[iy], &zt, ci, cw, 0);
10634 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
10635 met->lat[iy], &h2ot, ci, cw, 0);
10636 met->tt[ix][iy] = (float) tt;
10637 met->zt[ix][iy] = (float) zt;
10638 met->h2ot[ix][iy] = (float) h2ot;
10639 }
10640}
10641
10642/*****************************************************************************/
10643
10645 const char *filename,
10646 const ctl_t *ctl,
10647 double *rt,
10648 double *rz,
10649 double *rlon,
10650 double *rlat,
10651 double *robs,
10652 int *nobs) {
10653
10654 /* Write info... */
10655 LOG(1, "Read observation data: %s", filename);
10656
10657 /* Read data... */
10658 if (ctl->obs_type == 0)
10659 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
10660 else if (ctl->obs_type == 1)
10661 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
10662 else
10663 ERRMSG("Set OBS_TYPE to 0 or 1!");
10664
10665 /* Check time... */
10666 for (int i = 1; i < *nobs; i++)
10667 if (rt[i] < rt[i - 1])
10668 ERRMSG("Time must be ascending!");
10669
10670 /* Write info... */
10671 int n = *nobs;
10672 double mini, maxi;
10673 LOG(2, "Number of observations: %d", *nobs);
10674 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
10675 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
10676 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
10677 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
10678 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
10679 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
10680 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
10681 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
10682 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
10683 LOG(2, "Observation range: %g ... %g", mini, maxi);
10684}
10685
10686/*****************************************************************************/
10687
10689 const char *filename,
10690 double *rt,
10691 double *rz,
10692 double *rlon,
10693 double *rlat,
10694 double *robs,
10695 int *nobs) {
10696
10697 /* Open observation data file... */
10698 FILE *in;
10699 if (!(in = fopen(filename, "r")))
10700 ERRMSG("Cannot open file!");
10701
10702 /* Read observations... */
10703 char line[LEN];
10704 while (fgets(line, LEN, in))
10705 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
10706 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
10707 if ((++(*nobs)) >= NOBS)
10708 ERRMSG("Too many observations!");
10709
10710 /* Close observation data file... */
10711 fclose(in);
10712}
10713
10714/*****************************************************************************/
10715
10717 const char *filename,
10718 double *rt,
10719 double *rz,
10720 double *rlon,
10721 double *rlat,
10722 double *robs,
10723 int *nobs) {
10724
10725 int ncid, varid;
10726
10727 /* Open netCDF file... */
10728 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
10729 ERRMSG("Cannot open file!");
10730
10731 /* Read the observations from the NetCDF file... */
10732 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
10733 NC_GET_DOUBLE("time", rt, 1);
10734 NC_GET_DOUBLE("alt", rz, 1);
10735 NC_GET_DOUBLE("lon", rlon, 1);
10736 NC_GET_DOUBLE("lat", rlat, 1);
10737 NC_GET_DOUBLE("obs", robs, 1);
10738
10739 /* Close file... */
10740 NC(nc_close(ncid));
10741}
10742
10743/*****************************************************************************/
10744
10746 const char *filename,
10747 int argc,
10748 char *argv[],
10749 const char *varname,
10750 const int arridx,
10751 const char *defvalue,
10752 char *value) {
10753
10754 FILE *in = NULL;
10755
10756 char fullname1[LEN], fullname2[LEN], rval[LEN];
10757
10758 int contain = 0, i;
10759
10760 /* Open file... */
10761 if (filename[strlen(filename) - 1] != '-')
10762 if (!(in = fopen(filename, "r")))
10763 ERRMSG("Cannot open file!");
10764
10765 /* Set full variable name... */
10766 if (arridx >= 0) {
10767 sprintf(fullname1, "%s[%d]", varname, arridx);
10768 sprintf(fullname2, "%s[*]", varname);
10769 } else {
10770 sprintf(fullname1, "%s", varname);
10771 sprintf(fullname2, "%s", varname);
10772 }
10773
10774 /* Read data... */
10775 if (in != NULL) {
10776 char dummy[LEN], line[LEN], rvarname[LEN];
10777 while (fgets(line, LEN, in)) {
10778 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
10779 if (strcasecmp(rvarname, fullname1) == 0 ||
10780 strcasecmp(rvarname, fullname2) == 0) {
10781 contain = 1;
10782 break;
10783 }
10784 }
10785 }
10786 for (i = 1; i < argc - 1; i++)
10787 if (strcasecmp(argv[i], fullname1) == 0 ||
10788 strcasecmp(argv[i], fullname2) == 0) {
10789 sprintf(rval, "%s", argv[i + 1]);
10790 contain = 1;
10791 break;
10792 }
10793
10794 /* Close file... */
10795 if (in != NULL)
10796 fclose(in);
10797
10798 /* Check for missing variables... */
10799 if (!contain) {
10800 if (strlen(defvalue) > 0)
10801 sprintf(rval, "%s", defvalue);
10802 else
10803 ERRMSG("Missing variable %s!\n", fullname1);
10804 }
10805
10806 /* Write info... */
10807 LOG(1, "%s = %s", fullname1, rval);
10808
10809 /* Return values... */
10810 if (value != NULL)
10811 sprintf(value, "%s", rval);
10812 return atof(rval);
10813}
10814
10815/*****************************************************************************/
10816
10817double sedi(
10818 const double p,
10819 const double T,
10820 const double rp,
10821 const double rhop) {
10822
10823 /* Convert particle radius from microns to m... */
10824 const double rp_help = rp * 1e-6;
10825
10826 /* Density of dry air [kg / m^3]... */
10827 const double rho = RHO(p, T);
10828
10829 /* Dynamic viscosity of air [kg / (m s)]... */
10830 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
10831
10832 /* Thermal velocity of an air molecule [m / s]... */
10833 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
10834
10835 /* Mean free path of an air molecule [m]... */
10836 const double lambda = 2. * eta / (rho * v);
10837
10838 /* Knudsen number for air (dimensionless)... */
10839 const double K = lambda / rp_help;
10840
10841 /* Cunningham slip-flow correction (dimensionless)... */
10842 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
10843
10844 /* Sedimentation velocity [m / s]... */
10845 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
10846}
10847
10848/*****************************************************************************/
10849
10851 const double *x,
10852 const double *y,
10853 const int n,
10854 const double *x2,
10855 double *y2,
10856 const int n2,
10857 const int method) {
10858
10859 /* Cubic spline interpolation... */
10860 if (method == 1) {
10861
10862 /* Allocate... */
10863 gsl_interp_accel *acc = gsl_interp_accel_alloc();
10864 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
10865
10866 /* Interpolate profile... */
10867 gsl_spline_init(s, x, y, (size_t) n);
10868 for (int i = 0; i < n2; i++)
10869 if (x2[i] <= x[0])
10870 y2[i] = y[0];
10871 else if (x2[i] >= x[n - 1])
10872 y2[i] = y[n - 1];
10873 else
10874 y2[i] = gsl_spline_eval(s, x2[i], acc);
10875
10876 /* Free... */
10877 gsl_spline_free(s);
10878 gsl_interp_accel_free(acc);
10879 }
10880
10881 /* Linear interpolation... */
10882 else {
10883 for (int i = 0; i < n2; i++)
10884 if (x2[i] <= x[0])
10885 y2[i] = y[0];
10886 else if (x2[i] >= x[n - 1])
10887 y2[i] = y[n - 1];
10888 else {
10889 const int idx = locate_irr(x, n, x2[i]);
10890 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
10891 }
10892 }
10893}
10894
10895/*****************************************************************************/
10896
10898 const float *data,
10899 const int n) {
10900
10901 if (n <= 0)
10902 return 0;
10903
10904 float mean = 0, var = 0;
10905
10906 for (int i = 0; i < n; ++i) {
10907 mean += data[i];
10908 var += SQR(data[i]);
10909 }
10910
10911 var = var / (float) n - SQR(mean / (float) n);
10912
10913 return (var > 0 ? sqrtf(var) : 0);
10914}
10915
10916/*****************************************************************************/
10917
10919 const int year,
10920 const int mon,
10921 const int day,
10922 const int hour,
10923 const int min,
10924 const int sec,
10925 const double remain,
10926 double *jsec) {
10927
10928 struct tm t0, t1;
10929
10930 t0.tm_year = 100;
10931 t0.tm_mon = 0;
10932 t0.tm_mday = 1;
10933 t0.tm_hour = 0;
10934 t0.tm_min = 0;
10935 t0.tm_sec = 0;
10936
10937 t1.tm_year = year - 1900;
10938 t1.tm_mon = mon - 1;
10939 t1.tm_mday = day;
10940 t1.tm_hour = hour;
10941 t1.tm_min = min;
10942 t1.tm_sec = sec;
10943
10944 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
10945}
10946
10947/*****************************************************************************/
10948
10950 const char *name,
10951 const char *group,
10952 const int output) {
10953
10954 static char names[NTIMER][100], groups[NTIMER][100];
10955
10956 static double rt_name[NTIMER], rt_group[NTIMER],
10957 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
10958
10959 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
10960
10961 /* Get time... */
10962 t1 = omp_get_wtime();
10963 dt = t1 - t0;
10964
10965 /* Add elapsed time to current timers... */
10966 if (iname >= 0) {
10967 rt_name[iname] += dt;
10968 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
10969 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
10970 ct_name[iname]++;
10971 }
10972 if (igroup >= 0)
10973 rt_group[igroup] += t1 - t0;
10974
10975 /* Report timers... */
10976 if (output) {
10977 for (int i = 0; i < nname; i++)
10978 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
10979 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
10980 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
10981 for (int i = 0; i < ngroup; i++)
10982 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
10983 double total = 0.0;
10984 for (int i = 0; i < nname; i++)
10985 total += rt_name[i];
10986 LOG(1, "TIMER_TOTAL = %.3f s", total);
10987 }
10988
10989 /* Identify IDs of next timer... */
10990 for (iname = 0; iname < nname; iname++)
10991 if (strcasecmp(name, names[iname]) == 0)
10992 break;
10993 for (igroup = 0; igroup < ngroup; igroup++)
10994 if (strcasecmp(group, groups[igroup]) == 0)
10995 break;
10996
10997 /* Check whether this is a new timer... */
10998 if (iname >= nname) {
10999 sprintf(names[iname], "%s", name);
11000 if ((++nname) >= NTIMER)
11001 ERRMSG("Too many timers!");
11002 }
11003
11004 /* Check whether this is a new group... */
11005 if (igroup >= ngroup) {
11006 sprintf(groups[igroup], "%s", group);
11007 if ((++ngroup) >= NTIMER)
11008 ERRMSG("Too many groups!");
11009 }
11010
11011 /* Save starting time... */
11012 t0 = t1;
11013}
11014
11015/*****************************************************************************/
11016
11018 const char *filename,
11019 const int offset) {
11020
11021 char tstr[10];
11022
11023 double t;
11024
11025 /* Get time from filename... */
11026 int len = (int) strlen(filename);
11027 sprintf(tstr, "%.4s", &filename[len - offset]);
11028 int year = atoi(tstr);
11029 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
11030 int mon = atoi(tstr);
11031 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
11032 int day = atoi(tstr);
11033 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
11034 int hour = atoi(tstr);
11035 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
11036 int min = atoi(tstr);
11037
11038 /* Check time... */
11039 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
11040 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
11041 ERRMSG("Cannot read time from filename!");
11042
11043 /* Convert time to Julian seconds... */
11044 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
11045
11046 /* Return time... */
11047 return t;
11048}
11049
11050/*****************************************************************************/
11051
11053 const clim_t *clim,
11054 const atm_t *atm,
11055 const int ip) {
11056
11057 /* Get tropopause pressure... */
11058 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
11059
11060 /* Get pressure range... */
11061 const double p1 = pt * 0.866877899;
11062 const double p0 = pt / 0.866877899;
11063
11064 /* Get weighting factor... */
11065 if (atm->p[ip] > p0)
11066 return 1;
11067 else if (atm->p[ip] < p1)
11068 return 0;
11069 else
11070 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
11071}
11072
11073/*****************************************************************************/
11074
11076 const char *filename,
11077 const ctl_t *ctl,
11078 const atm_t *atm,
11079 const double t) {
11080
11081 FILE *out;
11082
11083 /* Set time interval for output... */
11084 const double t0 = t - 0.5 * ctl->dt_mod;
11085 const double t1 = t + 0.5 * ctl->dt_mod;
11086
11087 /* Check if gnuplot output is requested... */
11088 if (ctl->atm_gpfile[0] != '-') {
11089
11090 /* Create gnuplot pipe... */
11091 if (!(out = popen("gnuplot", "w")))
11092 ERRMSG("Cannot create pipe to gnuplot!");
11093
11094 /* Set plot filename... */
11095 fprintf(out, "set out \"%s.png\"\n", filename);
11096
11097 /* Set time string... */
11098 double r;
11099 int year, mon, day, hour, min, sec;
11100 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11101 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
11102 year, mon, day, hour, min);
11103
11104 /* Dump gnuplot file to pipe... */
11105 FILE *in;
11106 if (!(in = fopen(ctl->atm_gpfile, "r")))
11107 ERRMSG("Cannot open file!");
11108 char line[LEN];
11109 while (fgets(line, LEN, in))
11110 fprintf(out, "%s", line);
11111 fclose(in);
11112 }
11113
11114 else {
11115
11116 /* Create file... */
11117 if (!(out = fopen(filename, "w")))
11118 ERRMSG("Cannot create file!");
11119 }
11120
11121 /* Write header... */
11122 fprintf(out,
11123 "# $1 = time [s]\n"
11124 "# $2 = altitude [km]\n"
11125 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11126 for (int iq = 0; iq < ctl->nq; iq++)
11127 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
11128 ctl->qnt_unit[iq]);
11129 fprintf(out, "\n");
11130
11131 /* Write data... */
11132 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
11133
11134 /* Check time... */
11135 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11136 continue;
11137
11138 /* Write output... */
11139 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
11140 atm->lon[ip], atm->lat[ip]);
11141 for (int iq = 0; iq < ctl->nq; iq++) {
11142 fprintf(out, " ");
11143 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11144 fprintf(out, ctl->qnt_format[iq], NAN);
11145 else
11146 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11147 }
11148 fprintf(out, "\n");
11149 }
11150
11151 /* Close file... */
11152 fclose(out);
11153}
11154
11155/*****************************************************************************/
11156
11158 const char *filename,
11159 const ctl_t *ctl,
11160 const atm_t *atm) {
11161
11162 FILE *out;
11163
11164 /* Create file... */
11165 if (!(out = fopen(filename, "w")))
11166 ERRMSG("Cannot create file!");
11167
11168 /* Write version of binary data... */
11169 int version = 100;
11170 FWRITE(&version, int,
11171 1,
11172 out);
11173
11174 /* Write data... */
11175 FWRITE(&atm->np, int,
11176 1,
11177 out);
11178 FWRITE(atm->time, double,
11179 (size_t) atm->np,
11180 out);
11181 FWRITE(atm->p, double,
11182 (size_t) atm->np,
11183 out);
11184 FWRITE(atm->lon, double,
11185 (size_t) atm->np,
11186 out);
11187 FWRITE(atm->lat, double,
11188 (size_t) atm->np,
11189 out);
11190 for (int iq = 0; iq < ctl->nq; iq++)
11191 FWRITE(atm->q[iq], double,
11192 (size_t) atm->np,
11193 out);
11194
11195 /* Write final flag... */
11196 int final = 999;
11197 FWRITE(&final, int,
11198 1,
11199 out);
11200
11201 /* Close file... */
11202 fclose(out);
11203}
11204
11205/*****************************************************************************/
11206
11208 const char *filename,
11209 const ctl_t *ctl,
11210 const atm_t *atm) {
11211
11212 int tid, pid, ncid, varid;
11213 size_t start[2], count[2];
11214
11215 /* Create file... */
11216 NC(nc_create(filename, NC_NETCDF4, &ncid));
11217
11218 /* Define dimensions... */
11219 NC(nc_def_dim(ncid, "time", 1, &tid));
11220 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11221
11222 /* Define variables and their attributes... */
11223 int dim_ids[2] = { tid, pid };
11224 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11225 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11226 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11227 ctl->atm_nc_level, 0);
11228 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11229 ctl->atm_nc_level, 0);
11230 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11231 ctl->atm_nc_level, 0);
11232 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11233 for (int iq = 0; iq < ctl->nq; iq++)
11234 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11235 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11236 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11237
11238 /* Define global attributes... */
11239 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11240 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11241
11242 /* End definitions... */
11243 NC(nc_enddef(ncid));
11244
11245 /* Write data... */
11246 NC_PUT_DOUBLE("time", atm->time, 0);
11247 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11248 NC_PUT_DOUBLE("LON", atm->lon, 0);
11249 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11250 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11251 for (int iq = 0; iq < ctl->nq; iq++)
11252 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11253
11254 /* Close file... */
11255 NC(nc_close(ncid));
11256}
11257
11258/*****************************************************************************/
11259
11261 const char *dirname,
11262 const ctl_t *ctl,
11263 const atm_t *atm,
11264 const double t) {
11265
11266 /* Global Counter... */
11267 static size_t out_cnt = 0;
11268
11269 double r, r_start, r_stop;
11270 int year, mon, day, hour, min, sec;
11271 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
11272 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
11273 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
11274
11275 int ncid, varid, tid, pid, cid;
11276 int dim_ids[2];
11277
11278 /* time, nparc */
11279 size_t start[2];
11280 size_t count[2];
11281
11282 /* Determine start and stop times of calculation... */
11283 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11284 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
11285 &min_start, &sec_start, &r_start);
11286 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
11287 &min_stop, &sec_stop, &r_stop);
11288
11289 sprintf(filename_out,
11290 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
11291 year_start % 100, mon_start, day_start, hour_start,
11292 year_stop % 100, mon_stop, day_stop, hour_stop);
11293 LOG(1, "Write traj file: %s", filename_out);
11294
11295 /* Define hyperslap for the traj_file... */
11296 start[0] = out_cnt;
11297 start[1] = 0;
11298 count[0] = 1;
11299 count[1] = (size_t) atm->np;
11300
11301 /* Create the file at the first timestep... */
11302 if (out_cnt == 0) {
11303
11304 /* Create file... */
11305 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
11306
11307 /* Define dimensions... */
11308 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
11309 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11310 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
11311 dim_ids[0] = tid;
11312 dim_ids[1] = pid;
11313
11314 /* Define variables and their attributes... */
11315 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11316 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11317 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
11318 ctl->atm_nc_level, 0);
11319 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
11320 ctl->atm_nc_level, 0);
11321 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
11322 ctl->atm_nc_level, 0);
11323 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
11324 ctl->atm_nc_level, 0);
11325 for (int iq = 0; iq < ctl->nq; iq++)
11326 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11327 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11328 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11329
11330 /* Define global attributes... */
11331 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11332 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11333
11334 /* End definitions... */
11335 NC(nc_enddef(ncid));
11336 NC(nc_close(ncid));
11337 }
11338
11339 /* Increment global counter to change hyperslap... */
11340 out_cnt++;
11341
11342 /* Open file... */
11343 NC(nc_open(filename_out, NC_WRITE, &ncid));
11344
11345 /* Write data... */
11346 NC_PUT_DOUBLE("time", atm->time, 1);
11347 NC_PUT_DOUBLE("LAT", atm->lat, 1);
11348 NC_PUT_DOUBLE("LON", atm->lon, 1);
11349 NC_PUT_DOUBLE("PRESS", atm->p, 1);
11350 if (ctl->advect_vert_coord == 1) {
11351 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
11352 } else if (ctl->qnt_zeta >= 0) {
11353 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
11354 }
11355 for (int iq = 0; iq < ctl->nq; iq++)
11356 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
11357
11358 /* Close file... */
11359 NC(nc_close(ncid));
11360
11361 /* At the last time step create the init_fix_YYYYMMDDHH file... */
11362 if ((year == year_stop) && (mon == mon_stop)
11363 && (day == day_stop) && (hour == hour_stop)) {
11364
11365 /* Set filename... */
11366 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
11367 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
11368 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
11369 LOG(1, "Write init file: %s", filename_init);
11370
11371 /* Create file... */
11372 NC(nc_create(filename_init, NC_NETCDF4, &ncid));
11373
11374 /* Define dimensions... */
11375 NC(nc_def_dim(ncid, "time", 1, &tid));
11376 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11377 dim_ids[0] = tid;
11378 dim_ids[1] = pid;
11379
11380 /* Define variables and their attributes... */
11381 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11382 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11383 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11384 ctl->atm_nc_level, 0);
11385 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11386 ctl->atm_nc_level, 0);
11387 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11388 ctl->atm_nc_level, 0);
11389 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11390 for (int iq = 0; iq < ctl->nq; iq++)
11391 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11392 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11393 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11394
11395 /* Define global attributes... */
11396 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11397 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11398
11399 /* End definitions... */
11400 NC(nc_enddef(ncid));
11401
11402 /* Write data... */
11403 NC_PUT_DOUBLE("time", atm->time, 0);
11404 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11405 NC_PUT_DOUBLE("LON", atm->lon, 0);
11406 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11407 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11408 for (int iq = 0; iq < ctl->nq; iq++)
11409 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11410
11411 /* Close file... */
11412 NC(nc_close(ncid));
11413 }
11414}
11415
11416/*****************************************************************************/
11417
11419 const char *filename,
11420 const ctl_t *ctl,
11421 const atm_t *atm) {
11422
11423 int ncid, obsid, varid;
11424
11425 size_t start[2], count[2];
11426
11427 /* Create file... */
11428 NC(nc_create(filename, NC_NETCDF4, &ncid));
11429
11430 /* Define dimensions... */
11431 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
11432
11433 /* Define variables and their attributes... */
11434 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
11435 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11436 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
11437 ctl->atm_nc_level, 0);
11438 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
11439 ctl->atm_nc_level, 0);
11440 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
11441 ctl->atm_nc_level, 0);
11442 for (int iq = 0; iq < ctl->nq; iq++)
11443 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
11444 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
11445 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11446
11447 /* Define global attributes... */
11448 NC_PUT_ATT_GLOBAL("featureType", "point");
11449
11450 /* End definitions... */
11451 NC(nc_enddef(ncid));
11452
11453 /* Write data... */
11454 NC_PUT_DOUBLE("time", atm->time, 0);
11455 NC_PUT_DOUBLE("press", atm->p, 0);
11456 NC_PUT_DOUBLE("lon", atm->lon, 0);
11457 NC_PUT_DOUBLE("lat", atm->lat, 0);
11458 for (int iq = 0; iq < ctl->nq; iq++)
11459 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11460
11461 /* Close file... */
11462 NC(nc_close(ncid));
11463}
11464
11465/*****************************************************************************/
11466
11468 const char *filename,
11469 const ctl_t *ctl,
11470 const atm_t *atm,
11471 const double t) {
11472
11473 static FILE *out;
11474
11475 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
11476 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
11477
11478 static int *obscount, nobs, nk;
11479
11480 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
11481
11482 const int ensemble = (ctl->nens > 0);
11483
11484 /* Set timer */
11485 SELECT_TIMER("WRITE_CSI", "OUTPUT");
11486
11487 /* Check quantities... */
11488 if (ctl->qnt_m < 0)
11489 ERRMSG("Need quantity mass!");
11490 if (ensemble) {
11491 if (ctl->qnt_ens < 0)
11492 ERRMSG("Missing ensemble IDs!");
11493 if (ctl->nens > NENS)
11494 ERRMSG("Too many ensembles!");
11495 }
11496
11497 /* Init... */
11498 if (t == ctl->t_start) {
11499
11500 /* Allocate.. */
11501 ALLOC(area, double,
11502 ctl->csi_ny);
11503 ALLOC(rt, double,
11504 NOBS);
11505 ALLOC(rz, double,
11506 NOBS);
11507 ALLOC(rlon, double,
11508 NOBS);
11509 ALLOC(rlat, double,
11510 NOBS);
11511 ALLOC(robs, double,
11512 NOBS);
11513
11514 /* Read observation data... */
11515 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11516
11517 /* Read kernel data... */
11518 if (ctl->csi_kernel[0] != '-')
11519 read_kernel(ctl->csi_kernel, kz, kw, &nk);
11520
11521 /* Create new file... */
11522 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
11523 if (!(out = fopen(filename, "w")))
11524 ERRMSG("Cannot create file!");
11525
11526 /* Write header... */
11527 fprintf(out,
11528 "# $1 = time [s]\n"
11529 "# $2 = ensemble ID\n"
11530 "# $3 = number of hits (cx)\n"
11531 "# $4 = number of misses (cy)\n"
11532 "# $5 = number of false alarms (cz)\n"
11533 "# $6 = number of observations (cx + cy)\n"
11534 "# $7 = number of forecasts (cx + cz)\n"
11535 "# $8 = bias (%%)\n"
11536 "# $9 = POD (%%)\n"
11537 "# $10 = FAR (%%)\n"
11538 "# $11 = CSI (%%)\n"
11539 "# $12 = hits by random chance\n"
11540 "# $13 = ETS (%%)\n"
11541 "# $14 = Pearson R\n"
11542 "# $15 = Spearman R\n"
11543 "# $16 = mean error [kg/m²]\n"
11544 "# $17 = RMSE [kg/m²]\n"
11545 "# $18 = MAE [kg/m²]\n"
11546 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
11547
11548 /* Set grid box size... */
11549 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
11550 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
11551 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
11552
11553 /* Set horizontal coordinates... */
11554 for (int iy = 0; iy < ctl->csi_ny; iy++) {
11555 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
11556 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
11557 }
11558 }
11559
11560 /* Set time interval... */
11561 const double t0 = t - 0.5 * ctl->dt_mod;
11562 const double t1 = t + 0.5 * ctl->dt_mod;
11563
11564 /* Allocate... */
11565 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
11566 ALLOC(modmean, double,
11567 (ensemble ? ctl->nens : 1) * grid_size);
11568 ALLOC(obsmean, double,
11569 grid_size);
11570 ALLOC(obscount, int,
11571 grid_size);
11572 ALLOC(obsstd, double,
11573 grid_size);
11574
11575 /* Init... */
11576 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
11577 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
11578
11579 /* Loop over observations... */
11580 for (int i = 0; i < nobs; i++) {
11581 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
11582 continue;
11583
11584 /* Calculate indices... */
11585 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
11586 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
11587 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
11588 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11589 || iz >= ctl->csi_nz)
11590 continue;
11591
11592 /* Get mean observation index... */
11593 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11594 obsmean[idx] += robs[i];
11595 obsstd[idx] += SQR(robs[i]);
11596 obscount[idx]++;
11597 }
11598
11599 /* Analyze model data... */
11600 for (int ip = 0; ip < atm->np; ip++) {
11601
11602 /* Check time... */
11603 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11604 continue;
11605
11606 /* Get ensemble ID... */
11607 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
11608 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
11609 ERRMSG("Ensemble ID out of range!");
11610
11611 /* Get indices... */
11612 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
11613 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
11614 const int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
11615 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11616 || iz >= ctl->csi_nz)
11617 continue;
11618
11619 /* Get total mass in grid cell... */
11620 const int idx =
11621 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11622 modmean[idx] +=
11623 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11624 }
11625 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11626 /* Analyze all grid cells... */
11627 for (int ix = 0; ix < ctl->csi_nx; ix++)
11628 for (int iy = 0; iy < ctl->csi_ny; iy++)
11629 for (int iz = 0; iz < ctl->csi_nz; iz++) {
11630
11631 /* Calculate mean observation index... */
11632 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11633 if (e == 0)
11634 if (obscount[idx]) {
11635 obsmean[idx] /= obscount[idx];
11636 obsstd[idx] =
11637 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
11638 }
11639
11640 /* Calculate model mean per ensemble... */
11641 const int midx = e * grid_size + idx;
11642 if (modmean[midx] > 0)
11643 modmean[midx] /= (1e6 * area[iy]);
11644
11645 /* Check number of observations... */
11646 if (obscount[idx]) {
11647
11648 /* Calculate CSI... */
11649 ct[e]++;
11650 if (obsmean[idx] >= ctl->csi_obsmin
11651 && modmean[midx] >= ctl->csi_modmin)
11652 cx[e]++;
11653 else if (obsmean[idx] >= ctl->csi_obsmin)
11654 cy[e]++;
11655 else if (modmean[midx] >= ctl->csi_modmin)
11656 cz[e]++;
11657
11658 /* Save data for other verification statistics... */
11659 if (obsmean[idx] >= ctl->csi_obsmin
11660 || modmean[midx] >= ctl->csi_modmin) {
11661 x[n[e]] = modmean[midx];
11662 y[n[e]] = obsmean[idx];
11663 if (modmean[midx] >= ctl->csi_modmin)
11664 obsstdn[n[e]] = obsstd[idx];
11665 if ((++n[e]) >= NCSI)
11666 ERRMSG("Too many points for statistics!");
11667 }
11668 }
11669 }
11670 /* Write output... */
11671 if (fmod(t, ctl->csi_dt_out) == 0) {
11672
11673 if (n[e] == 0)
11674 continue;
11675
11676 /* Calculate verification statistics
11677 (https://www.cawcr.gov.au/projects/verification/) ... */
11678 static double work[2 * NCSI], work2[2 * NCSI];
11679 const int n_obs = cx[e] + cy[e];
11680 const int n_for = cx[e] + cz[e];
11681 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
11682 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
11683 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
11684 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
11685 const double csi =
11686 (cx[e] + cy[e] + cz[e] >
11687 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
11688 const double ets =
11689 (cx[e] + cy[e] + cz[e] - cx_rd >
11690 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
11691 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
11692 const double rho_s =
11693 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
11694 for (int i = 0; i < n[e]; i++) {
11695 work[i] = x[i] - y[i];
11696 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
11697 }
11698 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
11699 const double rmse =
11700 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
11701 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
11702 const double loglikelihood =
11703 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
11704
11705 /* Write... */
11706 fprintf(out,
11707 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
11708 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
11709 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
11710 loglikelihood, n[e]);
11711
11712 /* Set counters to zero... */
11713 for (int i = 0; i < n[e]; i++)
11714 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
11715 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
11716 }
11717 }
11718 /* Free... */
11719 free(modmean);
11720 free(obsmean);
11721 free(obscount);
11722 free(obsstd);
11723
11724 /* Finalize... */
11725 if (t == ctl->t_stop) {
11726
11727 /* Close output file... */
11728 fclose(out);
11729
11730 /* Free... */
11731 free(area);
11732 free(rt);
11733 free(rz);
11734 free(rlon);
11735 free(rlat);
11736 free(robs);
11737 }
11738}
11739
11740/*****************************************************************************/
11741
11743 const char *filename,
11744 const ctl_t *ctl,
11745 const atm_t *atm,
11746 const double t) {
11747
11748 static FILE *out;
11749
11750 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
11751 x[3], zm[NENS];
11752
11753 static int n[NENS];
11754
11755 /* Set timer... */
11756 SELECT_TIMER("WRITE_ENS", "OUTPUT");
11757
11758 /* Check quantities... */
11759 if (ctl->qnt_ens < 0)
11760 ERRMSG("Missing ensemble IDs!");
11761
11762 /* Set time interval... */
11763 const double t0 = t - 0.5 * ctl->dt_mod;
11764 const double t1 = t + 0.5 * ctl->dt_mod;
11765
11766 /* Init... */
11767 for (int i = 0; i < NENS; i++) {
11768 for (int iq = 0; iq < ctl->nq; iq++)
11769 qm[iq][i] = qs[iq][i] = 0;
11770 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
11771 n[i] = 0;
11772 }
11773
11774 /* Loop over air parcels... */
11775 for (int ip = 0; ip < atm->np; ip++) {
11776
11777 /* Check time... */
11778 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11779 continue;
11780
11781 /* Check ensemble ID... */
11782 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
11783 ERRMSG("Ensemble ID is out of range!");
11784
11785 /* Get means... */
11786 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
11787 for (int iq = 0; iq < ctl->nq; iq++) {
11788 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
11789 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
11790 }
11791 xm[ctl->qnt_ens][0] += x[0];
11792 xm[ctl->qnt_ens][1] += x[1];
11793 xm[ctl->qnt_ens][2] += x[2];
11794 zm[ctl->qnt_ens] += Z(atm->p[ip]);
11795 n[ctl->qnt_ens]++;
11796 }
11797
11798 /* Create file... */
11799 LOG(1, "Write ensemble data: %s", filename);
11800 if (!(out = fopen(filename, "w")))
11801 ERRMSG("Cannot create file!");
11802
11803 /* Write header... */
11804 fprintf(out,
11805 "# $1 = time [s]\n"
11806 "# $2 = altitude [km]\n"
11807 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11808 for (int iq = 0; iq < ctl->nq; iq++)
11809 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
11810 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11811 for (int iq = 0; iq < ctl->nq; iq++)
11812 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
11813 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11814 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
11815
11816 /* Write data... */
11817 for (int i = 0; i < NENS; i++)
11818 if (n[i] > 0) {
11819 cart2geo(xm[i], &dummy, &lon, &lat);
11820 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
11821 for (int iq = 0; iq < ctl->nq; iq++) {
11822 fprintf(out, " ");
11823 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
11824 }
11825 for (int iq = 0; iq < ctl->nq; iq++) {
11826 fprintf(out, " ");
11827 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
11828 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
11829 }
11830 fprintf(out, " %d\n", n[i]);
11831 }
11832
11833 /* Close file... */
11834 fclose(out);
11835}
11836
11837/*****************************************************************************/
11838
11840 const char *filename,
11841 const ctl_t *ctl,
11842 met_t *met0,
11843 met_t *met1,
11844 const atm_t *atm,
11845 const double t) {
11846
11847 static double kz[EP], kw[EP];
11848
11849 static int nk;
11850
11851 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
11852
11853 int *ixs, *iys, *izs, *np;
11854
11855 /* Set timer... */
11856 SELECT_TIMER("WRITE_GRID", "OUTPUT");
11857
11858 /* Write info... */
11859 LOG(1, "Write grid data: %s", filename);
11860
11861 /* Init... */
11862 if (t == ctl->t_start) {
11863
11864 /* Read kernel data... */
11865 if (ctl->grid_kernel[0] != '-')
11866 read_kernel(ctl->grid_kernel, kz, kw, &nk);
11867 }
11868
11869 /* Allocate... */
11870 ALLOC(cd, double,
11871 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11872 for (int iq = 0; iq < ctl->nq; iq++) {
11873 ALLOC(mean[iq], double,
11874 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11875 ALLOC(sigma[iq], double,
11876 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11877 }
11878 ALLOC(vmr_impl, double,
11879 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11880 ALLOC(z, double,
11881 ctl->grid_nz);
11882 ALLOC(lon, double,
11883 ctl->grid_nx);
11884 ALLOC(lat, double,
11885 ctl->grid_ny);
11886 ALLOC(area, double,
11887 ctl->grid_ny);
11888 ALLOC(press, double,
11889 ctl->grid_nz);
11890 ALLOC(np, int,
11891 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11892 ALLOC(ixs, int,
11893 atm->np);
11894 ALLOC(iys, int,
11895 atm->np);
11896 ALLOC(izs, int,
11897 atm->np);
11898
11899 /* Set grid box size... */
11900 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
11901 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
11902 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
11903
11904 /* Set vertical coordinates... */
11905#pragma omp parallel for default(shared)
11906 for (int iz = 0; iz < ctl->grid_nz; iz++) {
11907 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
11908 press[iz] = P(z[iz]);
11909 }
11910
11911 /* Set horizontal coordinates... */
11912 for (int ix = 0; ix < ctl->grid_nx; ix++)
11913 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
11914#pragma omp parallel for default(shared)
11915 for (int iy = 0; iy < ctl->grid_ny; iy++) {
11916 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
11917 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
11918 }
11919
11920 /* Set time interval for output... */
11921 const double t0 = t - 0.5 * ctl->dt_mod;
11922 const double t1 = t + 0.5 * ctl->dt_mod;
11923
11924 /* Get grid box indices... */
11925#pragma omp parallel for default(shared)
11926 for (int ip = 0; ip < atm->np; ip++) {
11927 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
11928 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
11929 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
11930 if (atm->time[ip] < t0 || atm->time[ip] > t1
11931 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
11932 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
11933 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
11934 izs[ip] = -1;
11935 }
11936
11937 /* Average data... */
11938 for (int ip = 0; ip < atm->np; ip++)
11939 if (izs[ip] >= 0) {
11940 const int idx =
11941 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
11942 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
11943 np[idx]++;
11944 for (int iq = 0; iq < ctl->nq; iq++) {
11945 mean[iq][idx] += kernel * atm->q[iq][ip];
11946 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
11947 }
11948 }
11949
11950 /* Calculate column density and volume mixing ratio... */
11951#pragma omp parallel for default(shared)
11952 for (int ix = 0; ix < ctl->grid_nx; ix++)
11953 for (int iy = 0; iy < ctl->grid_ny; iy++)
11954 for (int iz = 0; iz < ctl->grid_nz; iz++) {
11955
11956 /* Get grid index... */
11957 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
11958
11959 /* Calculate column density... */
11960 cd[idx] = NAN;
11961 if (ctl->qnt_m >= 0)
11962 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
11963
11964 /* Calculate volume mixing ratio (implicit)... */
11965 vmr_impl[idx] = NAN;
11966 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
11967 && met1 != NULL) {
11968 vmr_impl[idx] = 0;
11969 if (mean[ctl->qnt_m][idx] > 0) {
11970
11971 /* Get temperature... */
11972 double temp;
11974 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
11975 lon[ix], lat[iy], &temp, ci, cw, 1);
11976
11977 /* Calculate volume mixing ratio... */
11978 vmr_impl[idx] =
11979 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
11980 }
11981 }
11982
11983 /* Calculate mean... */
11984 if (np[idx] > 0)
11985 for (int iq = 0; iq < ctl->nq; iq++) {
11986 mean[iq][idx] /= np[idx];
11987 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
11988 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
11989 } else
11990 for (int iq = 0; iq < ctl->nq; iq++) {
11991 mean[iq][idx] = NAN;
11992 sigma[iq][idx] = NAN;
11993 }
11994 }
11995
11996 /* Write ASCII data... */
11997 if (ctl->grid_type == 0)
11998 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
11999 t, z, lon, lat, area, dz, np);
12000
12001 /* Write netCDF data... */
12002 else if (ctl->grid_type == 1)
12003 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
12004 t, z, lon, lat, area, dz, np);
12005
12006 /* Error message... */
12007 else
12008 ERRMSG("Grid data format GRID_TYPE unknown!");
12009
12010 /* Free... */
12011 free(cd);
12012 for (int iq = 0; iq < ctl->nq; iq++) {
12013 free(mean[iq]);
12014 free(sigma[iq]);
12015 }
12016 free(vmr_impl);
12017 free(z);
12018 free(lon);
12019 free(lat);
12020 free(area);
12021 free(press);
12022 free(np);
12023 free(ixs);
12024 free(iys);
12025 free(izs);
12026}
12027
12028/*****************************************************************************/
12029
12031 const char *filename,
12032 const ctl_t *ctl,
12033 const double *cd,
12034 double *mean[NQ],
12035 double *sigma[NQ],
12036 const double *vmr_impl,
12037 const double t,
12038 const double *z,
12039 const double *lon,
12040 const double *lat,
12041 const double *area,
12042 const double dz,
12043 const int *np) {
12044
12045 FILE *out;
12046
12047 /* Check if gnuplot output is requested... */
12048 if (ctl->grid_gpfile[0] != '-') {
12049
12050 /* Create gnuplot pipe... */
12051 if (!(out = popen("gnuplot", "w")))
12052 ERRMSG("Cannot create pipe to gnuplot!");
12053
12054 /* Set plot filename... */
12055 fprintf(out, "set out \"%s.png\"\n", filename);
12056
12057 /* Set time string... */
12058 double r;
12059 int year, mon, day, hour, min, sec;
12060 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12061 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12062 year, mon, day, hour, min);
12063
12064 /* Dump gnuplot file to pipe... */
12065 FILE *in;
12066 char line[LEN];
12067 if (!(in = fopen(ctl->grid_gpfile, "r")))
12068 ERRMSG("Cannot open file!");
12069 while (fgets(line, LEN, in))
12070 fprintf(out, "%s", line);
12071 fclose(in);
12072 }
12073
12074 else {
12075
12076 /* Create file... */
12077 if (!(out = fopen(filename, "w")))
12078 ERRMSG("Cannot create file!");
12079 }
12080
12081 /* Write header... */
12082 fprintf(out,
12083 "# $1 = time [s]\n"
12084 "# $2 = altitude [km]\n"
12085 "# $3 = longitude [deg]\n"
12086 "# $4 = latitude [deg]\n"
12087 "# $5 = surface area [km^2]\n"
12088 "# $6 = layer depth [km]\n"
12089 "# $7 = column density (implicit) [kg/m^2]\n"
12090 "# $8 = volume mixing ratio (implicit) [ppv]\n"
12091 "# $9 = number of particles [1]\n");
12092 for (int iq = 0; iq < ctl->nq; iq++)
12093 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
12094 ctl->qnt_unit[iq]);
12095 if (ctl->grid_stddev)
12096 for (int iq = 0; iq < ctl->nq; iq++)
12097 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
12098 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12099 fprintf(out, "\n");
12100
12101 /* Write data... */
12102 for (int ix = 0; ix < ctl->grid_nx; ix++) {
12103 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
12104 fprintf(out, "\n");
12105 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12106 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
12107 fprintf(out, "\n");
12108 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12109 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12110 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
12111 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
12112 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
12113 for (int iq = 0; iq < ctl->nq; iq++) {
12114 fprintf(out, " ");
12115 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
12116 }
12117 if (ctl->grid_stddev)
12118 for (int iq = 0; iq < ctl->nq; iq++) {
12119 fprintf(out, " ");
12120 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
12121 }
12122 fprintf(out, "\n");
12123 }
12124 }
12125 }
12126 }
12127
12128 /* Close file... */
12129 fclose(out);
12130}
12131
12132/*****************************************************************************/
12133
12135 const char *filename,
12136 const ctl_t *ctl,
12137 const double *cd,
12138 double *mean[NQ],
12139 double *sigma[NQ],
12140 const double *vmr_impl,
12141 const double t,
12142 const double *z,
12143 const double *lon,
12144 const double *lat,
12145 const double *area,
12146 const double dz,
12147 const int *np) {
12148
12149 char longname[2 * LEN], varname[2 * LEN];
12150
12151 double *help;
12152
12153 int *help2, ncid, dimid[10], varid;
12154
12155 size_t start[2], count[2];
12156
12157 /* Allocate... */
12158 ALLOC(help, double,
12159 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12160 ALLOC(help2, int,
12161 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12162
12163 /* Create file... */
12164 NC(nc_create(filename, NC_NETCDF4, &ncid));
12165
12166 /* Define dimensions... */
12167 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
12168 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
12169 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
12170 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
12171 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
12172
12173 /* Define variables and their attributes... */
12174 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
12175 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12176 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
12177 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
12178 0);
12179 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
12180 0);
12181 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
12182 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
12183
12184 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
12185 ctl->grid_nc_level, 0);
12186 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
12187 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
12188 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
12189 for (int iq = 0; iq < ctl->nq; iq++) {
12190 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12191 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
12192 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12193 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12194 if (ctl->grid_stddev) {
12195 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12196 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
12197 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12198 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12199 }
12200 }
12201 /* End definitions... */
12202 NC(nc_enddef(ncid));
12203
12204 /* Write data... */
12205 NC_PUT_DOUBLE("time", &t, 0);
12206 NC_PUT_DOUBLE("lon", lon, 0);
12207 NC_PUT_DOUBLE("lat", lat, 0);
12208 NC_PUT_DOUBLE("z", z, 0);
12209 NC_PUT_DOUBLE("area", area, 0);
12210 NC_PUT_DOUBLE("dz", &dz, 0);
12211
12212 for (int ix = 0; ix < ctl->grid_nx; ix++)
12213 for (int iy = 0; iy < ctl->grid_ny; iy++)
12214 for (int iz = 0; iz < ctl->grid_nz; iz++)
12215 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12216 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12217 NC_PUT_DOUBLE("cd", help, 0);
12218
12219 for (int ix = 0; ix < ctl->grid_nx; ix++)
12220 for (int iy = 0; iy < ctl->grid_ny; iy++)
12221 for (int iz = 0; iz < ctl->grid_nz; iz++)
12222 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12223 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12224 NC_PUT_DOUBLE("vmr_impl", help, 0);
12225
12226 for (int ix = 0; ix < ctl->grid_nx; ix++)
12227 for (int iy = 0; iy < ctl->grid_ny; iy++)
12228 for (int iz = 0; iz < ctl->grid_nz; iz++)
12229 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12230 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12231 NC_PUT_INT("np", help2, 0);
12232
12233 for (int iq = 0; iq < ctl->nq; iq++) {
12234 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12235 for (int ix = 0; ix < ctl->grid_nx; ix++)
12236 for (int iy = 0; iy < ctl->grid_ny; iy++)
12237 for (int iz = 0; iz < ctl->grid_nz; iz++)
12238 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12239 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12240 NC_PUT_DOUBLE(varname, help, 0);
12241 }
12242
12243 if (ctl->grid_stddev)
12244 for (int iq = 0; iq < ctl->nq; iq++) {
12245 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12246 for (int ix = 0; ix < ctl->grid_nx; ix++)
12247 for (int iy = 0; iy < ctl->grid_ny; iy++)
12248 for (int iz = 0; iz < ctl->grid_nz; iz++)
12249 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12250 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12251 NC_PUT_DOUBLE(varname, help, 0);
12252 }
12253
12254 /* Close file... */
12255 NC(nc_close(ncid));
12256
12257 /* Free... */
12258 free(help);
12259 free(help2);
12260}
12261
12262/*****************************************************************************/
12263
12265 const char *filename,
12266 const ctl_t *ctl,
12267 met_t *met) {
12268
12269 /* Create file... */
12270 FILE *out;
12271 if (!(out = fopen(filename, "w")))
12272 ERRMSG("Cannot create file!");
12273
12274 /* Write type of binary data... */
12275 FWRITE(&ctl->met_type, int,
12276 1,
12277 out);
12278
12279 /* Write version of binary data... */
12280 int version = 103;
12281 FWRITE(&version, int,
12282 1,
12283 out);
12284
12285 /* Write grid data... */
12286 FWRITE(&met->time, double,
12287 1,
12288 out);
12289 FWRITE(&met->nx, int,
12290 1,
12291 out);
12292 FWRITE(&met->ny, int,
12293 1,
12294 out);
12295 FWRITE(&met->np, int,
12296 1,
12297 out);
12298 FWRITE(met->lon, double,
12299 (size_t) met->nx,
12300 out);
12301 FWRITE(met->lat, double,
12302 (size_t) met->ny,
12303 out);
12304 FWRITE(met->p, double,
12305 (size_t) met->np,
12306 out);
12307
12308 /* Write surface data... */
12309 write_met_bin_2d(out, met, met->ps, "PS");
12310 write_met_bin_2d(out, met, met->ts, "TS");
12311 write_met_bin_2d(out, met, met->zs, "ZS");
12312 write_met_bin_2d(out, met, met->us, "US");
12313 write_met_bin_2d(out, met, met->vs, "VS");
12314 write_met_bin_2d(out, met, met->ess, "ESS");
12315 write_met_bin_2d(out, met, met->nss, "NSS");
12316 write_met_bin_2d(out, met, met->shf, "SHF");
12317 write_met_bin_2d(out, met, met->lsm, "LSM");
12318 write_met_bin_2d(out, met, met->sst, "SST");
12319 write_met_bin_2d(out, met, met->pbl, "PBL");
12320 write_met_bin_2d(out, met, met->pt, "PT");
12321 write_met_bin_2d(out, met, met->tt, "TT");
12322 write_met_bin_2d(out, met, met->zt, "ZT");
12323 write_met_bin_2d(out, met, met->h2ot, "H2OT");
12324 write_met_bin_2d(out, met, met->pct, "PCT");
12325 write_met_bin_2d(out, met, met->pcb, "PCB");
12326 write_met_bin_2d(out, met, met->cl, "CL");
12327 write_met_bin_2d(out, met, met->plcl, "PLCL");
12328 write_met_bin_2d(out, met, met->plfc, "PLFC");
12329 write_met_bin_2d(out, met, met->pel, "PEL");
12330 write_met_bin_2d(out, met, met->cape, "CAPE");
12331 write_met_bin_2d(out, met, met->cin, "CIN");
12332 write_met_bin_2d(out, met, met->o3c, "O3C");
12333
12334 /* Write level data... */
12335 write_met_bin_3d(out, ctl, met, met->z, "Z",
12336 ctl->met_comp_prec[0], ctl->met_comp_tol[0]);
12337 write_met_bin_3d(out, ctl, met, met->t, "T",
12338 ctl->met_comp_prec[1], ctl->met_comp_tol[1]);
12339 write_met_bin_3d(out, ctl, met, met->u, "U",
12340 ctl->met_comp_prec[2], ctl->met_comp_tol[2]);
12341 write_met_bin_3d(out, ctl, met, met->v, "V",
12342 ctl->met_comp_prec[3], ctl->met_comp_tol[3]);
12343 write_met_bin_3d(out, ctl, met, met->w, "W",
12344 ctl->met_comp_prec[4], ctl->met_comp_tol[4]);
12345 write_met_bin_3d(out, ctl, met, met->pv, "PV",
12346 ctl->met_comp_prec[5], ctl->met_comp_tol[5]);
12347 write_met_bin_3d(out, ctl, met, met->h2o, "H2O",
12348 ctl->met_comp_prec[6], ctl->met_comp_tol[6]);
12349 write_met_bin_3d(out, ctl, met, met->o3, "O3",
12350 ctl->met_comp_prec[7], ctl->met_comp_tol[7]);
12351 write_met_bin_3d(out, ctl, met, met->lwc, "LWC",
12352 ctl->met_comp_prec[8], ctl->met_comp_tol[8]);
12353 write_met_bin_3d(out, ctl, met, met->rwc, "RWC",
12354 ctl->met_comp_prec[9], ctl->met_comp_tol[9]);
12355 write_met_bin_3d(out, ctl, met, met->iwc, "IWC",
12356 ctl->met_comp_prec[10], ctl->met_comp_tol[10]);
12357 write_met_bin_3d(out, ctl, met, met->swc, "SWC",
12358 ctl->met_comp_prec[11], ctl->met_comp_tol[11]);
12359 write_met_bin_3d(out, ctl, met, met->cc, "CC",
12360 ctl->met_comp_prec[12], ctl->met_comp_tol[12]);
12361 if (METVAR != 13)
12362 ERRMSG("Number of meteo variables doesn't match!");
12363
12364 /* Write final flag... */
12365 int final = 999;
12366 FWRITE(&final, int,
12367 1,
12368 out);
12369
12370 /* Close file... */
12371 fclose(out);
12372}
12373
12374/*****************************************************************************/
12375
12377 FILE *out,
12378 met_t *met,
12379 float var[EX][EY],
12380 const char *varname) {
12381
12382 float *help;
12383
12384 /* Allocate... */
12385 ALLOC(help, float,
12386 EX * EY);
12387
12388 /* Copy data... */
12389 for (int ix = 0; ix < met->nx; ix++)
12390 for (int iy = 0; iy < met->ny; iy++)
12391 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
12392
12393 /* Write uncompressed data... */
12394 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
12395 FWRITE(help, float,
12396 (size_t) (met->nx * met->ny),
12397 out);
12398
12399 /* Free... */
12400 free(help);
12401}
12402
12403/*****************************************************************************/
12404
12406 FILE *out,
12407 const ctl_t *ctl,
12408 met_t *met,
12409 float var[EX][EY][EP],
12410 const char *varname,
12411 const int precision,
12412 const double tolerance) {
12413
12414 float *help;
12415
12416 /* Allocate... */
12417 ALLOC(help, float,
12418 EX * EY * EP);
12419
12420 /* Copy data... */
12421#pragma omp parallel for default(shared) collapse(2)
12422 for (int ix = 0; ix < met->nx; ix++)
12423 for (int iy = 0; iy < met->ny; iy++)
12424 for (int ip = 0; ip < met->np; ip++)
12425 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
12426
12427 /* Write uncompressed data... */
12428 if (ctl->met_type == 1) {
12429 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
12430 FWRITE(help, float,
12431 (size_t) (met->nx * met->ny * met->np),
12432 out);
12433 }
12434
12435 /* Write packed data... */
12436 else if (ctl->met_type == 2)
12437 compress_pck(varname, help, (size_t) (met->ny * met->nx),
12438 (size_t) met->np, 0, out);
12439
12440 /* Write ZFP data... */
12441#ifdef ZFP
12442 else if (ctl->met_type == 3) {
12443 FWRITE(&precision, int,
12444 1,
12445 out);
12446 FWRITE(&tolerance, double,
12447 1,
12448 out);
12449 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
12450 tolerance, 0, out);
12451 }
12452#endif
12453
12454 /* Write zstd data... */
12455#ifdef ZSTD
12456 else if (ctl->met_type == 4)
12457 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
12458 ctl->met_zstd_level, out);
12459#endif
12460
12461 /* Write cmultiscale data... */
12462#ifdef CMS
12463 else if (ctl->met_type == 5) {
12464 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
12465 (size_t) met->np, met->p, 0, out);
12466 }
12467#endif
12468
12469 /* Write SZ3 data... */
12470#ifdef SZ3
12471 else if (ctl->met_type == 7) {
12472 FWRITE(&precision, int,
12473 1,
12474 out);
12475 FWRITE(&tolerance, double,
12476 1,
12477 out);
12478 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
12479 tolerance, 0, out);
12480 }
12481#endif
12482
12483 /* Unknown method... */
12484 else {
12485 ERRMSG("MET_TYPE not supported!");
12486
12487 /* This will never execute, hack to avoid compilation error... */
12488 LOG(3, "%d %g", precision, tolerance);
12489 }
12490
12491 /* Free... */
12492 free(help);
12493}
12494
12495/*****************************************************************************/
12496
12498 const char *filename,
12499 const ctl_t *ctl,
12500 met_t *met) {
12501
12502 /* Create file... */
12503 int ncid, varid;
12504 size_t start[4], count[4];
12505 NC(nc_create(filename, NC_NETCDF4, &ncid));
12506
12507 /* Define dimensions... */
12508 int tid, lonid, latid, levid;
12509 NC(nc_def_dim(ncid, "time", 1, &tid));
12510 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
12511 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
12512 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
12513
12514 /* Define grid... */
12515 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
12516 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12517 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
12518 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
12519 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
12520
12521 /* Define surface variables... */
12522 int dimid2[2] = { latid, lonid };
12523 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
12524 ctl->met_nc_level, 0);
12525 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
12526 ctl->met_nc_level, 0);
12527 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
12528 ctl->met_nc_level, 0);
12529 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
12530 "m s**-1", ctl->met_nc_level, 0);
12531 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
12532 "m s**-1", ctl->met_nc_level, 0);
12533 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
12534 "Instantaneous eastward turbulent surface stress", "N m**-2",
12535 ctl->met_nc_level, 0);
12536 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
12537 "Instantaneous northward turbulent surface stress", "N m**-2",
12538 ctl->met_nc_level, 0);
12539 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
12540 "Instantaneous surface sensible heat flux", "W m**-1",
12541 ctl->met_nc_level, 0);
12542 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
12543 ctl->met_nc_level, 0);
12544 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
12545 ctl->met_nc_level, 0);
12546 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
12547 ctl->met_nc_level, 0);
12548 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
12549 ctl->met_nc_level, 0);
12550 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
12551 ctl->met_nc_level, 0);
12552 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
12553 ctl->met_nc_level, 0);
12554 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
12555 ctl->met_nc_level, 0);
12556 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
12557 ctl->met_nc_level, 0);
12558 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
12559 ctl->met_nc_level, 0);
12560 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water",
12561 "kg m**2", ctl->met_nc_level, 0);
12562 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
12563 "Pressure at lifted condensation level (LCL)", "Pa",
12564 ctl->met_nc_level, 0);
12565 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
12566 "Pressure at level of free convection (LFC)", "Pa",
12567 ctl->met_nc_level, 0);
12568 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2,
12569 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
12570 0);
12571 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
12572 "Convective available potential energy", "J kg**-1",
12573 ctl->met_nc_level, 0);
12574 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition",
12575 "J kg**-1", ctl->met_nc_level, 0);
12576 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
12577 ctl->met_nc_level, 0);
12578
12579 /* Define level data... */
12580 int dimid3[3] = { levid, latid, lonid };
12581 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
12582 ctl->met_nc_level, ctl->met_nc_quant);
12583 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
12584 ctl->met_nc_level, ctl->met_nc_quant);
12585 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
12586 ctl->met_nc_level, ctl->met_nc_quant);
12587 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
12588 ctl->met_nc_level, ctl->met_nc_quant);
12589 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
12590 ctl->met_nc_level, ctl->met_nc_quant);
12591 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
12592 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12593 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
12594 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12595 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
12596 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12597 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
12598 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12599 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
12600 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12601 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
12602 ctl->met_nc_level, ctl->met_nc_quant);
12603
12604 /* End definitions... */
12605 NC(nc_enddef(ncid));
12606
12607 /* Write grid data... */
12608 NC_PUT_DOUBLE("time", &met->time, 0);
12609 NC_PUT_DOUBLE("lon", met->lon, 0);
12610 NC_PUT_DOUBLE("lat", met->lat, 0);
12611 double phelp[EP];
12612 for (int ip = 0; ip < met->np; ip++)
12613 phelp[ip] = 100. * met->p[ip];
12614 NC_PUT_DOUBLE("lev", phelp, 0);
12615
12616 /* Write surface data... */
12617 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
12618 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
12619 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
12620 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
12621 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
12622 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
12623 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
12624 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
12625 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
12626 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
12627 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
12628 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
12629 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
12630 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
12631 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
12632 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
12633 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
12634 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
12635 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
12636 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
12637 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
12638 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
12639 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
12640 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
12641
12642 /* Write level data... */
12643 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
12644 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
12645 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
12646 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
12647 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
12648 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
12649 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
12650 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
12651 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
12652 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
12653 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
12654
12655 /* Close file... */
12656 NC(nc_close(ncid));
12657}
12658
12659/*****************************************************************************/
12660
12662 const int ncid,
12663 const char *varname,
12664 met_t *met,
12665 float var[EX][EY],
12666 const float scl) {
12667
12668 int varid;
12669 size_t start[4], count[4];
12670
12671 /* Allocate... */
12672 float *help;
12673 ALLOC(help, float,
12674 EX * EY);
12675
12676 /* Copy data... */
12677 for (int ix = 0; ix < met->nx; ix++)
12678 for (int iy = 0; iy < met->ny; iy++)
12679 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
12680
12681 /* Write data... */
12682 NC_PUT_FLOAT(varname, help, 0);
12683
12684 /* Free... */
12685 free(help);
12686}
12687
12688/*****************************************************************************/
12689
12691 const int ncid,
12692 const char *varname,
12693 met_t *met,
12694 float var[EX][EY][EP],
12695 const float scl) {
12696
12697 int varid;
12698 size_t start[4], count[4];
12699
12700 /* Allocate... */
12701 float *help;
12702 ALLOC(help, float,
12703 EX * EY * EP);
12704
12705 /* Copy data... */
12706 for (int ix = 0; ix < met->nx; ix++)
12707 for (int iy = 0; iy < met->ny; iy++)
12708 for (int ip = 0; ip < met->np; ip++)
12709 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
12710
12711 /* Write data... */
12712 NC_PUT_FLOAT(varname, help, 0);
12713
12714 /* Free... */
12715 free(help);
12716}
12717
12718/*****************************************************************************/
12719
12721 const char *filename,
12722 const ctl_t *ctl,
12723 met_t *met0,
12724 met_t *met1,
12725 const atm_t *atm,
12726 const double t) {
12727
12728 static FILE *out;
12729
12730 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
12731 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
12732
12733 static int nobs, *obscount, ip, okay;
12734
12735 /* Set timer... */
12736 SELECT_TIMER("WRITE_PROF", "OUTPUT");
12737
12738 /* Init... */
12739 if (t == ctl->t_start) {
12740
12741 /* Check quantity index for mass... */
12742 if (ctl->qnt_m < 0)
12743 ERRMSG("Need quantity mass!");
12744
12745 /* Check molar mass... */
12746 if (ctl->molmass <= 0)
12747 ERRMSG("Specify molar mass!");
12748
12749 /* Allocate... */
12750 ALLOC(lon, double,
12751 ctl->prof_nx);
12752 ALLOC(lat, double,
12753 ctl->prof_ny);
12754 ALLOC(area, double,
12755 ctl->prof_ny);
12756 ALLOC(z, double,
12757 ctl->prof_nz);
12758 ALLOC(press, double,
12759 ctl->prof_nz);
12760 ALLOC(rt, double,
12761 NOBS);
12762 ALLOC(rz, double,
12763 NOBS);
12764 ALLOC(rlon, double,
12765 NOBS);
12766 ALLOC(rlat, double,
12767 NOBS);
12768 ALLOC(robs, double,
12769 NOBS);
12770
12771 /* Read observation data... */
12772 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12773
12774 /* Create new output file... */
12775 LOG(1, "Write profile data: %s", filename);
12776 if (!(out = fopen(filename, "w")))
12777 ERRMSG("Cannot create file!");
12778
12779 /* Write header... */
12780 fprintf(out,
12781 "# $1 = time [s]\n"
12782 "# $2 = altitude [km]\n"
12783 "# $3 = longitude [deg]\n"
12784 "# $4 = latitude [deg]\n"
12785 "# $5 = pressure [hPa]\n"
12786 "# $6 = temperature [K]\n"
12787 "# $7 = volume mixing ratio [ppv]\n"
12788 "# $8 = H2O volume mixing ratio [ppv]\n"
12789 "# $9 = O3 volume mixing ratio [ppv]\n"
12790 "# $10 = observed BT index [K]\n"
12791 "# $11 = number of observations\n");
12792
12793 /* Set grid box size... */
12794 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
12795 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
12796 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
12797
12798 /* Set vertical coordinates... */
12799 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12800 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
12801 press[iz] = P(z[iz]);
12802 }
12803
12804 /* Set horizontal coordinates... */
12805 for (int ix = 0; ix < ctl->prof_nx; ix++)
12806 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
12807 for (int iy = 0; iy < ctl->prof_ny; iy++) {
12808 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
12809 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
12810 }
12811 }
12812
12813 /* Set time interval... */
12814 const double t0 = t - 0.5 * ctl->dt_mod;
12815 const double t1 = t + 0.5 * ctl->dt_mod;
12816
12817 /* Allocate... */
12818 ALLOC(mass, double,
12819 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
12820 ALLOC(obsmean, double,
12821 ctl->prof_nx * ctl->prof_ny);
12822 ALLOC(obscount, int,
12823 ctl->prof_nx * ctl->prof_ny);
12824
12825 /* Loop over observations... */
12826 for (int i = 0; i < nobs; i++) {
12827
12828 /* Check time... */
12829 if (rt[i] < t0)
12830 continue;
12831 else if (rt[i] >= t1)
12832 break;
12833
12834 /* Check observation data... */
12835 if (!isfinite(robs[i]))
12836 continue;
12837
12838 /* Calculate indices... */
12839 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
12840 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
12841
12842 /* Check indices... */
12843 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
12844 continue;
12845
12846 /* Get mean observation index... */
12847 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
12848 obsmean[idx] += robs[i];
12849 obscount[idx]++;
12850 }
12851
12852 /* Analyze model data... */
12853 for (ip = 0; ip < atm->np; ip++) {
12854
12855 /* Check time... */
12856 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12857 continue;
12858
12859 /* Get indices... */
12860 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
12861 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
12862 const int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
12863
12864 /* Check indices... */
12865 if (ix < 0 || ix >= ctl->prof_nx ||
12866 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
12867 continue;
12868
12869 /* Get total mass in grid cell... */
12870 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12871 mass[idx] += atm->q[ctl->qnt_m][ip];
12872 }
12873
12874 /* Extract profiles... */
12875 for (int ix = 0; ix < ctl->prof_nx; ix++)
12876 for (int iy = 0; iy < ctl->prof_ny; iy++) {
12877 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
12878 if (obscount[idx2] > 0) {
12879
12880 /* Check profile... */
12881 okay = 0;
12882 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12883 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12884 if (mass[idx3] > 0) {
12885 okay = 1;
12886 break;
12887 }
12888 }
12889 if (!okay)
12890 continue;
12891
12892 /* Write output... */
12893 fprintf(out, "\n");
12894
12895 /* Loop over altitudes... */
12896 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12897
12898 /* Get temperature, water vapor, and ozone... */
12900 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
12901 lon[ix], lat[iy], &temp, ci, cw, 1);
12902 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
12903 lon[ix], lat[iy], &h2o, ci, cw, 0);
12904 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
12905 lon[ix], lat[iy], &o3, ci, cw, 0);
12906
12907 /* Calculate volume mixing ratio... */
12908 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12909 vmr = MA / ctl->molmass * mass[idx3]
12910 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
12911
12912 /* Write output... */
12913 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
12914 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
12915 obsmean[idx2] / obscount[idx2], obscount[idx2]);
12916 }
12917 }
12918 }
12919
12920 /* Free... */
12921 free(mass);
12922 free(obsmean);
12923 free(obscount);
12924
12925 /* Finalize... */
12926 if (t == ctl->t_stop) {
12927
12928 /* Close output file... */
12929 fclose(out);
12930
12931 /* Free... */
12932 free(lon);
12933 free(lat);
12934 free(area);
12935 free(z);
12936 free(press);
12937 free(rt);
12938 free(rz);
12939 free(rlon);
12940 free(rlat);
12941 free(robs);
12942 }
12943}
12944
12945/*****************************************************************************/
12946
12948 const char *filename,
12949 const ctl_t *ctl,
12950 met_t *met0,
12951 met_t *met1,
12952 const atm_t *atm,
12953 const double t) {
12954
12955 static FILE *out;
12956
12957 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
12958 kw[EP];
12959
12960 static int nobs, nk;
12961
12962 /* Set timer... */
12963 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT");
12964
12965 /* Init... */
12966 if (t == ctl->t_start) {
12967
12968 /* Allocate... */
12969 ALLOC(rt, double,
12970 NOBS);
12971 ALLOC(rz, double,
12972 NOBS);
12973 ALLOC(rlon, double,
12974 NOBS);
12975 ALLOC(rlat, double,
12976 NOBS);
12977 ALLOC(robs, double,
12978 NOBS);
12979
12980 /* Read observation data... */
12981 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12982
12983 /* Read kernel data... */
12984 if (ctl->sample_kernel[0] != '-')
12985 read_kernel(ctl->sample_kernel, kz, kw, &nk);
12986
12987 /* Create output file... */
12988 LOG(1, "Write sample data: %s", filename);
12989 if (!(out = fopen(filename, "w")))
12990 ERRMSG("Cannot create file!");
12991
12992 /* Write header... */
12993 fprintf(out,
12994 "# $1 = time [s]\n"
12995 "# $2 = altitude [km]\n"
12996 "# $3 = longitude [deg]\n"
12997 "# $4 = latitude [deg]\n"
12998 "# $5 = surface area [km^2]\n"
12999 "# $6 = layer depth [km]\n"
13000 "# $7 = number of particles [1]\n"
13001 "# $8 = column density [kg/m^2]\n"
13002 "# $9 = volume mixing ratio [ppv]\n"
13003 "# $10 = observed BT index [K]\n\n");
13004
13005 /* Set latitude range, squared radius, and area... */
13006 dlat = DY2DEG(ctl->sample_dx);
13007 rmax2 = SQR(ctl->sample_dx);
13008 area = M_PI * rmax2;
13009 }
13010
13011 /* Set time interval for output... */
13012 const double t0 = t - 0.5 * ctl->dt_mod;
13013 const double t1 = t + 0.5 * ctl->dt_mod;
13014
13015 /* Loop over observations... */
13016 for (int i = 0; i < nobs; i++) {
13017
13018 /* Check time... */
13019 if (rt[i] < t0)
13020 continue;
13021 else if (rt[i] >= t1)
13022 break;
13023
13024 /* Calculate Cartesian coordinates... */
13025 double x0[3];
13026 geo2cart(0, rlon[i], rlat[i], x0);
13027
13028 /* Set pressure range... */
13029 const double rp = P(rz[i]);
13030 const double ptop = P(rz[i] + ctl->sample_dz);
13031 const double pbot = P(rz[i] - ctl->sample_dz);
13032
13033 /* Init... */
13034 double mass = 0;
13035 int np = 0;
13036
13037 /* Loop over air parcels... */
13038 //#pragma omp parallel for default(shared) reduction(+:mass,np)
13039 for (int ip = 0; ip < atm->np; ip++) {
13040
13041 /* Check time... */
13042 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13043 continue;
13044
13045 /* Check latitude... */
13046 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
13047 continue;
13048
13049 /* Check horizontal distance... */
13050 double x1[3];
13051 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13052 if (DIST2(x0, x1) > rmax2)
13053 continue;
13054
13055 /* Check pressure... */
13056 if (ctl->sample_dz > 0)
13057 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
13058 continue;
13059
13060 /* Add mass... */
13061 if (ctl->qnt_m >= 0)
13062 mass +=
13063 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13064 np++;
13065 }
13066
13067 /* Calculate column density... */
13068 const double cd = mass / (1e6 * area);
13069
13070 /* Calculate volume mixing ratio... */
13071 double vmr = 0;
13072 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
13073 if (mass > 0) {
13074
13075 /* Get temperature... */
13076 double temp;
13078 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
13079 rlon[i], rlat[i], &temp, ci, cw, 1);
13080
13081 /* Calculate volume mixing ratio... */
13082 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
13083 }
13084 } else
13085 vmr = NAN;
13086
13087 /* Write output... */
13088 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
13089 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
13090 }
13091
13092 /* Finalize...... */
13093 if (t == ctl->t_stop) {
13094
13095 /* Close output file... */
13096 fclose(out);
13097
13098 /* Free... */
13099 free(rt);
13100 free(rz);
13101 free(rlon);
13102 free(rlat);
13103 free(robs);
13104 }
13105}
13106
13107/*****************************************************************************/
13108
13110 const char *filename,
13111 const ctl_t *ctl,
13112 atm_t *atm,
13113 const double t) {
13114
13115 static FILE *out;
13116
13117 static double rmax2, x0[3], x1[3];
13118
13119 /* Set timer... */
13120 SELECT_TIMER("WRITE_STATION", "OUTPUT");
13121
13122 /* Init... */
13123 if (t == ctl->t_start) {
13124
13125 /* Write info... */
13126 LOG(1, "Write station data: %s", filename);
13127
13128 /* Create new file... */
13129 if (!(out = fopen(filename, "w")))
13130 ERRMSG("Cannot create file!");
13131
13132 /* Write header... */
13133 fprintf(out,
13134 "# $1 = time [s]\n"
13135 "# $2 = altitude [km]\n"
13136 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13137 for (int iq = 0; iq < ctl->nq; iq++)
13138 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
13139 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13140 fprintf(out, "\n");
13141
13142 /* Set geolocation and search radius... */
13143 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
13144 rmax2 = SQR(ctl->stat_r);
13145 }
13146
13147 /* Set time interval for output... */
13148 const double t0 = t - 0.5 * ctl->dt_mod;
13149 const double t1 = t + 0.5 * ctl->dt_mod;
13150
13151 /* Loop over air parcels... */
13152 for (int ip = 0; ip < atm->np; ip++) {
13153
13154 /* Check time... */
13155 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13156 continue;
13157
13158 /* Check time range for station output... */
13159 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
13160 continue;
13161
13162 /* Check station flag... */
13163 if (ctl->qnt_stat >= 0)
13164 if ((int) atm->q[ctl->qnt_stat][ip])
13165 continue;
13166
13167 /* Get Cartesian coordinates... */
13168 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13169
13170 /* Check horizontal distance... */
13171 if (DIST2(x0, x1) > rmax2)
13172 continue;
13173
13174 /* Set station flag... */
13175 if (ctl->qnt_stat >= 0)
13176 atm->q[ctl->qnt_stat][ip] = 1;
13177
13178 /* Write data... */
13179 fprintf(out, "%.2f %g %g %g",
13180 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
13181 for (int iq = 0; iq < ctl->nq; iq++) {
13182 fprintf(out, " ");
13183 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
13184 }
13185 fprintf(out, "\n");
13186 }
13187
13188 /* Close file... */
13189 if (t == ctl->t_stop)
13190 fclose(out);
13191}
13192
13193/*****************************************************************************/
13194
13196 const char *filename,
13197 const ctl_t *ctl,
13198 const atm_t *atm,
13199 const double t) {
13200
13201 FILE *out;
13202
13203 /* Set timer... */
13204 SELECT_TIMER("WRITE_VTK", "OUTPUT");
13205
13206 /* Write info... */
13207 LOG(1, "Write VTK data: %s", filename);
13208
13209 /* Set time interval for output... */
13210 const double t0 = t - 0.5 * ctl->dt_mod;
13211 const double t1 = t + 0.5 * ctl->dt_mod;
13212
13213 /* Create file... */
13214 if (!(out = fopen(filename, "w")))
13215 ERRMSG("Cannot create file!");
13216
13217 /* Count data points... */
13218 int np = 0;
13219 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13220 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13221 continue;
13222 np++;
13223 }
13224
13225 /* Write header... */
13226 fprintf(out,
13227 "# vtk DataFile Version 3.0\n"
13228 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
13229
13230 /* Write point coordinates... */
13231 fprintf(out, "POINTS %d float\n", np);
13232 if (ctl->vtk_sphere) {
13233 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13234 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13235 continue;
13236 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
13237 + ctl->vtk_offset) / RE;
13238 const double coslat = cos(DEG2RAD(atm->lat[ip]));
13239 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
13240 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
13241 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
13242 fprintf(out, "%g %g %g\n", x, y, z);
13243 }
13244 } else
13245 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13246 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13247 continue;
13248 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
13249 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
13250 }
13251
13252 /* Write point data... */
13253 fprintf(out, "POINT_DATA %d\n", np);
13254 for (int iq = 0; iq < ctl->nq; iq++) {
13255 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
13256 ctl->qnt_name[iq]);
13257 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13258 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13259 continue;
13260 fprintf(out, "%g\n", atm->q[iq][ip]);
13261 }
13262 }
13263
13264 /* Close file... */
13265 fclose(out);
13266}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:7870
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:4887
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:6526
void day2doy(const int year, const int mon, const int day, int *doy)
Get day of year from date.
Definition: mptrac.c:1052
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:7830
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:11260
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:8500
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:12661
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:10299
void write_met_bin_3d(FILE *out, const ctl_t *ctl, met_t *met, float var[EX][EY][EP], const char *varname, const int precision, const double tolerance)
Writes a 3-dimensional meteorological variable to a binary file.
Definition: mptrac.c:12405
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:10644
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:2627
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:4603
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:3852
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:6958
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:7669
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:3238
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:10817
double cos_sza(const double sec, const double lon, const double lat)
Calculates the cosine of the solar zenith angle.
Definition: mptrac.c:1011
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:2083
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:8822
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:6925
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:9907
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:7726
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:10472
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:10688
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:3075
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:2588
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:8303
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:9606
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:7077
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:10044
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:6260
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:4650
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:11742
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:3959
double clim_zm(const clim_zm_t *zm, const double t, const double lat, const double p)
Interpolates monthly mean zonal mean climatological variables.
Definition: mptrac.c:405
void module_mixing_help(const ctl_t *ctl, const clim_t *clim, atm_t *atm, const int *ixs, const int *iys, const int *izs, const int qnt_idx, const int use_ensemble)
Perform subgrid-scale interparcel mixing of a given quantity.
Definition: mptrac.c:4031
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:7049
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:9564
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:204
void read_obs_nc(const char *filename, double *rt, double *rz, double *rlon, double *rlat, double *robs, int *nobs)
Reads observation data from a NetCDF file.
Definition: mptrac.c:10716
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:7419
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:2524
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:3676
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:2371
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:12030
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:6414
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:10918
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:5098
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:2141
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:1692
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:1635
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:4752
void compress_pck(const char *varname, float *array, const size_t nxy, const size_t nz, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats.
Definition: mptrac.c:680
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:6721
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:10850
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:2913
double clim_photo(const double rate[CP][CSZA][CO3], const clim_photo_t *photo, const double p, const double sza, const double o3c)
Calculates the photolysis rate for a given set of atmospheric conditions.
Definition: mptrac.c:147
void read_clim_zm(const char *filename, const char *varname, clim_zm_t *zm)
Reads zonally averaged climatological data from a netCDF file and populates the given structure.
Definition: mptrac.c:7131
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:9731
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:4462
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:9691
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:10949
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:11075
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:2025
void module_sort(const ctl_t *ctl, const met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:4491
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:3117
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:7230
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:2817
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:10745
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:2790
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:4268
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:4976
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:4565
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:10897
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:2203
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:7448
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:2554
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:11017
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:12720
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:5188
double tropo_weight(const clim_t *clim, const atm_t *atm, const int ip)
Computes a weighting factor based on tropopause pressure.
Definition: mptrac.c:11052
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:12497
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:4326
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:5117
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:6470
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:6630
double clim_oh(const ctl_t *ctl, const clim_t *clim, const double t, const double lon, const double lat, const double p)
Calculates the hydroxyl radical (OH) concentration from climatology data, with an optional diurnal co...
Definition: mptrac.c:89
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:10270
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:8165
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:232
void module_rng(const ctl_t *ctl, double *rs, const size_t n, const int method)
Generate random numbers using various methods and distributions.
Definition: mptrac.c:4357
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:13109
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
void doy2day(const int year, const int doy, int *mon, int *day)
Converts a given day of the year (DOY) to a date (month and day).
Definition: mptrac.c:1605
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:1853
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:2170
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:4217
void clim_oh_diurnal_correction(const ctl_t *ctl, clim_t *clim)
Applies a diurnal correction to the hydroxyl radical (OH) concentration in climatology data.
Definition: mptrac.c:115
void locate_vert(float profiles[EX][EY][EP], const int np, const int lon_ap_ind, const int lat_ap_ind, const double height_ap, int *ind)
Locate the four vertical indizes of a box for a given height value.
Definition: mptrac.c:2607
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:12376
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:10164
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:6809
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:3277
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:387
void jsec2time(const double jsec, int *year, int *mon, int *day, int *hour, int *min, int *sec, double *remain)
Converts Julian seconds to calendar date and time components.
Definition: mptrac.c:2294
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:7271
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:11207
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:1759
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:3479
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:6865
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:6151
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:13195
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:4681
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:5248
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:4940
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:10105
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:3594
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:12134
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:6745
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:3354
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:12690
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:3746
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:4133
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:1674
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:7998
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:1783
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:2327
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:6767
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:1826
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:12947
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:11839
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:3531
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:12264
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:11157
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:7554
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:6586
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:2353
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:11467
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:11418
MPTRAC library declarations.
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1423
void dd_init(const ctl_t *ctl, dd_t *dd, atm_t *atm)
Initialize the domain decomposition infrastructure.
void compress_zstd(const char *varname, float *array, const size_t n, const int decompress, const int level, FILE *inout)
Compresses or decompresses a float array using Zstandard (ZSTD).
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:345
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:311
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1895
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:495
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1450
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:286
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:246
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:281
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:291
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:350
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:370
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:855
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1555
#define H0
Scale height [km].
Definition: mptrac.h:266
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1403
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1190
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:1028
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1204
#define SELECT_TIMER(id, group)
Select and start a timer with specific attributes.
Definition: mptrac.h:2176
#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:792
void compress_cms(const ctl_t *ctl, const char *varname, float *array, const size_t nx, const size_t ny, const size_t np, const double *plev, const int decompress, FILE *inout)
Compresses or decompresses a 3-D meteorological field using cmultiscale.
#define DOTP(a, b)
Calculate the dot product of two vectors.
Definition: mptrac.h:736
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:306
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:420
#define KARMAN
Karman's constant.
Definition: mptrac.h:276
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:870
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:1175
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2102
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1364
void compress_zfp(const char *varname, float *array, const int nx, const int ny, const int nz, const int precision, const double tolerance, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using the ZFP library.
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:340
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1720
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:901
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:375
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:380
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:476
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:1939
#define codes_handle
Placeholder when ECCODES is not available.
Definition: mptrac.h:237
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1480
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:271
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:261
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:395
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:360
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:835
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:651
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:587
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:335
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:256
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1528
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1820
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:316
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:1699
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:1796
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1870
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1970
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1849
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:688
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:2069
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:1989
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1632
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:974
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:453
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:1676
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:410
#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:769
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:604
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:296
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1733
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1572
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:355
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2146
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:884
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1602
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:1341
#define DD_EX_GLOB
Maximum number of longitudes of global meteo data.
Definition: mptrac.h:415
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:385
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:2032
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1233
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1771
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:520
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:365
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1263
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:330
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1504
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1657
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:390
void read_met_grib_grid(codes_handle **handles, int count_handles, met_t *met)
Reads global meteorological information from a grib file.
void compress_sz3(const char *varname, float *array, const int nx, const int ny, const int nz, const int precision, const double tolerance, const int decompress, FILE *inout)
Compresses or decompresses a 3-D float array using the SZ3 library.
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1317
#define ECC(cmd)
Execute an ECCODES command and check for errors.
Definition: mptrac.h:750
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:1047
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:720
#define NC_INQ_DIM(dimname, ptr, min, max, check)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1293
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:566
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:251
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:400
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:669
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1074
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:817
Air parcel data.
Definition: mptrac.h:3241
double time[NP]
Time [s].
Definition: mptrac.h:3247
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3256
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3253
int np
Number of air parcels.
Definition: mptrac.h:3244
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3259
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3250
Cache data structure.
Definition: mptrac.h:3296
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3317
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3305
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3308
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3302
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3314
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3311
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3299
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3328
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3334
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3343
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3364
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3340
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3358
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3361
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3355
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3349
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3370
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3373
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3352
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3367
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3346
int np
Number of pressure levels.
Definition: mptrac.h:3331
int no3c
Number of total ozone columns.
Definition: mptrac.h:3337
Climatological data.
Definition: mptrac.h:3436
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3478
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3454
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3466
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3457
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3439
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3484
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3472
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3475
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3469
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3448
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3463
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3442
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3460
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3451
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3445
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3481
Climatological data in the form of time series.
Definition: mptrac.h:3384
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3393
double time[CTS]
Time [s].
Definition: mptrac.h:3390
int ntime
Number of timesteps.
Definition: mptrac.h:3387
Climatological data in the form of zonal means.
Definition: mptrac.h:3404
double time[CT]
Time [s].
Definition: mptrac.h:3416
int np
Number of pressure levels.
Definition: mptrac.h:3413
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3422
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3425
int ntime
Number of timesteps.
Definition: mptrac.h:3407
int nlat
Number of latitudes.
Definition: mptrac.h:3410
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3419
Control parameters.
Definition: mptrac.h:2190
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3105
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2302
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3066
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3033
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2458
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2954
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2554
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2335
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3042
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2813
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2281
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2482
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3229
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:2994
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2876
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2900
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2209
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2221
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2491
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2230
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2314
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3036
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2323
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2852
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2801
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3057
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2290
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3183
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2861
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2712
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2873
double stat_r
Search radius around station [km].
Definition: mptrac.h:3189
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2948
int met_zstd_level
ZSTD compression level (from -5 to 22).
Definition: mptrac.h:2563
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3060
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3213
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2897
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2680
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2311
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2915
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2765
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2470
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2602
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2389
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3132
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3108
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2518
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2719
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2476
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2632
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2699
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2353
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2425
char species[LEN]
Species.
Definition: mptrac.h:2810
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3051
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3063
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2747
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2677
double met_comp_tol[METVAR]
Compression tolerance for SZ3 or ZFP.
Definition: mptrac.h:2569
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2305
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2756
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3093
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3111
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3007
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2774
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3123
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2236
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2380
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2605
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2332
int qnt_Acs137
Quantity array index for radioactive activity of Cs-137.
Definition: mptrac.h:2503
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3114
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2359
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2696
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3168
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2419
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2537
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2834
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2918
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2668
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3084
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2593
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2741
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2224
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2257
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2401
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2789
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3195
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3027
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2738
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3129
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3054
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2263
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2924
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3099
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2386
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2906
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2807
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2371
int radio_decay
Switch for radioactive decay module (0=off, 1=on).
Definition: mptrac.h:2942
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2665
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2638
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2233
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2729
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3135
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2716
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2795
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2239
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3138
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3030
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2674
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3039
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2635
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2909
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2753
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2617
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2620
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3081
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2596
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3141
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2296
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2780
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2690
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3147
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2218
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2687
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2227
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2705
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2864
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2428
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2356
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3048
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3192
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2927
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3220
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2837
int qnt_eta
Quantity array index for eta vertical coordinate.
Definition: mptrac.h:2413
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2822
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:2966
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2870
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2377
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3012
int met_cms_nd0x
cmultiscale number of cells of coarsest grid in x-direction.
Definition: mptrac.h:2578
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2656
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2936
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3024
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2975
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2254
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2245
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2455
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3201
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2524
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2771
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3171
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2347
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3078
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2551
int met_comp_prec[METVAR]
Compression precision for SZ3 or ZFP.
Definition: mptrac.h:2566
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2275
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2395
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2623
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2786
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2683
int met_dx
Stride for longitudes.
Definition: mptrac.h:2626
int qnt_destination
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2515
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2885
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2540
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2407
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2831
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2939
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2527
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2732
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2443
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2416
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2437
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2278
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3210
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2293
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2374
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2783
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2702
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2350
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2206
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2461
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2653
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2921
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2299
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3156
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2398
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2287
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3177
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2819
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3021
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3096
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2611
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2242
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2587
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3117
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2485
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2479
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2200
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:2991
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2888
int nens
Number of ensembles.
Definition: mptrac.h:3069
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2266
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2326
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2722
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3144
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2659
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2284
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3000
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2933
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2404
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2762
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3072
int qnt_Ai131
Quantity array index for radioactive activity of I-131.
Definition: mptrac.h:2506
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2945
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:2544
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3045
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2422
int qnt_Apb210
Quantity array index for radioactive activity of Pb-210.
Definition: mptrac.h:2497
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3186
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2464
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2963
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3120
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2488
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2449
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2644
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2759
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2534
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2798
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2590
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2894
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2338
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2410
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2777
int met_cms_nd0y
cmultiscale number of cells of coarsest grid in y-direction.
Definition: mptrac.h:2581
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2867
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2344
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2792
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2879
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2843
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2452
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2440
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3102
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2828
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2251
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3075
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3165
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3003
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2671
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2891
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:2997
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2855
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3162
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2572
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2981
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2641
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3150
int qnt_Axe133
Quantity array index for radioactive activity of Xe-133.
Definition: mptrac.h:2509
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2903
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2320
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2368
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2383
int qnt_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2512
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2662
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3159
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2341
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2984
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3153
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2614
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2560
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2930
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2473
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3018
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2972
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2912
int qnt_Abe7
Quantity array index for radioactive activity of Be-7.
Definition: mptrac.h:2500
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2846
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2608
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2575
int met_cms_maxlev
cmultiscale maximum refinement level.
Definition: mptrac.h:2584
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3090
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3198
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2978
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2269
int met_np
Number of target pressure levels.
Definition: mptrac.h:2647
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2215
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2557
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2858
int qnt_Arn222
Quantity array index for radioactive activity of Rn-222.
Definition: mptrac.h:2494
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2365
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3207
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2849
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2599
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2960
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2735
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2768
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2431
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev,...
Definition: mptrac.h:2726
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2362
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2467
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2260
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2882
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3015
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2825
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2969
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2392
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2248
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2957
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2951
int met_dy
Stride for latitudes.
Definition: mptrac.h:2629
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2446
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2750
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2804
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3223
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2212
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2693
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2308
double t_start
Start time of simulation [s].
Definition: mptrac.h:2521
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2203
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2650
int nq
Number of quantities.
Definition: mptrac.h:2197
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2816
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3174
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3204
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3180
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2744
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3126
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3226
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2272
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:2548
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2317
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2329
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3087
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2434
Domain decomposition data structure.
Definition: mptrac.h:3669
size_t halo_bnd_count[4]
Extent of the periodic boundary halo hyperslab.
Definition: mptrac.h:3701
int halo_offset_end
Offset of the periodic halo block at the end of the local x-array.
Definition: mptrac.h:3707
int nx_glob
Number of global longitudes.
Definition: mptrac.h:3676
size_t halo_bnd_start[4]
Start indices of the periodic boundary halo hyperslab.
Definition: mptrac.h:3698
double lon_glob[DD_EX_GLOB]
Longitudes of the global grid [deg].
Definition: mptrac.h:3682
double lat_glob[DD_EY_GLOB]
Latitudes of the global grid [deg].
Definition: mptrac.h:3685
int halo_offset_start
Offset of the periodic halo block at the beginning of the local x-array.
Definition: mptrac.h:3704
size_t subdomain_count[4]
Extent of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:3695
int ny_glob
Number of global latitudes.
Definition: mptrac.h:3679
size_t subdomain_start[4]
Start indices of the local subdomain hyperslab (including inner halos).
Definition: mptrac.h:3692
Meteo data structure.
Definition: mptrac.h:3495
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3573
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3561
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3633
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3603
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3660
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3624
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3597
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3618
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3579
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3522
int nx
Number of longitudes.
Definition: mptrac.h:3501
int ny
Number of latitudes.
Definition: mptrac.h:3504
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3555
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3534
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3630
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3543
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3654
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3651
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3540
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3627
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3642
int np
Number of pressure levels.
Definition: mptrac.h:3507
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3609
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3537
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3612
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3549
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3648
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3582
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3594
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3600
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3588
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3513
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3567
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3570
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3564
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3546
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3606
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3615
int npl
Number of model levels.
Definition: mptrac.h:3510
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3558
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3636
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3576
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3621
double eta[EP]
Model level eta values.
Definition: mptrac.h:3531
double time
Time [s].
Definition: mptrac.h:3498
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3585
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3552
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3645
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3591
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3525
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3516
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3639
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3528
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3657
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3519
Particle data.
Definition: mptrac.h:3270
double p
Pressure [hPa].
Definition: mptrac.h:3276
double lat
Latitude [deg].
Definition: mptrac.h:3282
double time
Time [s].
Definition: mptrac.h:3273
double lon
Longitude [deg].
Definition: mptrac.h:3279
double q[NQ]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3285