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 if ((precision > 0) == (tolerance > 0.0))
788 ERRMSG("Exactly one of precision or tolerance must be set for SZ3!");
789
790 size_t r1 = (size_t) nx, r2 = (size_t) ny, r3 = (size_t) nz,
791 outSize = 0, total_elems = r1 * r2 * r3;
792
793 unsigned char *bytes = NULL;
794
795 /* Read compressed stream and decompress array... */
796 if (decompress) {
797
798 size_t sz3size;
799 FREAD(&sz3size, size_t,
800 1,
801 inout);
802 ALLOC(bytes, char,
803 sz3size);
804 FREAD(bytes, unsigned char,
805 sz3size,
806 inout);
807
808 void *outData = SZ_decompress(SZ_FLOAT, bytes, sz3size, 0, 0, r3, r2, r1);
809 if (!outData)
810 ERRMSG("Decompression failed!");
811
812 memcpy(array, outData, total_elems * sizeof(float));
813
814 free(outData);
815 free(bytes);
816
817 LOG(2, "Read 3-D variable: %s (SZ3, PREC=%d, TOL=%g, RATIO=%g)",
818 varname, precision, tolerance,
819 (double) (total_elems * sizeof(float)) / (double) sz3size);
820 }
821
822 /* Compress array and output compressed stream... */
823 else {
824
825 const int errBoundMode = (precision > 0) ? REL : ABS;
826 const double absBound = (errBoundMode == ABS) ? tolerance : 0.0;
827 const double relBound =
828 (errBoundMode == REL) ? pow(2.0, -(double) precision) : 0.0;
829
830 bytes = SZ_compress_args(SZ_FLOAT, array, &outSize,
831 errBoundMode, absBound, relBound, 0.0,
832 0, 0, r3, r2, r1);
833 if (!bytes || outSize == 0)
834 ERRMSG("Compression failed!");
835
836 FWRITE(&outSize, size_t,
837 1,
838 inout);
839 FWRITE(bytes, unsigned char,
840 outSize,
841 inout);
842
843 free(bytes);
844
845 LOG(2, "Write 3-D variable: %s (SZ3, PREC=%d, TOL=%g, RATIO=%g)",
846 varname, precision, tolerance,
847 (double) (total_elems * sizeof(float)) / (double) outSize);
848 }
849}
850#endif
851
852/*****************************************************************************/
853
854#ifdef ZFP
855void compress_zfp(
856 const char *varname,
857 float *array,
858 const int nx,
859 const int ny,
860 const int nz,
861 const int precision,
862 const double tolerance,
863 const int decompress,
864 FILE *inout) {
865
866 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
867 const size_t snx = (size_t) nx;
868 const size_t sny = (size_t) ny;
869 const size_t snz = (size_t) nz;
870 const zfp_type type = zfp_type_float;
871 zfp_field *field = zfp_field_3d(array, type, snx, sny, snz);
872
873 /* Allocate meta data for a compressed stream... */
874 zfp_stream *zfp = zfp_stream_open(NULL);
875 if (!field || !zfp)
876 ERRMSG("Failed to allocate zfp structures!");
877
878 /* Set compression mode... */
879 int actual_prec = 0;
880 double actual_tol = 0;
881 if ((precision > 0 && tolerance > 0) || (precision <= 0 && tolerance <= 0)) {
882 ERRMSG("Exactly one of precision or tolerance must be set for zfp!");
883 } else if (precision > 0)
884 actual_prec =
885 (int) zfp_stream_set_precision(zfp, (unsigned int) precision);
886 else if (tolerance > 0)
887 actual_tol = zfp_stream_set_accuracy(zfp, tolerance);
888
889 /* Allocate buffer for compressed data... */
890 const size_t bufsize = zfp_stream_maximum_size(zfp, field);
891 void *buffer;
892 ALLOC(buffer, char,
893 bufsize);
894
895 /* Associate bit stream with allocated buffer... */
896 bitstream *stream = stream_open(buffer, bufsize);
897 zfp_stream_set_bit_stream(zfp, stream);
898 zfp_stream_rewind(zfp);
899
900 /* Read compressed stream and decompress array... */
901 size_t zfpsize;
902 if (decompress) {
903 FREAD(&zfpsize, size_t,
904 1,
905 inout);
906 if (zfpsize > bufsize)
907 ERRMSG("Compressed data size exceeds allocated buffer!");
908 FREAD(buffer, unsigned char,
909 zfpsize,
910 inout);
911 if (!zfp_decompress(zfp, field)) {
912 ERRMSG("Decompression failed!");
913 }
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 atm_t *atm,
1074 ctl_t *ctl,
1075 dd_t *dd,
1076 int init) {
1077
1078 SELECT_TIMER("DD_ASSIGN_RECT_SUBDOMAINS", "DD");
1079
1080 if (init) {
1081#ifdef _OPENACC
1082#pragma acc enter data create(dd)
1083#pragma acc update device(dd->rank, dd->subdomain_lon_min, dd->subdomain_lon_max, dd->subdomain_lat_min, dd->subdomain_lat_max)
1084#pragma acc data present(atm, ctl, dd)
1085#pragma acc parallel loop independent gang vector
1086#endif
1087 for (int ip = 0; ip < atm->np; ip++) {
1088
1089 double lont = atm->lon[ip];
1090 if (lont < 0)
1091 lont += 360;
1092
1093 if (lont >= dd->subdomain_lon_min && lont < dd->subdomain_lon_max
1094 && atm->lat[ip] >= dd->subdomain_lat_min
1095 && atm->lat[ip] < dd->subdomain_lat_max) {
1096 atm->q[ctl->qnt_subdomain][ip] = dd->rank;
1097 atm->q[ctl->qnt_destination][ip] = dd->rank;
1098 } else {
1099 WARN
1100 ("DD: Particle is outside the domain (lon: %f, lat: %f, subdomain: %d, subdomain bounds: [%f, %f], [%f, %f])",
1101 atm->lon[ip], atm->lat[ip], dd->rank, dd->subdomain_lon_min,
1103 dd->subdomain_lat_max);
1104 atm->q[ctl->qnt_subdomain][ip] = -1;
1105 atm->q[ctl->qnt_destination][ip] = -1;
1106 }
1107 }
1108#ifdef _OPENACC
1109#pragma acc exit data delete(dd)
1110#endif
1111 } else {
1112
1113 /* Classify air parcels into subdomain... */
1114#ifdef _OPENACC
1115#pragma acc enter data create(dd)
1116#pragma acc update device(dd->neighbours[:DD_NNMAX], dd->rank, dd->size, dd->subdomain_lon_min, dd->subdomain_lon_max, dd->subdomain_lat_min, dd->subdomain_lat_max)
1117#pragma acc data present(atm, ctl, dd)
1118#pragma acc parallel loop independent gang vector
1119#endif
1120 for (int ip = 0; ip < atm->np; ip++) {
1121
1122 /* Skip empty places in the particle array... */
1123 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
1124 continue;
1125
1126 double lont = atm->lon[ip];
1127 double latt = atm->lat[ip];
1128
1129 double lon_max = dd->subdomain_lon_max;
1130 double lon_min = dd->subdomain_lon_min;
1131 double lat_max = dd->subdomain_lat_max;
1132 double lat_min = dd->subdomain_lat_min;
1133
1134 if (lont < 0)
1135 lont += 360;
1136
1137 int left = (dd->rank <= ctl->dd_subdomains_meridional - 1);
1138 int right = (dd->rank >= dd->size - ctl->dd_subdomains_meridional);
1139
1140 int bound = 0;
1141 if (left)
1142 bound = (lont - lon_max > 90) ? 1 : 0;
1143 if (right)
1144 bound = (lon_min - lont > 90) ? 1 : 0;
1145
1146 if (!bound) {
1147 if ((lont >= lon_max) && (latt >= lat_max)) {
1148
1149 // Upper right...
1150 atm->q[ctl->qnt_destination][ip] = dd->neighbours[5];
1151 LOG(4,
1152 "DD: Particle crossing to upper right: from rank %d to rank %d (lon: %f, lat: %f)",
1153 dd->rank, dd->neighbours[5], atm->lon[ip], atm->lat[ip]);
1154 } else if ((lont >= lon_max) && (latt <= lat_min)) {
1155
1156 // Lower right...
1157 atm->q[ctl->qnt_destination][ip] = dd->neighbours[4];
1158 LOG(4,
1159 "DD: Particle crossing to lower right: from rank %d to rank %d (lon: %f, lat: %f)",
1160 dd->rank, dd->neighbours[4], atm->lon[ip], atm->lat[ip]);
1161 } else if ((lont <= lon_min) && (latt >= lat_max)) {
1162
1163 // Upper left...
1164 atm->q[ctl->qnt_destination][ip] = dd->neighbours[2];
1165 LOG(4,
1166 "DD: Particle crossing to upper left: from rank %d to rank %d (lon: %f, lat: %f)",
1167 dd->rank, dd->neighbours[2], atm->lon[ip], atm->lat[ip]);
1168 } else if ((lont <= lon_min) && (latt <= lat_min)) {
1169
1170 // Lower left...
1171 atm->q[ctl->qnt_destination][ip] = dd->neighbours[1];
1172 LOG(4,
1173 "DD: Particle crossing to lower left: from rank %d to rank %d (lon: %f, lat: %f)",
1174 dd->rank, dd->neighbours[1], atm->lon[ip], atm->lat[ip]);
1175 } else if (lont >= lon_max) {
1176
1177 // Right...
1178 atm->q[ctl->qnt_destination][ip] = dd->neighbours[3];
1179 LOG(4,
1180 "DD: Particle crossing to right: from rank %d to rank %d (lon: %f, lat: %f)",
1181 dd->rank, dd->neighbours[3], atm->lon[ip], atm->lat[ip]);
1182 } else if (lont <= lon_min) {
1183
1184 // Left...
1185 atm->q[ctl->qnt_destination][ip] = dd->neighbours[0];
1186 LOG(4,
1187 "DD: Particle crossing to left: from rank %d to rank %d (lon: %f, lat: %f)",
1188 dd->rank, dd->neighbours[0], atm->lon[ip], atm->lat[ip]);
1189 } else if (latt <= lat_min) {
1190
1191 // Down...
1192 atm->q[ctl->qnt_destination][ip] = dd->neighbours[7];
1193 LOG(4,
1194 "DD: Particle crossing downward: from rank %d to rank %d (lon: %f, lat: %f)",
1195 dd->rank, dd->neighbours[7], atm->lon[ip], atm->lat[ip]);
1196 } else if (latt >= lat_max) {
1197
1198 // Up...
1199 atm->q[ctl->qnt_destination][ip] = dd->neighbours[6];
1200 LOG(4,
1201 "DD: Particle crossing upward: from rank %d to rank %d (lon: %f, lat: %f)",
1202 dd->rank, dd->neighbours[6], atm->lon[ip], atm->lat[ip]);
1203 } else {
1204
1205 // Within...
1206 atm->q[ctl->qnt_destination][ip] = dd->rank;
1207 }
1208 } else {
1209 if ((lont >= lon_max) && (latt >= lat_max)) {
1210
1211 // Upper right...
1212 atm->q[ctl->qnt_destination][ip] = dd->neighbours[2];
1213 LOG(4,
1214 "DD: Particle crossing to upper left (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1215 dd->rank, dd->neighbours[2], atm->lon[ip], atm->lat[ip]);
1216 } else if ((lont >= lon_max) && (latt <= lat_min)) {
1217
1218 // Lower right...
1219 atm->q[ctl->qnt_destination][ip] = dd->neighbours[1];
1220 LOG(4,
1221 "DD: Particle crossing to lower left (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1222 dd->rank, dd->neighbours[1], atm->lon[ip], atm->lat[ip]);
1223 } else if ((lont <= lon_min) && (latt >= lat_max)) {
1224
1225 // Upper left...
1226 atm->q[ctl->qnt_destination][ip] = dd->neighbours[5];
1227 LOG(4,
1228 "DD: Particle crossing to upper right (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1229 dd->rank, dd->neighbours[5], atm->lon[ip], atm->lat[ip]);
1230 } else if ((lont <= lon_min) && (latt <= lat_min)) {
1231
1232 // Lower left...
1233 atm->q[ctl->qnt_destination][ip] = dd->neighbours[4];
1234 LOG(4,
1235 "DD: Particle crossing to lower right (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1236 dd->rank, dd->neighbours[4], atm->lon[ip], atm->lat[ip]);
1237 } else if (lont >= lon_max) {
1238
1239 // Right...
1240 atm->q[ctl->qnt_destination][ip] = dd->neighbours[0];
1241 LOG(4,
1242 "DD: Particle crossing to left (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1243 dd->rank, dd->neighbours[0], atm->lon[ip], atm->lat[ip]);
1244 } else if (lont <= lon_min) {
1245
1246 // Left...
1247 atm->q[ctl->qnt_destination][ip] = dd->neighbours[3];
1248 LOG(4,
1249 "DD: Particle crossing to right (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1250 dd->rank, dd->neighbours[3], atm->lon[ip], atm->lat[ip]);
1251 } else if (latt <= lat_min) {
1252
1253 // Down...
1254 atm->q[ctl->qnt_destination][ip] = dd->neighbours[7];
1255 LOG(4,
1256 "DD: Particle crossing downward (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1257 dd->rank, dd->neighbours[7], atm->lon[ip], atm->lat[ip]);
1258 } else if (latt >= lat_max) {
1259
1260 // Up...
1261 atm->q[ctl->qnt_destination][ip] = dd->neighbours[6];
1262 LOG(4,
1263 "DD: Particle crossing upward (bound case): from rank %d to rank %d (lon: %f, lat: %f)",
1264 dd->rank, dd->neighbours[6], atm->lon[ip], atm->lat[ip]);
1265 } else {
1266
1267 // Within...
1268 atm->q[ctl->qnt_destination][ip] = dd->rank;
1269 }
1270 }
1271 }
1272#ifdef _OPENACC
1273#pragma acc exit data delete(dd)
1274#endif
1275 }
1276}
1277#endif
1278
1279/*****************************************************************************/
1280
1281#ifdef DD
1282void dd_atm2particles(
1283 atm_t *atm,
1284 particle_t *particles,
1285 ctl_t *ctl,
1286 int *nparticles,
1287 cache_t *cache,
1288 int rank) {
1289
1290 SELECT_TIMER("DD_ATM2PARTICLES", "DD");
1291
1292 /* Select the particles that will be send... */
1293#ifdef _OPENACC
1294 int npart = *nparticles;
1295#pragma acc enter data create( nparticles, particles[:DD_NPART])
1296#pragma acc update device( nparticles)
1297#pragma acc parallel loop present( atm, ctl, particles, cache, nparticles)
1298#endif
1299 for (int ip = atm->np; ip < atm->np + *nparticles; ip++)
1300 if (((int) (atm->q[ctl->qnt_destination][ip]) != rank)
1301 && ((int) (atm->q[ctl->qnt_destination][ip]) >= 0)
1302 && ((int) atm->q[ctl->qnt_subdomain][ip] >= 0)) {
1303
1304 particles[ip - atm->np].time = atm->time[ip];
1305 particles[ip - atm->np].lon = atm->lon[ip];
1306 particles[ip - atm->np].lat = atm->lat[ip];
1307 particles[ip - atm->np].p = atm->p[ip];
1308 for (int iq = 0; iq < ctl->nq; iq++)
1309 particles[ip - atm->np].q[iq] = atm->q[iq][ip];
1310
1311 LOG(3,
1312 "DD: Particle being prepared for transfer: subdomain %d -> destination %d (lon: %f, lat: %f)",
1313 (int) atm->q[ctl->qnt_subdomain][ip],
1314 (int) atm->q[ctl->qnt_destination][ip], atm->lon[ip], atm->lat[ip]);
1315 atm->q[ctl->qnt_subdomain][ip] = -1;
1316 cache->dt[ip] = 0;
1317 }
1318#ifdef _OPENACC
1319#pragma acc update host( particles[:npart])
1320#pragma acc exit data delete( nparticles, particles)
1321#endif
1322}
1323#endif
1324
1325/*****************************************************************************/
1326
1327#ifdef DD
1329 double lon,
1330 double lat,
1331 met_t *met,
1332 ctl_t *ctl,
1333 int mpi_size,
1334 int nx_glob,
1335 int ny_glob) {
1336
1337 /* Wrap longitude to [0, 360)... */
1338 double wrapped_lon = lon;
1339 while (wrapped_lon < 0)
1340 wrapped_lon += 360;
1341 while (wrapped_lon >= 360)
1342 wrapped_lon -= 360;
1343
1344 /* Handle polar coordinates by wrapping latitude and adjusting longitude */
1345 double wrapped_lat = lat;
1346 if (lat > 90) {
1347
1348 /* North pole overflow: wrap latitude and flip longitude */
1349 wrapped_lat = 180 - lat;
1350 wrapped_lon = fmod(wrapped_lon + 180, 360);
1351 } else if (lat < -90) {
1352
1353 /* South pole overflow: wrap latitude and flip longitude */
1354 wrapped_lat = -180 - lat;
1355 wrapped_lon = fmod(wrapped_lon + 180, 360);
1356 }
1357
1358 /* Get global domain ranges... */
1359 double lon_range = 360.0;
1360 LOG(2, "nx_glob: %d", nx_glob);
1361 double lat_range = met->lat[ny_glob - 1] - met->lat[0];
1362 double global_lon_min = met->lon[0];
1363 double global_lat_min = met->lat[0];
1364
1365 /* Calculate subdomain indices... */
1366 int lon_idx =
1367 (int) ((wrapped_lon -
1368 global_lon_min) * ctl->dd_subdomains_zonal / lon_range);
1369 int lat_idx =
1370 (int) ((wrapped_lat -
1371 global_lat_min) * ctl->dd_subdomains_meridional / lat_range);
1372
1373 // print wrapped coords, ranges, mins and idxs for debugging
1374 printf
1375 ("DD: Input Lon: %f, Lat: %f | Wrapped Lon: %f, Lat: %f | Lon Range: %f, Lat Range: %f | Lon Min: %f, Lat Min: %f | Lon Idx: %d, Lat Idx: %d\n",
1376 lon, lat, wrapped_lon, wrapped_lat, lon_range, lat_range, global_lon_min,
1377 global_lat_min, lon_idx, lat_idx);
1378
1379 /* Clamp to valid ranges... */
1380 lon_idx =
1381 (lon_idx <
1382 0) ? 0 : ((lon_idx >=
1384 1 : lon_idx);
1385 lat_idx =
1386 (lat_idx <
1387 0) ? 0 : ((lat_idx >=
1388 ctl->dd_subdomains_meridional) ? ctl->
1389 dd_subdomains_meridional - 1 : lat_idx);
1390
1391 /* Calculate rank from indices */
1392 int target_rank = lon_idx * ctl->dd_subdomains_meridional + lat_idx;
1393
1394 /* Ensure rank is within valid range */
1395 if (target_rank >= mpi_size)
1396 target_rank = mpi_size - 1;
1397 if (target_rank < 0)
1398 target_rank = 0;
1399
1400 return target_rank;
1401}
1402#endif
1403
1404/*****************************************************************************/
1405
1406#ifdef DD
1408 particle_t *particles,
1409 int *nparticles,
1410 MPI_Datatype MPI_Particle,
1411 int *neighbours,
1412 int nneighbours,
1413 ctl_t ctl) {
1414
1415 /* Initialize the buffers... */
1416 int *nbs;
1417 int *nbr;
1418 ALLOC(nbs, int,
1419 nneighbours);
1420 ALLOC(nbr, int,
1421 nneighbours);
1422 particle_t *send_buffers[DD_NNMAX] = { NULL };
1423 particle_t *recieve_buffers[DD_NNMAX] = { NULL };
1424
1425 /* Get MPI rank... */
1426 int rank;
1427 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
1428
1429 /* Infos for MPI async... */
1430 MPI_Request *requests_snd_nbr =
1431 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1432 MPI_Request *requests_rcv_nbr =
1433 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1434 MPI_Request *requests_snd_part =
1435 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1436 MPI_Request *requests_rcv_part =
1437 (MPI_Request *) calloc((size_t) nneighbours, sizeof(MPI_Request));
1438 MPI_Status *states =
1439 (MPI_Status *) calloc((size_t) nneighbours, sizeof(MPI_Status));
1440
1441 /* Initialize with MPI_REQUEST_NULL */
1442 for (int i = 0; i < nneighbours; i++) {
1443 requests_snd_nbr[i] = MPI_REQUEST_NULL;
1444 requests_rcv_nbr[i] = MPI_REQUEST_NULL;
1445 requests_snd_part[i] = MPI_REQUEST_NULL;
1446 requests_rcv_part[i] = MPI_REQUEST_NULL;
1447 }
1448
1449 /* Sending... */
1450 for (int idest = 0; idest < nneighbours; idest++) {
1451
1452 /* Ignore poles... */
1453 if (neighbours[idest] < 0)
1454 continue;
1455
1456 SELECT_TIMER("DD_COUNT_NUMBER", "DD");
1457 /* Count number of particles in particle array that will be send... */
1458 int help_sum = 0;
1459 for (int ip = 0; ip < *nparticles; ip++)
1460 if ((int) particles[ip].q[ctl.qnt_destination] == neighbours[idest])
1461 help_sum++;
1462 nbs[idest] = help_sum;
1463
1464 if (help_sum > 0) {
1465 LOG(3, "DD: Rank %d sending %d particles to neighbour %d (rank %d)",
1466 rank, help_sum, idest, neighbours[idest]);
1467 }
1468
1469 SELECT_TIMER("DD_SEND_NUMBER", "DD");
1470 /* Send buffer sizes... */
1471 MPI_Isend(&nbs[idest], 1, MPI_INT,
1472 neighbours[idest], 0, MPI_COMM_WORLD, &requests_snd_nbr[idest]);
1473
1474 /* Don't send empty signals... */
1475 if (nbs[idest] == 0)
1476 continue;
1477
1478 SELECT_TIMER("DD_PREP_BUFFER", "DD");
1479 /* Allocate buffer for sending... */
1480 ALLOC(send_buffers[idest], particle_t, nbs[idest]);
1481
1482 /* Fill the send buffer in a sorted way... */
1483 int ibs = 0;
1484 for (int ip = 0; ip < *nparticles; ip++) {
1485 if ((int) particles[ip].q[ctl.qnt_destination] == neighbours[idest]) {
1486 memcpy(&send_buffers[idest][ibs], &particles[ip], sizeof(particle_t));
1487 ibs++;
1488 }
1489
1490 if (ibs == nbs[idest])
1491 break;
1492 }
1493
1494 SELECT_TIMER("DD_SEND_PARTICLES", "DD");
1495
1496 /* Send the buffer... */
1497 MPI_Isend(send_buffers[idest], nbs[idest], MPI_Particle,
1498 neighbours[idest], 1, MPI_COMM_WORLD,
1499 &requests_snd_part[idest]);
1500 }
1501
1502 SELECT_TIMER("DD_RECIEVE_NUMBERS", "DD");
1503
1504 /* Recieving... */
1505 for (int isourc = 0; isourc < nneighbours; isourc++) {
1506
1507 /* Ignore poles... */
1508 if (neighbours[isourc] < 0) {
1509 requests_rcv_nbr[isourc] = MPI_REQUEST_NULL;
1510 continue;
1511 }
1512
1513 /* Recieve buffer sizes... */
1514 MPI_Irecv(&nbr[isourc], 1, MPI_INT, neighbours[isourc], 0, MPI_COMM_WORLD,
1515 &requests_rcv_nbr[isourc]);
1516 }
1517
1518 /* Wait for all particle numbers to be recieved... */
1519 MPI_Waitall(nneighbours, requests_rcv_nbr, states);
1520
1521 SELECT_TIMER("DD_RECIEVE_PARTICLES", "DD");
1522 for (int isourc = 0; isourc < nneighbours; isourc++) {
1523
1524 /* Ignore poles, and neighbours without signal... */
1525 if ((neighbours[isourc] < 0) || (nbr[isourc] == 0)) {
1526 requests_rcv_part[isourc] = MPI_REQUEST_NULL;
1527 continue;
1528 }
1529
1530 /* Allocate buffer for recieving... */
1531 ALLOC(recieve_buffers[isourc], particle_t, nbr[isourc]);
1532
1533 /* Receive... */
1534 MPI_Irecv(recieve_buffers[isourc], nbr[isourc], MPI_Particle,
1535 neighbours[isourc], 1, MPI_COMM_WORLD,
1536 &requests_rcv_part[isourc]);
1537 }
1538
1539 /* Wait for all particles to be recieved... */
1540 MPI_Waitall(nneighbours, requests_rcv_part, states);
1541
1542 SELECT_TIMER("DD_EMPTY_BUFFER", "DD");
1543
1544 /* Start position for different buffer ranges... */
1545 int api = 0;
1546
1547 /* Putting buffer into particle array... */
1548 for (int isourc = 0; isourc < nneighbours; isourc++) {
1549
1550 /* Ignore poles... */
1551 if (neighbours[isourc] < 0)
1552 continue;
1553
1554 if (nbr[isourc] > 0) {
1555 LOG(3, "DD: Rank %d receiving %d particles from neighbour %d (rank %d)",
1556 rank, nbr[isourc], isourc, neighbours[isourc]);
1557 }
1558
1559 /* Getting particles from buffer... */
1560 for (int ip = 0; ip < nbr[isourc]; ip++) {
1561 memcpy(&particles[ip + api], &recieve_buffers[isourc][ip],
1562 sizeof(particle_t));
1563 particles[ip + api].q[ctl.qnt_destination] = rank;
1564 particles[ip + api].q[ctl.qnt_subdomain] = rank;
1565 }
1566 api += nbr[isourc];
1567 }
1568
1569 /* Set number of recieved particles... */
1570 *nparticles = api;
1571
1572 SELECT_TIMER("DD_FREE_BUFFER", "DD");
1573
1574 /* Wait for all communication to be finished... */
1575 MPI_Waitall(nneighbours, requests_snd_part, states);
1576 MPI_Waitall(nneighbours, requests_snd_nbr, states);
1577
1578 /* Free buffers and buffersizes... */
1579 for (int i = 0; i < nneighbours; i++) {
1580
1581 if ((send_buffers[i] != NULL) && (nbs[i] != 0)) {
1582 free(send_buffers[i]);
1583 send_buffers[i] = NULL;
1584 }
1585
1586 if ((recieve_buffers[i] != NULL) && (nbr[i] != 0)) {
1587 free(recieve_buffers[i]);
1588 recieve_buffers[i] = NULL;
1589 }
1590 }
1591
1592 free(nbs);
1593 free(nbr);
1594}
1595#endif
1596
1597/*****************************************************************************/
1598
1599#ifdef DD
1601 const ctl_t ctl,
1602 dd_t *dd) {
1603 SELECT_TIMER("DD_GET_RECT_NEIGHBOUR", "DD");
1604
1605 const int rank = dd->rank;
1606 const int size = dd->size;
1607 const int m = ctl.dd_subdomains_meridional;
1608 int *nb = dd->neighbours;
1609
1610 nb[0] = (size + rank - m) % size; // left
1611 nb[3] = (rank + m) % size; // right
1612 nb[1] = ((rank + 1) % m == 0) ? DD_SPOLE : (size + rank - m + 1) % size; // lower left
1613 nb[2] = (rank % m == 0) ? DD_NPOLE : (size + rank - m - 1) % size; // upper left
1614 nb[4] = ((rank + 1) % m == 0) ? DD_SPOLE : (rank + m + 1) % size; // lower right
1615 nb[5] = (rank % m == 0) ? DD_NPOLE : (rank + m - 1) % size; // upper right
1616 nb[6] = (rank % m == 0) ? DD_NPOLE : rank - 1; // upper
1617 nb[7] = ((rank + 1) % m == 0) ? DD_SPOLE : rank + 1; // lower
1618}
1619#endif
1620
1621/*****************************************************************************/
1622
1623#ifdef DD
1625 met_t *met,
1626 int nx_glob) {
1627
1628 /* Check if we have at least 2 longitude points... */
1629 if (nx_glob < 2)
1630 return 0;
1631
1632 /* Calculate the longitude spacing */
1633 double lon_spacing = met->lon[1] - met->lon[0];
1634
1635 /* Check if the total range plus one spacing equals 360 degrees
1636 This is the same logic as used in read_met_periodic() */
1637 double total_range = met->lon[nx_glob - 1] - met->lon[0] + lon_spacing;
1638
1639 /* Return 1 if periodic (global), 0 if not periodic (regional) */
1640 return (fabs(total_range - 360.0) < 0.01);
1641}
1642#endif
1643
1644/*****************************************************************************/
1645
1646#ifdef DD
1647int dd_init(
1648 ctl_t *ctl,
1649 dd_t *dd,
1650 atm_t *atm) {
1651
1652 /* Check if enough tasks are requested... */
1653 if (dd->size != ctl->dd_subdomains_meridional * ctl->dd_subdomains_zonal)
1654 ERRMSG("The number of tasks and subdomains is not identical.");
1655
1656 /* Register the MPI_Particle data type... */
1657 dd_register_MPI_type_particle(&dd->MPI_Particle);
1658
1659 /* Define grid neighbours ... */
1660 dd_get_rect_neighbour(*ctl, dd);
1661
1662 /* Check if particles are in subdomain... */
1663 dd_assign_rect_subdomains_atm(atm, ctl, dd, 1);
1664
1665 /* Set flag of initialization. */
1666 return 1;
1667}
1668#endif
1669
1670/*****************************************************************************/
1671
1672#ifdef DD
1673void dd_particles2atm(
1674 atm_t *atm,
1675 particle_t *particles,
1676 ctl_t *ctl,
1677 int *nparticles,
1678 cache_t *cache) {
1679
1680 SELECT_TIMER("DD_PARTICLES2ATM", "DD");
1681
1682#ifdef _OPENACC
1683 int npart = *nparticles;
1684#pragma acc enter data create(nparticles, particles[:DD_NPART])
1685#pragma acc update device(particles[:npart], nparticles)
1686#pragma acc data present(atm, ctl, cache, particles, nparticles)
1687#pragma acc parallel loop
1688#endif
1689 for (int ip = atm->np; ip < atm->np + *nparticles; ip++) {
1690 atm->time[ip] = particles[ip - atm->np].time;
1691 atm->lon[ip] = particles[ip - atm->np].lon;
1692 atm->lat[ip] = particles[ip - atm->np].lat;
1693 atm->p[ip] = particles[ip - atm->np].p;
1694 for (int iq = 0; iq < ctl->nq; iq++)
1695 atm->q[iq][ip] = particles[ip - atm->np].q[iq];
1696 cache->dt[ip] = ctl->dt_mod;
1697 }
1698#ifdef _OPENACC
1699#pragma acc exit data delete(nparticles, particles)
1700#endif
1701
1702 /* Reset size... */
1703 atm->np += *nparticles;
1704#ifdef _OPENACC
1705#pragma acc update device(atm->np)
1706#endif
1707 if (atm->np > NP)
1708 ERRMSG("Number of particles to high. Increase NP!");
1709}
1710#endif
1711
1712/*****************************************************************************/
1713
1714#ifdef DD
1716 MPI_Datatype *MPI_Particle) {
1717
1718 MPI_Datatype types[5] = { MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE,
1719 MPI_DOUBLE, MPI_DOUBLE
1720 };
1721
1722 int blocklengths[5] = { 1, 1, 1, 1, NQ };
1723
1724 MPI_Aint displacements[5] = { offsetof(particle_t, time),
1725 offsetof(particle_t, p),
1726 offsetof(particle_t, lon),
1727 offsetof(particle_t, lat),
1728 offsetof(particle_t, q)
1729 };
1730
1731 MPI_Type_create_struct(5, blocklengths, displacements, types, MPI_Particle);
1732 MPI_Type_commit(MPI_Particle);
1733}
1734#endif
1735
1736/*****************************************************************************/
1737
1738#ifdef DD
1739void dd_sort(
1740 const ctl_t *ctl,
1741 met_t *met0,
1742 atm_t *atm,
1743 dd_t *dd,
1744 int *nparticles,
1745 int *rank) {
1746
1747 /* Set timer... */
1748 SELECT_TIMER("DD_SORT", "DD");
1749
1750 /* Allocate... */
1751 const int np = atm->np;
1752 double amax = (met0->nx * met0->ny + met0->ny) * met0->np + met0->np;
1753#ifdef _OPENACC
1754#pragma acc enter data create(amax, rank)
1755#pragma acc update device(rank, amax)
1756#pragma acc data present(ctl,met0,atm,dd,amax,rank)
1757#endif
1758
1759 /* Get box index... */
1760#ifdef _OPENACC
1761#pragma acc parallel loop independent gang vector
1762#else
1763#pragma omp parallel for default(shared)
1764#endif
1765 for (int ip = 0; ip < np; ip++) {
1766 if ((int) atm->q[ctl->qnt_subdomain][ip] != -1) {
1767 if ((int) atm->q[ctl->qnt_destination][ip] == *rank)
1768 dd->a[ip] =
1769 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) *
1770 met0->ny + locate_irr(met0->lat, met0->ny, atm->lat[ip]))
1771 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
1772 else
1773 dd->a[ip] = amax + 1;
1774 } else {
1775 dd->a[ip] = amax + 2;
1776 }
1777 dd->p[ip] = ip;
1778 }
1779
1780 /* Sorting... */
1781#ifdef THRUST
1782#ifdef _OPENACC
1783#pragma acc host_data use_device(dd->a,dd->p)
1784#endif
1785 thrustSortWrapper(dd->a, np, dd->p);
1786#else
1787#ifdef _OPENACC
1788 ERRMSG("GSL sort fallback not available on GPU, use THRUST!");
1789#endif
1790 gsl_sort_index((size_t *) (dd->p), (dd->a), 1, (size_t) np);
1791#endif
1792
1793 /* Sort data... */
1794 dd_sort_help(atm->time, dd, np);
1795 dd_sort_help(atm->p, dd, np);
1796 dd_sort_help(atm->lon, dd, np);
1797 dd_sort_help(atm->lat, dd, np);
1798 for (int iq = 0; iq < ctl->nq; iq++)
1799 dd_sort_help(atm->q[iq], dd, np);
1800
1801 /* Reset the size... */
1802 int npt = 0;
1803#ifdef _OPENACC
1804#pragma acc parallel loop reduction(+:npt) present(atm, rank, ctl)
1805#endif
1806 for (int ip = 0; ip < np; ip++)
1807 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
1808 && ((int) atm->q[ctl->qnt_destination][ip] == *rank))
1809 npt++;
1810
1811 /* Count number of particles to send... */
1812 int nparticlest = 0;
1813#ifdef _OPENACC
1814#pragma acc parallel loop reduction(+:nparticlest) present(atm, rank, ctl)
1815#endif
1816 for (int ip = npt; ip < np; ip++)
1817 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
1818 && ((int) atm->q[ctl->qnt_destination][ip] != *rank))
1819 nparticlest++;
1820
1821 /* Reset sizes... */
1822 *nparticles = nparticlest;
1823
1824 /* Count particles with -1 subdomain (these will be effectively lost) */
1825 int nlost = 0;
1826 for (int ip = 0; ip < np; ip++)
1827 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
1828 nlost++;
1829
1830 if (nlost > 0) {
1831 WARN
1832 ("DD: Rank %d: %d particles have subdomain index -1 and will be lost (kept: %d, to_send: %d, total_before: %d)",
1833 *rank, nlost, npt, nparticlest, np);
1834 }
1835
1836 atm->np = npt;
1837#ifdef _OPENACC
1838#pragma acc update device(atm->np)
1839#endif
1840
1841 if (*nparticles > DD_NPART)
1842 ERRMSG
1843 ("Number of particles to send and recieve to small. Increase DD_NPART!");
1844
1845 /* Free... */
1846#ifdef _OPENACC
1847#pragma acc exit data delete(amax, rank)
1848#endif
1849}
1850#endif
1851
1852/*****************************************************************************/
1853
1854#ifdef DD
1855void dd_sort_help(
1856 double *a,
1857 dd_t *dd,
1858 const int np) {
1859
1860 /* Reordering of array... */
1861#ifdef _OPENACC
1862#pragma acc data present(dd,a)
1863#pragma acc parallel loop independent gang vector
1864#else
1865#pragma omp parallel for default(shared)
1866#endif
1867 for (int ip = 0; ip < np; ip++)
1868 dd->help[ip] = a[dd->p[ip]];
1869#ifdef _OPENACC
1870#pragma acc parallel loop independent gang vector
1871#else
1872#pragma omp parallel for default(shared)
1873#endif
1874 for (int ip = 0; ip < np; ip++)
1875 a[ip] = dd->help[ip];
1876}
1877#endif
1878
1879/*****************************************************************************/
1880
1882 const int year,
1883 const int doy,
1884 int *mon,
1885 int *day) {
1886
1887 const int
1888 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
1889 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
1890
1891 int i;
1892
1893 /* Get month and day... */
1894 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
1895 for (i = 11; i > 0; i--)
1896 if (d0l[i] <= doy)
1897 break;
1898 *mon = i + 1;
1899 *day = doy - d0l[i] + 1;
1900 } else {
1901 for (i = 11; i > 0; i--)
1902 if (d0[i] <= doy)
1903 break;
1904 *mon = i + 1;
1905 *day = doy - d0[i] + 1;
1906 }
1907}
1908
1909/*****************************************************************************/
1910
1912 double *fcReal,
1913 double *fcImag,
1914 const int n) {
1915
1916 double data[2 * EX];
1917
1918 /* Check size... */
1919 if (n > EX)
1920 ERRMSG("Too many data points!");
1921
1922 /* Allocate... */
1923 gsl_fft_complex_wavetable *wavetable =
1924 gsl_fft_complex_wavetable_alloc((size_t) n);
1925 gsl_fft_complex_workspace *workspace =
1926 gsl_fft_complex_workspace_alloc((size_t) n);
1927
1928 /* Set data (real, complex)... */
1929 for (int i = 0; i < n; i++) {
1930 data[2 * i] = fcReal[i];
1931 data[2 * i + 1] = fcImag[i];
1932 }
1933
1934 /* Calculate FFT... */
1935 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
1936
1937 /* Copy data... */
1938 for (int i = 0; i < n; i++) {
1939 fcReal[i] = data[2 * i];
1940 fcImag[i] = data[2 * i + 1];
1941 }
1942
1943 /* Free... */
1944 gsl_fft_complex_wavetable_free(wavetable);
1945 gsl_fft_complex_workspace_free(workspace);
1946}
1947
1948/*****************************************************************************/
1949
1951 const double z,
1952 const double lon,
1953 const double lat,
1954 double *x) {
1955
1956 const double radius = z + RE;
1957 const double latrad = DEG2RAD(lat);
1958 const double lonrad = DEG2RAD(lon);
1959 const double coslat = cos(latrad);
1960
1961 x[0] = radius * coslat * cos(lonrad);
1962 x[1] = radius * coslat * sin(lonrad);
1963 x[2] = radius * sin(latrad);
1964}
1965
1966/*****************************************************************************/
1967
1969 const ctl_t *ctl,
1970 const double t,
1971 const int direct,
1972 const char *metbase,
1973 const double dt_met,
1974 char *filename) {
1975
1976 char repl[LEN];
1977
1978 double t6, r;
1979
1980 int year, mon, day, hour, min, sec;
1981
1982 /* Round time to fixed intervals... */
1983 if (direct == -1)
1984 t6 = floor(t / dt_met) * dt_met;
1985 else
1986 t6 = ceil(t / dt_met) * dt_met;
1987
1988 /* Decode time... */
1989 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1990
1991 /* Set filename of MPTRAC meteo files... */
1992 if (ctl->met_clams == 0) {
1993 if (ctl->met_type == 0)
1994 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1995 else if (ctl->met_type == 1)
1996 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1997 else if (ctl->met_type == 2)
1998 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1999 else if (ctl->met_type == 3)
2000 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
2001 else if (ctl->met_type == 4)
2002 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
2003 else if (ctl->met_type == 5)
2004 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
2005 else if (ctl->met_type == 7)
2006 sprintf(filename, "%s_YYYY_MM_DD_HH.sz3", metbase);
2007 sprintf(repl, "%d", year);
2008 get_met_replace(filename, "YYYY", repl);
2009 sprintf(repl, "%02d", mon);
2010 get_met_replace(filename, "MM", repl);
2011 sprintf(repl, "%02d", day);
2012 get_met_replace(filename, "DD", repl);
2013 sprintf(repl, "%02d", hour);
2014 get_met_replace(filename, "HH", repl);
2015 }
2016
2017 /* Set filename of CLaMS meteo files... */
2018 else {
2019 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
2020 sprintf(repl, "%d", year);
2021 get_met_replace(filename, "YYYY", repl);
2022 sprintf(repl, "%02d", year % 100);
2023 get_met_replace(filename, "YY", repl);
2024 sprintf(repl, "%02d", mon);
2025 get_met_replace(filename, "MM", repl);
2026 sprintf(repl, "%02d", day);
2027 get_met_replace(filename, "DD", repl);
2028 sprintf(repl, "%02d", hour);
2029 get_met_replace(filename, "HH", repl);
2030 }
2031}
2032
2033/*****************************************************************************/
2034
2036 char *orig,
2037 char *search,
2038 char *repl) {
2039
2040 char buffer[LEN];
2041
2042 /* Iterate... */
2043 for (int i = 0; i < 3; i++) {
2044
2045 /* Replace sub-string... */
2046 char *ch;
2047 if (!(ch = strstr(orig, search)))
2048 return;
2049 strncpy(buffer, orig, (size_t) (ch - orig));
2050 buffer[ch - orig] = 0;
2051 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
2052 orig[0] = 0;
2053 strcpy(orig, buffer);
2054 }
2055}
2056
2057/*****************************************************************************/
2058
2060 const int met_tropo,
2061 ctl_t *ctl,
2062 clim_t *clim,
2063 met_t *met,
2064 const double *lons,
2065 const int nx,
2066 const double *lats,
2067 const int ny,
2068 double *pt,
2069 double *zt,
2070 double *tt,
2071 double *qt,
2072 double *o3t,
2073 double *ps,
2074 double *zs) {
2075
2077
2078 ctl->met_tropo = met_tropo;
2079 read_met_tropo(ctl, clim, met);
2080#pragma omp parallel for default(shared) private(ci,cw)
2081 for (int ix = 0; ix < nx; ix++)
2082 for (int iy = 0; iy < ny; iy++) {
2083 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
2084 &pt[iy * nx + ix], ci, cw, 1);
2085 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
2086 &ps[iy * nx + ix], ci, cw, 0);
2087 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
2088 &zs[iy * nx + ix], ci, cw, 0);
2089 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
2090 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
2091 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
2092 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
2093 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
2094 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
2095 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
2096 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
2097 }
2098}
2099
2100/*****************************************************************************/
2101
2103 const double *lons,
2104 const int nlon,
2105 const double *lats,
2106 const int nlat,
2107 const double lon,
2108 const double lat,
2109 double *lon2,
2110 double *lat2) {
2111
2112 /* Check longitude... */
2113 *lon2 = FMOD(lon, 360.);
2114 if (*lon2 < lons[0])
2115 *lon2 += 360;
2116 else if (*lon2 > lons[nlon - 1])
2117 *lon2 -= 360;
2118
2119 /* Check latitude... */
2120 *lat2 = lat;
2121 if (lats[0] < lats[nlat - 1])
2122 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
2123 else
2124 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
2125}
2126
2127/*****************************************************************************/
2128
2130 const met_t *met0,
2131 float heights0[EX][EY][EP],
2132 float array0[EX][EY][EP],
2133 const met_t *met1,
2134 float heights1[EX][EY][EP],
2135 float array1[EX][EY][EP],
2136 const double ts,
2137 const double height,
2138 const double lon,
2139 const double lat,
2140 double *var,
2141 int *ci,
2142 double *cw,
2143 const int init) {
2144
2145 if (init) {
2146
2147 /* Check longitude and latitude... */
2148 double lon2, lat2;
2149 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
2150 &lon2, &lat2);
2151
2152 /* Get horizontal indizes... */
2153 ci[0] = locate_reg(met0->lon, met0->nx, lon2);
2154 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
2155
2156 /* Locate the vertical indizes for each edge of the column... */
2157 int ind[2][4];
2158 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
2159 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
2160
2161 /* Find minimum and maximum indizes... */
2162 ci[2] = ind[0][0];
2163 int k_max = ind[0][0];
2164 for (int i = 0; i < 2; i++)
2165 for (int j = 0; j < 4; j++) {
2166 if (ci[2] > ind[i][j])
2167 ci[2] = ind[i][j];
2168 if (k_max < ind[i][j])
2169 k_max = ind[i][j];
2170 }
2171
2172 /* Get weighting factors for time, longitude and latitude... */
2173 cw[3] = (ts - met0->time) / (met1->time - met0->time);
2174 cw[0] = (lon2 - met0->lon[ci[0]]) /
2175 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
2176 cw[1] = (lat2 - met0->lat[ci[1]]) /
2177 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
2178
2179 /* Interpolate in time at the lowest level... */
2180 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
2181 - heights0[ci[0]][ci[1]][ci[2]])
2182 + heights0[ci[0]][ci[1]][ci[2]];
2183 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
2184 - heights0[ci[0]][ci[1] + 1][ci[2]])
2185 + heights0[ci[0]][ci[1] + 1][ci[2]];
2186 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
2187 - heights0[ci[0] + 1][ci[1]][ci[2]])
2188 + heights0[ci[0] + 1][ci[1]][ci[2]];
2189 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
2190 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
2191 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
2192
2193 /* Interpolate in latitude direction... */
2194 double height0 = cw[1] * (height01 - height00) + height00;
2195 double height1 = cw[1] * (height11 - height10) + height10;
2196
2197 /* Interpolate in longitude direction... */
2198 double height_bot = cw[0] * (height1 - height0) + height0;
2199
2200 /* Interpolate in time at the upper level... */
2201 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2202 - heights0[ci[0]][ci[1]][ci[2] + 1])
2203 + heights0[ci[0]][ci[1]][ci[2] + 1];
2204 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2205 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2206 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2207 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2208 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2209 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2210 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2211 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2212 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2213
2214 /* Interpolate in latitude direction... */
2215 height0 = cw[1] * (height01 - height00) + height00;
2216 height1 = cw[1] * (height11 - height10) + height10;
2217
2218 /* Interpolate in longitude direction... */
2219 double height_top = cw[0] * (height1 - height0) + height0;
2220
2221 /* Search at higher levels if height is not in box... */
2222 while (((heights0[0][0][0] > heights0[0][0][1]) &&
2223 ((height_bot <= height) || (height_top > height))
2224 && (height_bot >= height) && (ci[2] < k_max))
2225 ||
2226 ((heights0[0][0][0] < heights0[0][0][1]) &&
2227 ((height_bot >= height) || (height_top < height))
2228 && (height_bot <= height) && (ci[2] < k_max))
2229 ) {
2230
2231 ci[2]++;
2232 height_bot = height_top;
2233
2234 /* Interpolate in time at the next level... */
2235 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
2236 - heights0[ci[0]][ci[1]][ci[2] + 1])
2237 + heights0[ci[0]][ci[1]][ci[2] + 1];
2238 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
2239 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
2240 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
2241 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
2242 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
2243 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
2244 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2245 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2246 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2247
2248 /* Interpolate in latitude direction... */
2249 height0 = cw[1] * (height01 - height00) + height00;
2250 height1 = cw[1] * (height11 - height10) + height10;
2251
2252 /* Interpolate in longitude direction... */
2253 height_top = cw[0] * (height1 - height0) + height0;
2254 }
2255
2256 /* Get vertical weighting factors... */
2257 cw[2] = (height - height_bot)
2258 / (height_top - height_bot);
2259 }
2260
2261 /* Calculate the needed array values... */
2262 const double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
2263 - array0[ci[0]][ci[1]][ci[2]])
2264 + array0[ci[0]][ci[1]][ci[2]];
2265 const double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
2266 - array0[ci[0] + 1][ci[1]][ci[2]])
2267 + array0[ci[0] + 1][ci[1]][ci[2]];
2268 const double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
2269 - array0[ci[0]][ci[1] + 1][ci[2]])
2270 + array0[ci[0]][ci[1] + 1][ci[2]];
2271 const double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
2272 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
2273 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
2274 const double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
2275 - array0[ci[0]][ci[1]][ci[2] + 1])
2276 + array0[ci[0]][ci[1]][ci[2] + 1];
2277 const double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
2278 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
2279 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
2280 const double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
2281 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
2282 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
2283 const double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
2284 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
2285 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
2286
2287 const double array00 = cw[0] * (array100 - array000) + array000;
2288 const double array10 = cw[0] * (array110 - array010) + array010;
2289 const double array01 = cw[0] * (array101 - array001) + array001;
2290 const double array11 = cw[0] * (array111 - array011) + array011;
2291
2292 const double aux0 = cw[1] * (array10 - array00) + array00;
2293 const double aux1 = cw[1] * (array11 - array01) + array01;
2294
2295 /* Interpolate vertically... */
2296 *var = cw[2] * (aux1 - aux0) + aux0;
2297}
2298
2299/*****************************************************************************/
2300
2302 const met_t *met,
2303 float array[EX][EY][EP],
2304 const double p,
2305 const double lon,
2306 const double lat,
2307 double *var,
2308 int *ci,
2309 double *cw,
2310 const int init) {
2311
2312 /* Initialize interpolation... */
2313 if (init) {
2314
2315 /* Check longitude and latitude... */
2316 double lon2, lat2;
2317 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2318 &lon2, &lat2);
2319
2320 /* Get interpolation indices... */
2321 ci[0] = locate_irr(met->p, met->np, p);
2322 ci[1] = locate_reg(met->lon, met->nx, lon2);
2323 ci[2] = locate_irr(met->lat, met->ny, lat2);
2324
2325 /* Get interpolation weights... */
2326 cw[0] = (met->p[ci[0] + 1] - p)
2327 / (met->p[ci[0] + 1] - met->p[ci[0]]);
2328 cw[1] = (met->lon[ci[1] + 1] - lon2)
2329 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2330 cw[2] = (met->lat[ci[2] + 1] - lat2)
2331 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2332 }
2333
2334 /* Interpolate vertically... */
2335 const double aux00 =
2336 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
2337 + array[ci[1]][ci[2]][ci[0] + 1];
2338 const double aux01 =
2339 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
2340 array[ci[1]][ci[2] + 1][ci[0] + 1])
2341 + array[ci[1]][ci[2] + 1][ci[0] + 1];
2342 const double aux10 =
2343 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
2344 array[ci[1] + 1][ci[2]][ci[0] + 1])
2345 + array[ci[1] + 1][ci[2]][ci[0] + 1];
2346 const double aux11 =
2347 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
2348 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
2349 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
2350
2351 /* Interpolate horizontally... */
2352 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2353 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2354 *var = cw[1] * (aux0 - aux1) + aux1;
2355}
2356
2357/*****************************************************************************/
2358
2360 const met_t *met,
2361 float array[EX][EY],
2362 const double lon,
2363 const double lat,
2364 double *var,
2365 int *ci,
2366 double *cw,
2367 const int init) {
2368
2369 /* Initialize interpolation... */
2370 if (init) {
2371
2372 /* Check longitude and latitude... */
2373 double lon2, lat2;
2374 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
2375 &lon2, &lat2);
2376
2377 /* Get interpolation indices... */
2378 ci[1] = locate_reg(met->lon, met->nx, lon2);
2379 ci[2] = locate_irr(met->lat, met->ny, lat2);
2380
2381 /* Get interpolation weights... */
2382 cw[1] = (met->lon[ci[1] + 1] - lon2)
2383 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
2384 cw[2] = (met->lat[ci[2] + 1] - lat2)
2385 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
2386 }
2387
2388 /* Set variables... */
2389 const double aux00 = array[ci[1]][ci[2]];
2390 const double aux01 = array[ci[1]][ci[2] + 1];
2391 const double aux10 = array[ci[1] + 1][ci[2]];
2392 const double aux11 = array[ci[1] + 1][ci[2] + 1];
2393
2394 /* Interpolate horizontally... */
2395 if (isfinite(aux00) && isfinite(aux01)
2396 && isfinite(aux10) && isfinite(aux11)) {
2397 const double aux0 = cw[2] * (aux00 - aux01) + aux01;
2398 const double aux1 = cw[2] * (aux10 - aux11) + aux11;
2399 *var = cw[1] * (aux0 - aux1) + aux1;
2400 } else {
2401 if (cw[2] < 0.5) {
2402 if (cw[1] < 0.5)
2403 *var = aux11;
2404 else
2405 *var = aux01;
2406 } else {
2407 if (cw[1] < 0.5)
2408 *var = aux10;
2409 else
2410 *var = aux00;
2411 }
2412 }
2413}
2414
2415/*****************************************************************************/
2416
2418 const met_t *met0,
2419 float array0[EX][EY][EP],
2420 const met_t *met1,
2421 float array1[EX][EY][EP],
2422 const double ts,
2423 const double p,
2424 const double lon,
2425 const double lat,
2426 double *var,
2427 int *ci,
2428 double *cw,
2429 const int init) {
2430
2431 double var0, var1;
2432
2433 /* Spatial interpolation... */
2434 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
2435 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
2436
2437 /* Get weighting factor... */
2438 const double wt = (met1->time - ts) / (met1->time - met0->time);
2439
2440 /* Interpolate... */
2441 *var = wt * (var0 - var1) + var1;
2442}
2443
2444/*****************************************************************************/
2445
2447 const met_t *met0,
2448 float array0[EX][EY],
2449 const met_t *met1,
2450 float array1[EX][EY],
2451 const double ts,
2452 const double lon,
2453 const double lat,
2454 double *var,
2455 int *ci,
2456 double *cw,
2457 const int init) {
2458
2459 double var0, var1;
2460
2461 /* Spatial interpolation... */
2462 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
2463 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
2464
2465 /* Get weighting factor... */
2466 const double wt = (met1->time - ts) / (met1->time - met0->time);
2467
2468 /* Interpolate... */
2469 if (isfinite(var0) && isfinite(var1))
2470 *var = wt * (var0 - var1) + var1;
2471 else if (wt < 0.5)
2472 *var = var1;
2473 else
2474 *var = var0;
2475}
2476
2477/*****************************************************************************/
2478
2480 const double time0,
2481 float array0[EX][EY],
2482 const double time1,
2483 float array1[EX][EY],
2484 const double lons[EX],
2485 const double lats[EY],
2486 const int nlon,
2487 const int nlat,
2488 const double time,
2489 const double lon,
2490 const double lat,
2491 const int method,
2492 double *var,
2493 double *sigma) {
2494
2495 double mean = 0;
2496
2497 int n = 0;
2498
2499 /* Check longitude and latitude... */
2500 double lon2, lat2;
2501 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
2502
2503 /* Get indices... */
2504 const int ix = locate_reg(lons, (int) nlon, lon2);
2505 const int iy = locate_irr(lats, (int) nlat, lat2);
2506
2507 /* Calculate standard deviation... */
2508 *sigma = 0;
2509 for (int dx = 0; dx < 2; dx++)
2510 for (int dy = 0; dy < 2; dy++) {
2511 if (isfinite(array0[ix + dx][iy + dy])) {
2512 mean += array0[ix + dx][iy + dy];
2513 *sigma += SQR(array0[ix + dx][iy + dy]);
2514 n++;
2515 }
2516 if (isfinite(array1[ix + dx][iy + dy])) {
2517 mean += array1[ix + dx][iy + dy];
2518 *sigma += SQR(array1[ix + dx][iy + dy]);
2519 n++;
2520 }
2521 }
2522 if (n > 0)
2523 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
2524
2525 /* Linear interpolation... */
2526 if (method == 1 && isfinite(array0[ix][iy])
2527 && isfinite(array0[ix][iy + 1])
2528 && isfinite(array0[ix + 1][iy])
2529 && isfinite(array0[ix + 1][iy + 1])
2530 && isfinite(array1[ix][iy])
2531 && isfinite(array1[ix][iy + 1])
2532 && isfinite(array1[ix + 1][iy])
2533 && isfinite(array1[ix + 1][iy + 1])) {
2534
2535 const double aux00 = LIN(lons[ix], array0[ix][iy],
2536 lons[ix + 1], array0[ix + 1][iy], lon2);
2537 const double aux01 = LIN(lons[ix], array0[ix][iy + 1],
2538 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2539 const double aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2540
2541 const double aux10 = LIN(lons[ix], array1[ix][iy],
2542 lons[ix + 1], array1[ix + 1][iy], lon2);
2543 const double aux11 = LIN(lons[ix], array1[ix][iy + 1],
2544 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2545 const double aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2546
2547 *var = LIN(time0, aux0, time1, aux1, time);
2548 }
2549
2550 /* Nearest neighbor interpolation... */
2551 else {
2552 const double aux00 = NN(lons[ix], array0[ix][iy],
2553 lons[ix + 1], array0[ix + 1][iy], lon2);
2554 const double aux01 = NN(lons[ix], array0[ix][iy + 1],
2555 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
2556 const double aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
2557
2558 const double aux10 = NN(lons[ix], array1[ix][iy],
2559 lons[ix + 1], array1[ix + 1][iy], lon2);
2560 const double aux11 = NN(lons[ix], array1[ix][iy + 1],
2561 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
2562 const double aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
2563
2564 *var = NN(time0, aux0, time1, aux1, time);
2565 }
2566}
2567
2568/*****************************************************************************/
2569
2571 const double jsec,
2572 int *year,
2573 int *mon,
2574 int *day,
2575 int *hour,
2576 int *min,
2577 int *sec,
2578 double *remain) {
2579
2580 struct tm t0, *t1;
2581
2582 t0.tm_year = 100;
2583 t0.tm_mon = 0;
2584 t0.tm_mday = 1;
2585 t0.tm_hour = 0;
2586 t0.tm_min = 0;
2587 t0.tm_sec = 0;
2588
2589 const time_t jsec0 = (time_t) jsec + timegm(&t0);
2590 t1 = gmtime(&jsec0);
2591
2592 *year = t1->tm_year + 1900;
2593 *mon = t1->tm_mon + 1;
2594 *day = t1->tm_mday;
2595 *hour = t1->tm_hour;
2596 *min = t1->tm_min;
2597 *sec = t1->tm_sec;
2598 *remain = jsec - floor(jsec);
2599}
2600
2601/*****************************************************************************/
2602
2604 const double kz[EP],
2605 const double kw[EP],
2606 const int nk,
2607 const double p) {
2608
2609 /* Check number of data points... */
2610 if (nk < 2)
2611 return 1.0;
2612
2613 /* Get altitude... */
2614 const double z = Z(p);
2615
2616 /* Get weighting factor... */
2617 if (z < kz[0])
2618 return kw[0];
2619 else if (z > kz[nk - 1])
2620 return kw[nk - 1];
2621 else {
2622 const int idx = locate_irr(kz, nk, z);
2623 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
2624 }
2625}
2626
2627/*****************************************************************************/
2628
2630 const double t,
2631 const double h2o) {
2632
2633 /*
2634 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
2635 and water vapor volume mixing ratio [1].
2636
2637 Reference: https://en.wikipedia.org/wiki/Lapse_rate
2638 */
2639
2640 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
2641
2642 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
2643}
2644
2645/*****************************************************************************/
2646
2648 ctl_t *ctl) {
2649
2650 if (0 == ctl->met_press_level_def) {
2651
2652 ERRMSG("MET_PRESS_LEVEL_DEF=0 is disabled. Use 3 for the extended L137 set.");
2653
2654 } else if (1 == ctl->met_press_level_def) {
2655
2656 ERRMSG("MET_PRESS_LEVEL_DEF=1 is disabled. Use 4 for the extended L91 set.");
2657
2658 } else if (2 == ctl->met_press_level_def) {
2659
2660 ERRMSG("MET_PRESS_LEVEL_DEF=2 is disabled. Use 5 for the extended L60 set.");
2661
2662 } else if (3 == ctl->met_press_level_def) {
2663
2664 ctl->met_np = 147;
2665
2666 const double press[147] = {
2667 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
2668 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
2669 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
2670 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
2671 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2672 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
2673 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
2674 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
2675 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
2676 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
2677 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
2678 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
2679 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
2680 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
2681 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
2682 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
2683 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
2684 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
2685 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
2686 1031.97,
2687 1035.09, 1038.21, 1041.33, 1044.45
2688 };
2689
2690 for (int ip = 0; ip < ctl->met_np; ip++)
2691 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2692
2693 } else if (4 == ctl->met_press_level_def) {
2694
2695 ctl->met_np = 101;
2696
2697 const double press[101] = {
2698 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
2699 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
2700 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
2701 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
2702 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
2703 113.6382,
2704 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
2705 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
2706 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2707 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2708 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2709 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2710 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2711 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
2712 1028.85, 1031.97,
2713 1035.09, 1038.21, 1041.33, 1044.45
2714 };
2715
2716 for (int ip = 0; ip < ctl->met_np; ip++)
2717 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2718
2719 } else if (5 == ctl->met_press_level_def) {
2720
2721 ctl->met_np = 62;
2722
2723 const double press[62] = {
2724 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2725 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2726 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2727 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2728 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2729 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2730 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2731 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
2732 1044.45
2733 };
2734
2735 for (int ip = 0; ip < ctl->met_np; ip++)
2736 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2737
2738 } else if (6 == ctl->met_press_level_def) {
2739
2740 ctl->met_np = 137;
2741
2742 const double press[137] = {
2743 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
2744 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
2745 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
2746 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
2747 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
2748 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2749 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
2750 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
2751 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
2752 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
2753 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
2754 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
2755 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
2756 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
2757 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
2758 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
2759 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
2760 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
2761 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
2762 1030.06, 1037.25, 1044.45
2763 };
2764
2765 for (int ip = 0; ip < ctl->met_np; ip++)
2766 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2767
2768 } else if (7 == ctl->met_press_level_def) {
2769
2770 ctl->met_np = 59;
2771
2772 const double press[59] = {
2773 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2774 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2775 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2776 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2777 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2778 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2779 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2780 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2781 1028.53, 1046.13
2782 };
2783
2784 for (int ip = 0; ip < ctl->met_np; ip++)
2785 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2786
2787 } else {
2788 ERRMSG("Use values between 3 and 7.");
2789 }
2790
2791 if (ctl->met_np > EP) {
2792 ERRMSG("Recompile with larger EP to use this pressure level definition.");
2793 }
2794}
2795
2796/*****************************************************************************/
2797
2799 const double *xx,
2800 const int n,
2801 const double x) {
2802
2803 int ilo = 0;
2804 int ihi = n - 1;
2805 int i = (ihi + ilo) >> 1;
2806
2807 if (xx[i] < xx[i + 1])
2808 while (ihi > ilo + 1) {
2809 i = (ihi + ilo) >> 1;
2810 if (xx[i] > x)
2811 ihi = i;
2812 else
2813 ilo = i;
2814 } else
2815 while (ihi > ilo + 1) {
2816 i = (ihi + ilo) >> 1;
2817 if (xx[i] <= x)
2818 ihi = i;
2819 else
2820 ilo = i;
2821 }
2822
2823 return ilo;
2824}
2825
2826/*****************************************************************************/
2827
2829 const float *xx,
2830 const int n,
2831 const double x,
2832 const int ig) {
2833
2834 int ilo = 0;
2835 int ihi = n - 1;
2836 int i = (ihi + ilo) >> 1;
2837
2838 if ((xx[ig] <= x && x < xx[ig + 1]) || (xx[ig] >= x && x > xx[ig + 1]))
2839 return ig;
2840
2841 if (xx[i] < xx[i + 1])
2842 while (ihi > ilo + 1) {
2843 i = (ihi + ilo) >> 1;
2844 if (xx[i] > x)
2845 ihi = i;
2846 else
2847 ilo = i;
2848 } else
2849 while (ihi > ilo + 1) {
2850 i = (ihi + ilo) >> 1;
2851 if (xx[i] <= x)
2852 ihi = i;
2853 else
2854 ilo = i;
2855 }
2856
2857 return ilo;
2858}
2859
2860/*****************************************************************************/
2861
2863 const double *xx,
2864 const int n,
2865 const double x) {
2866
2867 /* Calculate index... */
2868 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2869
2870 /* Check range... */
2871 if (i < 0)
2872 return 0;
2873 else if (i > n - 2)
2874 return n - 2;
2875 else
2876 return i;
2877}
2878
2879/*****************************************************************************/
2880
2882 float profiles[EX][EY][EP],
2883 const int np,
2884 const int lon_ap_ind,
2885 const int lat_ap_ind,
2886 const double height_ap,
2887 int *ind) {
2888
2889 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2890 np, height_ap, 0);
2891 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2892 np, height_ap, ind[0]);
2893 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2894 np, height_ap, ind[1]);
2895 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2896 np, height_ap, ind[2]);
2897}
2898
2899/*****************************************************************************/
2900
2902 const ctl_t *ctl,
2903 const cache_t *cache,
2904 met_t *met0,
2905 met_t *met1,
2906 atm_t *atm) {
2907
2908 /* Set timer... */
2909 SELECT_TIMER("MODULE_ADVECT", "PHYSICS");
2910
2911 /* Use omega vertical velocity... */
2912 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2913
2914 /* Loop over particles... */
2915 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2916
2917 /* Init... */
2919 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2920 x[3] = { 0, 0, 0 };
2921
2922 /* Loop over integration nodes... */
2923 for (int i = 0; i < ctl->advect; i++) {
2924
2925 /* Set position... */
2926 if (i == 0) {
2927 dts = 0.0;
2928 x[0] = atm->lon[ip];
2929 x[1] = atm->lat[ip];
2930 x[2] = atm->p[ip];
2931 } else {
2932 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2933 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2934 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2935 x[2] = atm->p[ip] + dts * w[i - 1];
2936 }
2937 const double tm = atm->time[ip] + dts;
2938
2939 /* Interpolate meteo data on pressure levels... */
2940 if (ctl->advect_vert_coord == 0) {
2941 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2942 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2943 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2944 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2945 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2946 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2947 }
2948
2949 /* Interpolate meteo data on model levels... */
2950 else {
2951 intpol_met_4d_zeta(met0, met0->pl, met0->ul,
2952 met1, met1->pl, met1->ul,
2953 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2954 intpol_met_4d_zeta(met0, met0->pl, met0->vl,
2955 met1, met1->pl, met1->vl,
2956 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2957 intpol_met_4d_zeta(met0, met0->pl, met0->wl,
2958 met1, met1->pl, met1->wl,
2959 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2960 }
2961
2962 /* Get mean wind... */
2963 double k = 1.0;
2964 if (ctl->advect == 2)
2965 k = (i == 0 ? 0.0 : 1.0);
2966 else if (ctl->advect == 4)
2967 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2968 um += k * u[i];
2969 vm += k * v[i];
2970 wm += k * w[i];
2971 }
2972
2973 /* Set new position... */
2974 atm->time[ip] += cache->dt[ip];
2975 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2976 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2977 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2978 atm->p[ip] += cache->dt[ip] * wm;
2979 }
2980 }
2981
2982 /* Use zeta or eta vertical velocity... */
2983 else if (ctl->advect_vert_coord == 1 || ctl->advect_vert_coord == 3) {
2984
2985 /* Select quantity index depending on coordinate... */
2986 const int qnt = (ctl->advect_vert_coord == 1
2987 ? ctl->qnt_zeta : ctl->qnt_eta);
2988
2989 /* Loop over particles... */
2990 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2991
2992 /* Convert pressure to vertical coordinate (zeta or eta)... */
2994 intpol_met_4d_zeta(met0, met0->pl, met0->zetal,
2995 met1, met1->pl, met1->zetal,
2996 atm->time[ip], atm->p[ip],
2997 atm->lon[ip], atm->lat[ip],
2998 &atm->q[qnt][ip], ci, cw, 1);
2999
3000 /* Init... */
3001 double dts, u[4], um = 0, v[4], vm = 0, wdot[4],
3002 wdotm = 0, x[3] = { 0, 0, 0 };
3003
3004 /* Loop over integration nodes (Runge–Kutta steps)... */
3005 for (int i = 0; i < ctl->advect; i++) {
3006
3007 /* Set position... */
3008 if (i == 0) {
3009 dts = 0.0;
3010 x[0] = atm->lon[ip];
3011 x[1] = atm->lat[ip];
3012 x[2] = atm->q[qnt][ip];
3013 } else {
3014 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
3015 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
3016 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
3017 x[2] = atm->q[qnt][ip] + dts * wdot[i - 1];
3018 }
3019
3020 const double tm = atm->time[ip] + dts;
3021
3022 /* Interpolate meteo data... */
3023 intpol_met_4d_zeta(met0, met0->zetal, met0->ul,
3024 met1, met1->zetal, met1->ul,
3025 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
3026 intpol_met_4d_zeta(met0, met0->zetal, met0->vl,
3027 met1, met1->zetal, met1->vl,
3028 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
3029 intpol_met_4d_zeta(met0, met0->zetal, met0->zeta_dotl,
3030 met1, met1->zetal, met1->zeta_dotl,
3031 tm, x[2], x[0], x[1], &wdot[i], ci, cw, 0);
3032
3033 /* Compute Runge–Kutta weights... */
3034 double k = 1.0;
3035 if (ctl->advect == 2)
3036 k = (i == 0 ? 0.0 : 1.0);
3037 else if (ctl->advect == 4)
3038 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
3039
3040 um += k * u[i];
3041 vm += k * v[i];
3042 wdotm += k * wdot[i];
3043 }
3044
3045 /* Update particle position... */
3046 atm->time[ip] += cache->dt[ip];
3047 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
3048 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
3049 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
3050 atm->q[qnt][ip] += cache->dt[ip] * wdotm;
3051
3052 /* Convert vertical coordinate (zeta or eta) back to pressure... */
3053 intpol_met_4d_zeta(met0, met0->zetal, met0->pl,
3054 met1, met1->zetal, met1->pl,
3055 atm->time[ip],
3056 atm->q[qnt][ip], atm->lon[ip], atm->lat[ip],
3057 &atm->p[ip], ci, cw, 1);
3058 }
3059 }
3060}
3061
3062/*****************************************************************************/
3063
3065 const ctl_t *ctl,
3066 const cache_t *cache,
3067 met_t *met0,
3068 met_t *met1,
3069 atm_t *atm) {
3070
3071 /* Check parameters... */
3072 if (ctl->advect_vert_coord != 1)
3073 return;
3074
3075 /* Set timer... */
3076 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS");
3077
3078 /* Loop over particles... */
3079 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
3080
3081 /* Initialize pressure consistent with zeta... */
3083 intpol_met_4d_zeta(met0, met0->zetal, met0->pl, met1, met1->zetal,
3084 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
3085 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
3086 }
3087}
3088
3089/*****************************************************************************/
3090
3092 const ctl_t *ctl,
3093 const cache_t *cache,
3094 const clim_t *clim,
3095 met_t *met0,
3096 met_t *met1,
3097 atm_t *atm) {
3098
3099 /* Set timer... */
3100 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS");
3101
3102 /* Check quantity flags... */
3103 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
3104 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
3105 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
3106 return;
3107
3108 /* Loop over particles... */
3109 PARTICLE_LOOP(0, atm->np, 1,
3110 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3111
3112 /* Check latitude and pressure range... */
3113 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
3114 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
3115 continue;
3116
3117 /* Check surface layer... */
3118 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
3119 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
3120
3121 /* Get surface pressure... */
3122 double ps;
3124 INTPOL_2D(ps, 1);
3125
3126 /* Check pressure... */
3127 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
3128 continue;
3129
3130 /* Check height... */
3131 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
3132 continue;
3133
3134 /* Check zeta range... */
3135 if (ctl->bound_zetas > 0) {
3136 double t;
3137 INTPOL_3D(t, 1);
3138 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
3139 continue;
3140 }
3141
3142 /* Check planetary boundary layer... */
3143 if (ctl->bound_pbl) {
3144 double pbl;
3145 INTPOL_2D(pbl, 0);
3146 if (atm->p[ip] < pbl)
3147 continue;
3148 }
3149 }
3150
3151 /* Set mass and volume mixing ratio... */
3152 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
3153 atm->q[ctl->qnt_m][ip] =
3154 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
3155 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
3156 atm->q[ctl->qnt_vmr][ip] =
3157 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
3158
3159 /* Set CFC-10 volume mixing ratio... */
3160 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
3161 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
3162
3163 /* Set CFC-11 volume mixing ratio... */
3164 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
3165 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
3166
3167 /* Set CFC-12 volume mixing ratio... */
3168 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
3169 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
3170
3171 /* Set N2O volume mixing ratio... */
3172 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
3173 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
3174
3175 /* Set SF6 volume mixing ratio... */
3176 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
3177 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
3178
3179 /* Set age of air... */
3180 if (ctl->qnt_aoa >= 0)
3181 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
3182 }
3183}
3184
3185/*****************************************************************************/
3186
3188 const ctl_t *ctl,
3189 met_t *met0,
3190 met_t *met1,
3191 atm_t *atm,
3192 const double tt) {
3193
3194 /* Check quantities... */
3195 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
3196 return;
3197 if (ctl->molmass <= 0)
3198 ERRMSG("Molar mass is not defined!");
3199
3200 /* Set timer... */
3201 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS");
3202
3203 /* Allocate... */
3204 const int ensemble_mode = (ctl->nens > 0);
3205 const int np = atm->np;
3206 const int nz = ctl->chemgrid_nz;
3207 const int nx = ctl->chemgrid_nx;
3208 const int ny = ctl->chemgrid_ny;
3209 const int ngrid = nx * ny * nz;
3210 const int nens = ensemble_mode ? ctl->nens : 1;
3211
3212 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
3213 double *restrict const press =
3214 (double *) malloc((size_t) nz * sizeof(double));
3215 double *restrict const mass =
3216 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
3217 double *restrict const area =
3218 (double *) malloc((size_t) ny * sizeof(double));
3219 double *restrict const lon =
3220 (double *) malloc((size_t) nx * sizeof(double));
3221 double *restrict const lat =
3222 (double *) malloc((size_t) ny * sizeof(double));
3223
3224 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3225 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3226 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3227
3228 /* Set grid box size... */
3229 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
3230 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
3231 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
3232
3233 /* Set vertical coordinates... */
3234#ifdef _OPENACC
3235#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])
3236#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
3237#pragma acc parallel loop independent gang vector
3238#else
3239#pragma omp parallel for default(shared)
3240#endif
3241 for (int iz = 0; iz < nz; iz++) {
3242 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
3243 press[iz] = P(z[iz]);
3244 }
3245
3246 /* Set time interval for output... */
3247 const double t0 = tt - 0.5 * ctl->dt_mod;
3248 const double t1 = tt + 0.5 * ctl->dt_mod;
3249
3250 /* Get indices... */
3251#ifdef _OPENACC
3252#pragma acc parallel loop independent gang vector
3253#else
3254#pragma omp parallel for default(shared)
3255#endif
3256 for (int ip = 0; ip < np; ip++) {
3257 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
3258 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
3259 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
3260 if (atm->time[ip] < t0 || atm->time[ip] > t1
3261 || ixs[ip] < 0 || ixs[ip] >= nx
3262 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
3263 izs[ip] = -1;
3264 }
3265
3266 /* Set horizontal coordinates... */
3267#ifdef _OPENACC
3268#pragma acc parallel loop independent gang vector
3269#else
3270#pragma omp parallel for default(shared)
3271#endif
3272 for (int ix = 0; ix < nx; ix++)
3273 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
3274
3275#ifdef _OPENACC
3276#pragma acc parallel loop independent gang vector
3277#else
3278#pragma omp parallel for default(shared)
3279#endif
3280 for (int iy = 0; iy < ny; iy++) {
3281 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
3282 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
3283 }
3284
3285 /* Get mass per grid box... */
3286#ifdef _OPENACC
3287#pragma acc parallel loop independent gang vector
3288#endif
3289 for (int ip = 0; ip < np; ip++) {
3290 if (izs[ip] >= 0) {
3291 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3292 if (ensemble_mode) {
3293 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3294 mass_idx += ens * ngrid;
3295 }
3296#ifdef _OPENACC
3297#pragma acc atomic update
3298#endif
3299 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
3300 }
3301 }
3302
3303 /* Assign grid data to air parcels ... */
3304#ifdef _OPENACC
3305#pragma acc parallel loop independent gang vector
3306#else
3307#pragma omp parallel for default(shared)
3308#endif
3309 for (int ip = 0; ip < np; ip++)
3310 if (izs[ip] >= 0) {
3311
3312 /* Interpolate temperature... */
3313 double temp;
3315 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
3316 press[izs[ip]],
3317 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
3318
3319 /* Set mass... */
3320 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
3321 if (ensemble_mode) {
3322 const int ens = (int) atm->q[ctl->qnt_ens][ip];
3323 mass_idx += ens * ngrid;
3324 }
3325
3326 /* Calculate volume mixing ratio... */
3327 const double m = mass[mass_idx];
3328 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
3329 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
3330 }
3331
3332 /* Free... */
3333#ifdef _OPENACC
3334#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
3335#endif
3336 free(mass);
3337 free(lon);
3338 free(lat);
3339 free(area);
3340 free(z);
3341 free(press);
3342 free(ixs);
3343 free(iys);
3344 free(izs);
3345}
3346
3347/*****************************************************************************/
3348
3350 const ctl_t *ctl,
3351 const cache_t *cache,
3352 const clim_t *clim,
3353 met_t *met0,
3354 met_t *met1,
3355 atm_t *atm) {
3356
3357 /* Set timer... */
3358 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS");
3359
3360 /* Loop over particles... */
3361 PARTICLE_LOOP(0, atm->np, 0,
3362 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3363
3364 /* Set H2O and O3 using meteo data... */
3366 if (ctl->qnt_Ch2o >= 0) {
3367 double h2o;
3368 INTPOL_3D(h2o, 1);
3369 SET_ATM(qnt_Ch2o, h2o);
3370 }
3371 if (ctl->qnt_Co3 >= 0) {
3372 double o3;
3373 INTPOL_3D(o3, 1);
3374 SET_ATM(qnt_Co3, o3);
3375 }
3376
3377 /* Set radical species... */
3378 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
3379 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3380 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
3381 atm->lat[ip], atm->p[ip]));
3382 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
3383 atm->lat[ip], atm->p[ip]));
3384 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
3385 atm->lat[ip], atm->p[ip]));
3386 }
3387}
3388
3389/*****************************************************************************/
3390
3392 const ctl_t *ctl,
3393 cache_t *cache,
3394 met_t *met0,
3395 met_t *met1,
3396 atm_t *atm) {
3397
3398 /* Set timer... */
3399 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS");
3400
3401 /* Create random numbers... */
3402 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
3403
3404 /* Loop over particles... */
3405 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3406
3407 /* Interpolate surface pressure... */
3408 double ps;
3410 INTPOL_2D(ps, 1);
3411
3412 /* Initialize pressure range for vertical mixing... */
3413 double pbot = ps, ptop = ps;
3414
3415 /* Mixing in the PBL... */
3416 if (ctl->conv_mix_pbl) {
3417
3418 /* Interpolate PBL... */
3419 double pbl;
3420 INTPOL_2D(pbl, 0);
3421
3422 /* Set pressure range... */
3423 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
3424 }
3425
3426 /* Convective mixing... */
3427 if (ctl->conv_cape >= 0) {
3428
3429 /* Interpolate CAPE, CIN, and equilibrium level... */
3430 double cape, cin, pel;
3431 INTPOL_2D(cape, 0);
3432 INTPOL_2D(cin, 0);
3433 INTPOL_2D(pel, 0);
3434
3435 /* Set pressure range... */
3436 if (isfinite(cape) && cape >= ctl->conv_cape
3437 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
3438 ptop = GSL_MIN(ptop, pel);
3439 }
3440
3441 /* Apply vertical mixing... */
3442 if (ptop != pbot && atm->p[ip] >= ptop) {
3443
3444 /* Get density range... */
3445 double tbot, ttop;
3446 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
3447 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
3448 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
3449 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
3450 const double rhobot = pbot / tbot;
3451 const double rhotop = ptop / ttop;
3452
3453 /* Get new density... */
3454 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
3455
3456 /* Get pressure... */
3457 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
3458 }
3459 }
3460}
3461
3462/*****************************************************************************/
3463
3464#ifdef DD
3465void module_dd(
3466 ctl_t *ctl,
3467 atm_t *atm,
3468 cache_t *cache,
3469 dd_t *dd,
3470 met_t **met) {
3471
3472 /* Initialize particles locally... */
3473 int nparticles = 0;
3474 particle_t *particles;
3475 ALLOC(particles, particle_t, DD_NPART);
3476
3477 /* Assign particles to new subdomains... */
3478 dd_assign_rect_subdomains_atm(atm, ctl, dd, 0);
3479
3480 /* Sorting particles according to location and target rank... */
3481 dd_sort(ctl, *met, atm, dd, &nparticles, &dd->rank);
3482
3483 /* Transform from struct of array to array of struct... */
3484 dd_atm2particles(atm, particles, ctl, &nparticles, cache, dd->rank);
3485
3486 /********************* CPU region start ***********************************/
3487
3488 /* Perform the communication... */
3489 dd_communicate_particles(particles, &nparticles, dd->MPI_Particle,
3490 dd->neighbours, ctl->dd_nbr_neighbours, *ctl);
3491
3492 /********************* CPU region end *************************************/
3493
3494 /* Transform from array of struct to struct of array... */
3495 dd_particles2atm(atm, particles, ctl, &nparticles, cache);
3496
3497 /* Free local particle array... */
3498 free(particles);
3499}
3500#endif
3501
3502/*****************************************************************************/
3503
3505 const ctl_t *ctl,
3506 const cache_t *cache,
3507 const clim_t *clim,
3508 atm_t *atm) {
3509
3510 /* Set timer... */
3511 SELECT_TIMER("MODULE_DECAY", "PHYSICS");
3512
3513 /* Check quantity flags... */
3514 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3515 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3516
3517 /* Loop over particles... */
3518 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
3519
3520 /* Get weighting factor... */
3521 const double w = tropo_weight(clim, atm, ip);
3522
3523 /* Set lifetime... */
3524 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
3525
3526 /* Calculate exponential decay... */
3527 const double aux = exp(-cache->dt[ip] / tdec);
3528 if (ctl->qnt_m >= 0) {
3529 if (ctl->qnt_mloss_decay >= 0)
3530 atm->q[ctl->qnt_mloss_decay][ip]
3531 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3532 atm->q[ctl->qnt_m][ip] *= aux;
3533 if (ctl->qnt_loss_rate >= 0)
3534 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
3535 }
3536 if (ctl->qnt_vmr >= 0)
3537 atm->q[ctl->qnt_vmr][ip] *= aux;
3538 }
3539}
3540
3541/*****************************************************************************/
3542
3544 const ctl_t *ctl,
3545 cache_t *cache,
3546 met_t *met0,
3547 met_t *met1,
3548 atm_t *atm) {
3549
3550 /* Set timer... */
3551 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS");
3552
3553 /* Create random numbers... */
3554 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3555
3556 /* Loop over particles... */
3557 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3558
3559 /* Get indices... */
3560 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
3561 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
3562 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
3563
3564 /* Get standard deviations of local wind data... */
3565 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
3566 for (int i = 0; i < 2; i++)
3567 for (int j = 0; j < 2; j++)
3568 for (int k = 0; k < 2; k++) {
3569 umean += met0->u[ix + i][iy + j][iz + k];
3570 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
3571 vmean += met0->v[ix + i][iy + j][iz + k];
3572 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
3573 wmean += met0->w[ix + i][iy + j][iz + k];
3574 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
3575
3576 umean += met1->u[ix + i][iy + j][iz + k];
3577 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
3578 vmean += met1->v[ix + i][iy + j][iz + k];
3579 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
3580 wmean += met1->w[ix + i][iy + j][iz + k];
3581 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
3582 }
3583 usig = usig / 16.f - SQR(umean / 16.f);
3584 usig = (usig > 0 ? sqrtf(usig) : 0);
3585 vsig = vsig / 16.f - SQR(vmean / 16.f);
3586 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
3587 wsig = wsig / 16.f - SQR(wmean / 16.f);
3588 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
3589
3590 /* Set temporal correlations for mesoscale fluctuations... */
3591 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
3592 const double r2 = sqrt(1 - r * r);
3593
3594 /* Calculate horizontal mesoscale wind fluctuations... */
3595 if (ctl->turb_mesox > 0) {
3596 cache->uvwp[ip][0] =
3597 (float) (r * cache->uvwp[ip][0] +
3598 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
3599 atm->lon[ip] +=
3600 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3601
3602 cache->uvwp[ip][1] =
3603 (float) (r * cache->uvwp[ip][1] +
3604 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
3605 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3606 }
3607
3608 /* Calculate vertical mesoscale wind fluctuations... */
3609 if (ctl->turb_mesoz > 0) {
3610 cache->uvwp[ip][2] =
3611 (float) (r * cache->uvwp[ip][2] +
3612 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
3613 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
3614 }
3615 }
3616}
3617
3618/*****************************************************************************/
3619
3621 const ctl_t *ctl,
3622 cache_t *cache,
3623 met_t *met0,
3624 met_t *met1,
3625 atm_t *atm) {
3626
3627 /* Set timer... */
3628 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS");
3629
3630 /* Create random numbers... */
3631 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3632
3633 /* Loop over particles... */
3634 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3635
3636 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
3637 tau_u = 300., tau_w = 100.;
3638
3639 /* Get surface and PBL pressure... */
3640 double pbl, ps;
3642 INTPOL_2D(ps, 1);
3643 INTPOL_2D(pbl, 0);
3644
3645 /* Boundary layer... */
3646 if (atm->p[ip] >= pbl) {
3647
3648 /* Calculate heights... */
3649 const double p = MIN(atm->p[ip], ps);
3650 const double zs = Z(ps);
3651 const double z = 1e3 * (Z(p) - zs);
3652 const double zi = 1e3 * (Z(pbl) - zs);
3653 const double zratio = z / zi;
3654
3655 /* Calculate friction velocity... */
3656 double ess, nss, h2o, t;
3657 INTPOL_2D(ess, 0);
3658 INTPOL_2D(nss, 0);
3659 INTPOL_3D(t, 1);
3660 INTPOL_3D(h2o, 0);
3661 const double rho = RHO(p, TVIRT(t, h2o));
3662 const double tau = sqrt(SQR(ess) + SQR(nss));
3663 const double ustar = sqrt(tau / rho);
3664
3665 /* Get surface sensible heat flux... */
3666 double shf;
3667 INTPOL_2D(shf, 1);
3668
3669 /* Stable or neutral conditions... */
3670 if (shf <= 0) {
3671
3672 /* Calcalute turbulent velocity variances... */
3673 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
3674 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
3675
3676 /* Calculate derivative dsig_w/dz... */
3677 dsigw_dz = -1.3 * ustar / zi;
3678
3679 /* Calcalute Lagrangian timescales... */
3680 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
3681 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
3682 }
3683
3684 /* Unstable conditions... */
3685 else {
3686
3687 /* Convective velocity... */
3688 const double wstar =
3689 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
3690
3691 /* Calcalute turbulent velocity variances... */
3692 sig_u = 1e-2
3693 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
3694 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
3695 * pow(zratio, 2.0 / 3.0)
3696 + (1.8 - 1.4 * zratio) * SQR(ustar));
3697
3698 /* Calculate derivative dsig_w/dz... */
3699 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
3700 * (0.8 *
3701 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
3702 - 1.8 * pow(zratio, 2.0 / 3.0)));
3703
3704 /* Calculate Lagrangian timescales... */
3705 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
3706 const double eps =
3707 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
3708 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
3709 tau_u = 2 * SQR(sig_u) / (C0 * eps);
3710 tau_w = 2 * SQR(sig_w) / (C0 * eps);
3711 }
3712 }
3713
3714 /* Set minimum values... */
3715 sig_u = MAX(sig_u, 0.25);
3716 sig_w = MAX(sig_w, 0.1);
3717 tau_u = MAX(tau_u, 300.);
3718 tau_w = MAX(tau_w, 100.);
3719
3720 /* Update perturbations... */
3721 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
3722 const double ru2 = sqrt(1.0 - SQR(ru));
3723 cache->uvwp[ip][0]
3724 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
3725 cache->uvwp[ip][1]
3726 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
3727
3728 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
3729 const double rw2 = sqrt(1.0 - SQR(rw));
3730 cache->uvwp[ip][2]
3731 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
3732 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
3733
3734 /* Calculate new air parcel position... */
3735 atm->lon[ip] +=
3736 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
3737 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
3738 atm->p[ip] +=
3739 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
3740 }
3741}
3742
3743/*****************************************************************************/
3744
3746 const ctl_t *ctl,
3747 cache_t *cache,
3748 const clim_t *clim,
3749 met_t *met0,
3750 met_t *met1,
3751 atm_t *atm) {
3752
3753 /* Set timer... */
3754 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS");
3755
3756 /* Create random numbers... */
3757 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3758
3759 /* Loop over particles... */
3760 PARTICLE_LOOP(0, atm->np, 1,
3761 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3762
3763 /* Get PBL and surface pressure... */
3764 double pbl, ps;
3766 INTPOL_2D(pbl, 1);
3767 INTPOL_2D(ps, 0);
3768
3769 /* Get weighting factors... */
3770 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
3771 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
3772 const double wstrat = 1.0 - wpbl - wtrop;
3773
3774 /* Set diffusivity... */
3775 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
3776 + wstrat * ctl->turb_dx_strat;
3777 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
3778 + wstrat * ctl->turb_dz_strat;
3779
3780 /* Horizontal turbulent diffusion... */
3781 if (dx > 0) {
3782 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
3783 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
3784 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
3785 }
3786
3787 /* Vertical turbulent diffusion... */
3788 if (dz > 0) {
3789 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
3790 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
3791 }
3792 }
3793}
3794
3795/*****************************************************************************/
3796
3798 const ctl_t *ctl,
3799 const cache_t *cache,
3800 met_t *met0,
3801 met_t *met1,
3802 atm_t *atm) {
3803
3804 /* Set timer... */
3805 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS");
3806
3807 /* Check quantity flags... */
3808 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3809 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3810
3811 /* Loop over particles... */
3812 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3813
3814 /* Get surface pressure... */
3815 double ps;
3817 INTPOL_2D(ps, 1);
3818
3819 /* Check whether particle is above the surface layer... */
3820 if (atm->p[ip] < ps - ctl->dry_depo_dp)
3821 continue;
3822
3823 /* Set depth of surface layer... */
3824 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
3825
3826 /* Calculate sedimentation velocity for particles... */
3827 double v_dep;
3828 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
3829
3830 /* Get temperature... */
3831 double t;
3832 INTPOL_3D(t, 1);
3833
3834 /* Set deposition velocity... */
3835 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3836 atm->q[ctl->qnt_rhop][ip]);
3837 }
3838
3839 /* Use explicit sedimentation velocity for gases... */
3840 else
3841 v_dep = ctl->dry_depo_vdep;
3842
3843 /* Calculate loss of mass based on deposition velocity... */
3844 const double aux = exp(-cache->dt[ip] * v_dep / dz);
3845 if (ctl->qnt_m >= 0) {
3846 if (ctl->qnt_mloss_dry >= 0)
3847 atm->q[ctl->qnt_mloss_dry][ip]
3848 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3849 atm->q[ctl->qnt_m][ip] *= aux;
3850 if (ctl->qnt_loss_rate >= 0)
3851 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
3852 }
3853 if (ctl->qnt_vmr >= 0)
3854 atm->q[ctl->qnt_vmr][ip] *= aux;
3855 }
3856}
3857
3858/*****************************************************************************/
3859
3861 const ctl_t *ctl,
3862 const cache_t *cache,
3863 const clim_t *clim,
3864 met_t *met0,
3865 met_t *met1,
3866 atm_t *atm) {
3867
3868 /* Set timer... */
3869 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS");
3870
3871 /* Check quantity flags... */
3872 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3873 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3874
3875 /* Parameter of SO2 correction... */
3876 const double a = 3.12541941e-06;
3877 const double b = -5.72532259e-01;
3878 const double low = pow(1. / a, 1. / b);
3879
3880 /* Loop over particles... */
3881 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3882
3883 /* Check whether particle is inside cloud... */
3884 double lwc, rwc;
3886 INTPOL_3D(lwc, 1);
3887 INTPOL_3D(rwc, 0);
3888 if (!(lwc > 0 || rwc > 0))
3889 continue;
3890
3891 /* Get temperature... */
3892 double t;
3893 INTPOL_3D(t, 0);
3894
3895 /* Get molecular density... */
3896 const double M = MOLEC_DENS(atm->p[ip], t);
3897
3898 /* Reaction rate (Berglen et al., 2004)... */
3899 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3900
3901 /* Henry constant of SO2... */
3902 const double H_SO2 =
3903 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3904 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3905
3906 /* Henry constant of H2O2... */
3907 const double H_h2o2 =
3908 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3909
3910 /* Correction factor for high SO2 concentration
3911 (if qnt_Cx is defined, the correction is switched on)... */
3912 double cor = 1.0;
3913 if (ctl->qnt_Cx >= 0)
3914 cor = atm->q[ctl->qnt_Cx][ip] >
3915 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3916
3917 const double h2o2 = H_h2o2
3918 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3919 * M * cor * 1000. / AVO; /* unit: mol/L */
3920
3921 /* Volume water content in cloud [m^3 m^(-3)]... */
3922 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3923 const double CWC = (lwc + rwc) * rho_air / 1e3;
3924
3925 /* Calculate exponential decay (Rolph et al., 1992)... */
3926 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3927 const double aux = exp(-cache->dt[ip] * rate_coef);
3928 if (ctl->qnt_m >= 0) {
3929 if (ctl->qnt_mloss_h2o2 >= 0)
3930 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3931 atm->q[ctl->qnt_m][ip] *= aux;
3932 if (ctl->qnt_loss_rate >= 0)
3933 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3934 }
3935 if (ctl->qnt_vmr >= 0)
3936 atm->q[ctl->qnt_vmr][ip] *= aux;
3937 }
3938}
3939
3940/*****************************************************************************/
3941
3943 const ctl_t *ctl,
3944 cache_t *cache,
3945 met_t *met0,
3946 met_t *met1,
3947 atm_t *atm) {
3948
3949 double t;
3950
3951 /* Set timer... */
3952 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS");
3953
3954 /* Save pressure... */
3955 if (ctl->isosurf == 1) {
3956 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
3957 cache->iso_var[ip] = atm->p[ip];
3958 }
3959 }
3960
3961 /* Save density... */
3962 else if (ctl->isosurf == 2) {
3963 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3965 INTPOL_3D(t, 1);
3966 cache->iso_var[ip] = atm->p[ip] / t;
3967 }
3968 }
3969
3970 /* Save potential temperature... */
3971 else if (ctl->isosurf == 3) {
3972 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3974 INTPOL_3D(t, 1);
3975 cache->iso_var[ip] = THETA(atm->p[ip], t);
3976 }
3977 }
3978
3979 /* Read balloon pressure data... */
3980 else if (ctl->isosurf == 4) {
3981
3982 /* Write info... */
3983 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3984
3985 /* Open file... */
3986 FILE *in;
3987 if (!(in = fopen(ctl->balloon, "r")))
3988 ERRMSG("Cannot open file!");
3989
3990 /* Read pressure time series... */
3991 char line[LEN];
3992 while (fgets(line, LEN, in))
3993 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3994 &(cache->iso_ps[cache->iso_n])) == 2)
3995 if ((++cache->iso_n) > NP)
3996 ERRMSG("Too many data points!");
3997
3998 /* Check number of points... */
3999 if (cache->iso_n < 1)
4000 ERRMSG("Could not read any data!");
4001
4002 /* Close file... */
4003 fclose(in);
4004
4005 /* Update of cache data on device... */
4006 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
4007 }
4008}
4009
4010/*****************************************************************************/
4011
4013 const ctl_t *ctl,
4014 const cache_t *cache,
4015 met_t *met0,
4016 met_t *met1,
4017 atm_t *atm) {
4018
4019 /* Set timer... */
4020 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS");
4021
4022 /* Loop over particles... */
4023 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
4024
4025 /* Init... */
4026 double t;
4028
4029 /* Restore pressure... */
4030 if (ctl->isosurf == 1)
4031 atm->p[ip] = cache->iso_var[ip];
4032
4033 /* Restore density... */
4034 else if (ctl->isosurf == 2) {
4035 INTPOL_3D(t, 1);
4036 atm->p[ip] = cache->iso_var[ip] * t;
4037 }
4038
4039 /* Restore potential temperature... */
4040 else if (ctl->isosurf == 3) {
4041 INTPOL_3D(t, 1);
4042 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
4043 }
4044
4045 /* Interpolate pressure... */
4046 else if (ctl->isosurf == 4) {
4047 if (atm->time[ip] <= cache->iso_ts[0])
4048 atm->p[ip] = cache->iso_ps[0];
4049 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
4050 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
4051 else {
4052 const int idx =
4053 locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
4054 atm->p[ip] =
4055 LIN(cache->iso_ts[idx], cache->iso_ps[idx], cache->iso_ts[idx + 1],
4056 cache->iso_ps[idx + 1], atm->time[ip]);
4057 }
4058 }
4059 }
4060}
4061
4062/*****************************************************************************/
4063
4064#ifdef KPP
4065void module_kpp_chem(
4066 ctl_t *ctl,
4067 cache_t *cache,
4068 clim_t *clim,
4069 met_t *met0,
4070 met_t *met1,
4071 atm_t *atm) {
4072
4073 /* Set timer... */
4074 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS");
4075
4076 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
4077 double rtol[1] = { 1.0e-3 };
4078 double atol[1] = { 1.0 };
4079
4080 /* Loop over particles... */
4081#ifdef _OPENACC
4082#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
4083#endif
4084 PARTICLE_LOOP(0, atm->np, 1,
4085 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
4086
4087 /* Initialize... */
4088 double var[nvar], fix[nfix], rconst[nreact];
4089 for (int i = 0; i < nvar; i++)
4090 var[i] = 0.0;
4091 for (int i = 0; i < nfix; i++)
4092 fix[i] = 0.0;
4093 for (int i = 0; i < nreact; i++)
4094 rconst[i] = 0.0;
4095 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
4096
4097 /* Integrate... */
4098 double rpar[20];
4099 int ipar[20];
4100 for (int i = 0; i < 20; i++) {
4101 ipar[i] = 0;
4102 rpar[i] = 0.0;
4103 }
4104 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) */
4105 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
4106 ipar[3] = 4; /* choice of the method:Rodas3 */
4107 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
4108 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
4109
4110 /* Save results.. */
4111 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
4112 }
4113}
4114#endif
4115
4116/*****************************************************************************/
4117
4119 const ctl_t *ctl,
4120 const cache_t *cache,
4121 const clim_t *clim,
4122 met_t *met0,
4123 met_t *met1,
4124 atm_t *atm) {
4125
4126 /* Set timer... */
4127 SELECT_TIMER("MODULE_METEO", "PHYSICS");
4128
4129 /* Check quantity flags... */
4130 if (ctl->qnt_tsts >= 0)
4131 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
4132 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
4133
4134 /* Loop over particles... */
4135 PARTICLE_LOOP(0, atm->np, 0,
4136 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4137
4138 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
4139 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
4140 o3, lwc, rwc, iwc, swc, cc, z, zt;
4141
4142 /* Interpolate meteo data... */
4144 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
4145
4146 /* Set quantities... */
4147 SET_ATM(qnt_ps, ps);
4148 SET_ATM(qnt_ts, ts);
4149 SET_ATM(qnt_zs, zs);
4150 SET_ATM(qnt_us, us);
4151 SET_ATM(qnt_vs, vs);
4152 SET_ATM(qnt_ess, ess);
4153 SET_ATM(qnt_nss, nss);
4154 SET_ATM(qnt_shf, shf);
4155 SET_ATM(qnt_lsm, lsm);
4156 SET_ATM(qnt_sst, sst);
4157 SET_ATM(qnt_pbl, pbl);
4158 SET_ATM(qnt_pt, pt);
4159 SET_ATM(qnt_tt, tt);
4160 SET_ATM(qnt_zt, zt);
4161 SET_ATM(qnt_h2ot, h2ot);
4162 SET_ATM(qnt_zg, z);
4163 SET_ATM(qnt_p, atm->p[ip]);
4164 SET_ATM(qnt_t, t);
4165 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
4166 SET_ATM(qnt_u, u);
4167 SET_ATM(qnt_v, v);
4168 SET_ATM(qnt_w, w);
4169 SET_ATM(qnt_h2o, h2o);
4170 SET_ATM(qnt_o3, o3);
4171 SET_ATM(qnt_lwc, lwc);
4172 SET_ATM(qnt_rwc, rwc);
4173 SET_ATM(qnt_iwc, iwc);
4174 SET_ATM(qnt_swc, swc);
4175 SET_ATM(qnt_cc, cc);
4176 SET_ATM(qnt_pct, pct);
4177 SET_ATM(qnt_pcb, pcb);
4178 SET_ATM(qnt_cl, cl);
4179 SET_ATM(qnt_plcl, plcl);
4180 SET_ATM(qnt_plfc, plfc);
4181 SET_ATM(qnt_pel, pel);
4182 SET_ATM(qnt_cape, cape);
4183 SET_ATM(qnt_cin, cin);
4184 SET_ATM(qnt_o3c, o3c);
4185 SET_ATM(qnt_hno3,
4186 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
4187 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
4188 atm->lon[ip], atm->lat[ip], atm->p[ip]));
4189 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
4190 atm->lat[ip], atm->p[ip]));
4191 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
4192 atm->lat[ip], atm->p[ip]));
4193 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
4194 atm->lat[ip], atm->p[ip]));
4195 SET_ATM(qnt_vh, sqrt(u * u + v * v));
4196 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
4197 SET_ATM(qnt_psat, PSAT(t));
4198 SET_ATM(qnt_psice, PSICE(t));
4199 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
4200 SET_ATM(qnt_sh, SH(h2o));
4201 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
4202 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
4203 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
4204 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
4205 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
4206 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
4207 SET_ATM(qnt_eta, atm->q[ctl->qnt_eta][ip]);
4208 SET_ATM(qnt_eta_dot, atm->q[ctl->qnt_eta_dot][ip]);
4209 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
4210 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
4211 SET_ATM(qnt_pv, pv);
4212 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
4213 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
4214 SET_ATM(qnt_tnat,
4215 nat_temperature(atm->p[ip], h2o,
4216 clim_zm(&clim->hno3, atm->time[ip],
4217 atm->lat[ip], atm->p[ip])));
4218 SET_ATM(qnt_tsts,
4219 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
4220 }
4221}
4222
4223/*****************************************************************************/
4224
4226 const ctl_t *ctl,
4227 const clim_t *clim,
4228 atm_t *atm,
4229 const double t) {
4230
4231 /* Set timer... */
4232 SELECT_TIMER("MODULE_MIXING", "PHYSICS");
4233
4234 /* Allocate... */
4235 const int np = atm->np;
4236 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
4237 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
4238 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
4239
4240 /* Set grid box size... */
4241 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
4242 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
4243 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
4244
4245 /* Set time interval... */
4246 const double t0 = t - 0.5 * ctl->dt_mod;
4247 const double t1 = t + 0.5 * ctl->dt_mod;
4248
4249 /* Get indices... */
4250#ifdef _OPENACC
4251#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
4252#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
4253#pragma acc parallel loop independent gang vector
4254#else
4255#pragma omp parallel for default(shared)
4256#endif
4257 for (int ip = 0; ip < np; ip++) {
4258 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
4259 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
4260 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
4261 if (atm->time[ip] < t0 || atm->time[ip] > t1
4262 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
4263 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
4264 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
4265 izs[ip] = -1;
4266 }
4267
4268 /* Calculate interparcel mixing... */
4269 const int use_ensemble = (ctl->nens > 0);
4270
4271 const int quantities[] = {
4272 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
4273 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
4274 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
4275 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
4276 ctl->qnt_Csf6, ctl->qnt_aoa, ctl->qnt_Arn222, ctl->qnt_Apb210,
4277 ctl->qnt_Abe7, ctl->qnt_Acs137, ctl->qnt_Ai131, ctl->qnt_Axe133
4278 };
4279 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
4280
4281 for (int i = 0; i < n_qnt; i++)
4282 if (quantities[i] >= 0)
4283 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
4284 use_ensemble);
4285
4286 /* Free... */
4287#ifdef _OPENACC
4288#pragma acc exit data delete(ixs,iys,izs)
4289#endif
4290 free(ixs);
4291 free(iys);
4292 free(izs);
4293}
4294
4295/*****************************************************************************/
4296
4298 const ctl_t *ctl,
4299 const clim_t *clim,
4300 atm_t *atm,
4301 const int *ixs,
4302 const int *iys,
4303 const int *izs,
4304 const int qnt_idx,
4305 const int use_ensemble) {
4306
4307 const int np = atm->np;
4308 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
4309 const int nens = use_ensemble ? ctl->nens : 1;
4310 const int total_grid = ngrid * nens;
4311
4312 double *restrict const cmean =
4313 (double *) malloc((size_t) total_grid * sizeof(double));
4314 int *restrict const count =
4315 (int *) malloc((size_t) total_grid * sizeof(int));
4316
4317 /* Init... */
4318#ifdef _OPENACC
4319#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
4320#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
4321#pragma acc parallel loop independent gang vector
4322#else
4323#ifdef __NVCOMPILER
4324#pragma novector
4325#endif
4326#pragma omp parallel for
4327#endif
4328 for (int i = 0; i < total_grid; i++) {
4329 count[i] = 0;
4330 cmean[i] = 0.0;
4331 }
4332
4333 /* Loop over particles... */
4334#ifdef _OPENACC
4335#pragma acc parallel loop independent gang vector
4336#endif
4337 for (int ip = 0; ip < np; ip++)
4338 if (izs[ip] >= 0) {
4339 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4340 const int idx =
4341 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4342 ctl->mixing_nz);
4343#ifdef _OPENACC
4344#pragma acc atomic update
4345#endif
4346 cmean[idx] += atm->q[qnt_idx][ip];
4347#ifdef _OPENACC
4348#pragma acc atomic update
4349#endif
4350 count[idx]++;
4351 }
4352
4353 /* Compute means... */
4354#ifdef _OPENACC
4355#pragma acc parallel loop independent gang vector
4356#else
4357#ifdef __NVCOMPILER
4358#pragma novector
4359#endif
4360#pragma omp parallel for
4361#endif
4362 for (int i = 0; i < total_grid; i++)
4363 if (count[i] > 0)
4364 cmean[i] /= count[i];
4365
4366 /* Interparcel mixing... */
4367#ifdef _OPENACC
4368#pragma acc parallel loop independent gang vector
4369#else
4370#pragma omp parallel for
4371#endif
4372 for (int ip = 0; ip < np; ip++) {
4373 if (izs[ip] >= 0) {
4374 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
4375
4376 double mixparam = 1.0;
4377 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
4378 const double w = tropo_weight(clim, atm, ip);
4379 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
4380 }
4381
4382 const int idx =
4383 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
4384 ctl->mixing_nz);
4385 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
4386 }
4387 }
4388
4389 /* Free... */
4390#ifdef _OPENACC
4391#pragma acc exit data delete(cmean,count)
4392#endif
4393 free(cmean);
4394 free(count);
4395}
4396
4397/*****************************************************************************/
4398
4400 const ctl_t *ctl,
4401 const cache_t *cache,
4402 const clim_t *clim,
4403 met_t *met0,
4404 met_t *met1,
4405 atm_t *atm) {
4406
4407 /* Set timer... */
4408 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS");
4409
4410 /* Check quantity flags... */
4411 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4412 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4413
4414 /* Parameter of SO2 correction... */
4415 const double a = 4.71572206e-08;
4416 const double b = -8.28782867e-01;
4417 const double low = pow(1. / a, 1. / b);
4418
4419 /* Loop over particles... */
4420 PARTICLE_LOOP(0, atm->np, 1,
4421 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4422
4423 /* Get temperature... */
4424 double t;
4426 INTPOL_3D(t, 1);
4427
4428 /* Calculate molecular density... */
4429 const double M = MOLEC_DENS(atm->p[ip], t);
4430
4431 /* Use constant reaction rate... */
4432 double k = NAN;
4433 if (ctl->oh_chem_reaction == 1)
4434 k = ctl->oh_chem[0];
4435
4436 /* Calculate bimolecular reaction rate... */
4437 else if (ctl->oh_chem_reaction == 2)
4438 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
4439
4440 /* Calculate termolecular reaction rate... */
4441 if (ctl->oh_chem_reaction == 3) {
4442
4443 /* Calculate rate coefficient for X + OH + M -> XOH + M
4444 (JPL Publication 19-05) ... */
4445 const double k0 =
4446 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
4447 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
4448 const double ki =
4449 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
4450 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
4451 const double c = log10(k0 * M / ki);
4452 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
4453 }
4454
4455 /* Correction factor for high SO2 concentration
4456 (if qnt_Cx is defined, the correction is switched on)... */
4457 double cor = 1;
4458 if (ctl->qnt_Cx >= 0)
4459 cor =
4460 atm->q[ctl->qnt_Cx][ip] >
4461 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
4462
4463 /* Calculate exponential decay... */
4464 const double rate_coef =
4465 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
4466 atm->lat[ip], atm->p[ip]) * M * cor;
4467 const double aux = exp(-cache->dt[ip] * rate_coef);
4468 if (ctl->qnt_m >= 0) {
4469 if (ctl->qnt_mloss_oh >= 0)
4470 atm->q[ctl->qnt_mloss_oh][ip]
4471 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4472 atm->q[ctl->qnt_m][ip] *= aux;
4473 if (ctl->qnt_loss_rate >= 0)
4474 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
4475 }
4476 if (ctl->qnt_vmr >= 0)
4477 atm->q[ctl->qnt_vmr][ip] *= aux;
4478 }
4479}
4480
4481/*****************************************************************************/
4482
4484 const cache_t *cache,
4485 met_t *met0,
4486 met_t *met1,
4487 atm_t *atm) {
4488
4489 /* Set timer... */
4490 SELECT_TIMER("MODULE_POSITION", "PHYSICS");
4491
4492 /* Loop over particles... */
4493 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
4494
4495 /* Init... */
4496 double ps;
4498
4499 /* Calculate modulo... */
4500 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
4501 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
4502
4503 /* Check latitude... */
4504 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
4505 if (atm->lat[ip] > 90) {
4506 atm->lat[ip] = 180 - atm->lat[ip];
4507 atm->lon[ip] += 180;
4508 }
4509 if (atm->lat[ip] < -90) {
4510 atm->lat[ip] = -180 - atm->lat[ip];
4511 atm->lon[ip] += 180;
4512 }
4513 }
4514
4515 /* Check longitude... */
4516 while (atm->lon[ip] < -180)
4517 atm->lon[ip] += 360;
4518 while (atm->lon[ip] >= 180)
4519 atm->lon[ip] -= 360;
4520
4521 /* Check pressure... */
4522 if (atm->p[ip] < met0->p[met0->np - 1]) {
4523 atm->p[ip] = met0->p[met0->np - 1];
4524 } else if (atm->p[ip] > 300.) {
4525 INTPOL_2D(ps, 1);
4526 if (atm->p[ip] > ps)
4527 atm->p[ip] = ps;
4528 }
4529 }
4530}
4531
4532/*****************************************************************************/
4533
4535 const ctl_t *ctl,
4536 const cache_t *cache,
4537 atm_t *atm) {
4538
4539 /* Set timer... */
4540 SELECT_TIMER("MODULE_RADIO_DECAY", "PHYSICS");
4541
4542 /* Set decay constants of radioactive species [s^-1]... */
4543 const double lambda_rn222 = log(2.0) / (3.8235 * 86400.0);
4544 const double lambda_pb210 = log(2.0) / (22.3 * 365.25 * 86400.0);
4545 const double lambda_be7 = log(2.0) / (53.22 * 86400.0);
4546 const double lambda_cs137 = log(2.0) / (30.05 * 365.25 * 86400.0);
4547 const double lambda_i131 = log(2.0) / (8.02 * 86400.0);
4548 const double lambda_xe133 = log(2.0) / (5.2474 * 86400.0);
4549
4550 /* Loop over particles... */
4551 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,atm)") {
4552
4553 /* Set timestep... */
4554 const double dt = cache->dt[ip];
4555
4556 /* Loss for Pb-210... */
4557 if (ctl->qnt_Apb210 >= 0)
4558 atm->q[ctl->qnt_Apb210][ip] *= exp(-dt * lambda_pb210);
4559
4560 /* Loss for Rn-222... */
4561 if (ctl->qnt_Arn222 >= 0) {
4562 const double old = atm->q[ctl->qnt_Arn222][ip];
4563 const double aux = exp(-dt * lambda_rn222);
4564 const double lost = old * (1.0 - aux);
4565 atm->q[ctl->qnt_Arn222][ip] = old * aux;
4566
4567 /* Parent-daughter process for Pb-210... */
4568 if (ctl->qnt_Apb210 >= 0)
4569 atm->q[ctl->qnt_Apb210][ip] += lost * lambda_pb210 / lambda_rn222;
4570 }
4571
4572 /* Loss for Be-7... */
4573 if (ctl->qnt_Abe7 >= 0)
4574 atm->q[ctl->qnt_Abe7][ip] *= exp(-dt * lambda_be7);
4575
4576 /* Loss for Cs-137... */
4577 if (ctl->qnt_Acs137 >= 0)
4578 atm->q[ctl->qnt_Acs137][ip] *= exp(-dt * lambda_cs137);
4579
4580 /* Loss for I-131... */
4581 if (ctl->qnt_Ai131 >= 0)
4582 atm->q[ctl->qnt_Ai131][ip] *= exp(-dt * lambda_i131);
4583
4584 /* Loss for Xe-133... */
4585 if (ctl->qnt_Axe133 >= 0)
4586 atm->q[ctl->qnt_Axe133][ip] *= exp(-dt * lambda_xe133);
4587 }
4588}
4589
4590/*****************************************************************************/
4591
4593 const int ntask) {
4594
4595 /* Initialize GSL random number generators... */
4596 gsl_rng_env_setup();
4597 if (omp_get_max_threads() > NTHREADS)
4598 ERRMSG("Too many threads!");
4599 for (int i = 0; i < NTHREADS; i++) {
4600 rng[i] = gsl_rng_alloc(gsl_rng_default);
4601 gsl_rng_set(rng[i], gsl_rng_default_seed
4602 + (long unsigned) (ntask * NTHREADS + i));
4603 }
4604
4605 /* Initialize cuRAND random number generators... */
4606#ifdef CURAND
4607 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
4608 CURAND_STATUS_SUCCESS)
4609 ERRMSG("Cannot create random number generator!");
4610 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
4611 CURAND_STATUS_SUCCESS)
4612 ERRMSG("Cannot set seed for random number generator!");
4613 if (curandSetStream
4614 (rng_curand,
4615 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
4616 CURAND_STATUS_SUCCESS)
4617 ERRMSG("Cannot set stream for random number generator!");
4618#endif
4619}
4620
4621/*****************************************************************************/
4622
4624 const ctl_t *ctl,
4625 double *rs,
4626 const size_t n,
4627 const int method) {
4628
4629 /* Use GSL random number generators... */
4630 if (ctl->rng_type == 0) {
4631
4632 /* Uniform distribution... */
4633 if (method == 0) {
4634#pragma omp parallel for default(shared)
4635 for (size_t i = 0; i < n; ++i)
4636 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
4637 }
4638
4639 /* Normal distribution... */
4640 else if (method == 1) {
4641#pragma omp parallel for default(shared)
4642 for (size_t i = 0; i < n; ++i)
4643 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
4644 }
4645
4646 /* Update of random numbers on device... */
4647#ifdef _OPENACC
4648 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
4649#pragma acc update device(rs[:n])
4650#endif
4651 }
4652
4653 /* Use Squares random number generator (Widynski, 2022)... */
4654 else if (ctl->rng_type == 1) {
4655
4656 /* Set key (don't change this!)... */
4657 const uint64_t key = 0xc8e4fd154ce32f6d;
4658
4659 /* Uniform distribution... */
4660#ifdef _OPENACC
4661#pragma acc data present(rs)
4662#pragma acc parallel loop independent gang vector
4663#else
4664#pragma omp parallel for default(shared)
4665#endif
4666 for (size_t i = 0; i < n + 1; ++i) {
4667 uint64_t r, t, x, y, z;
4668 y = x = (rng_ctr + i) * key;
4669 z = y + key;
4670 x = x * x + y;
4671 x = (x >> 32) | (x << 32);
4672 x = x * x + z;
4673 x = (x >> 32) | (x << 32);
4674 x = x * x + y;
4675 x = (x >> 32) | (x << 32);
4676 t = x = x * x + z;
4677 x = (x >> 32) | (x << 32);
4678 r = t ^ ((x * x + y) >> 32);
4679 rs[i] = (double) r / (double) UINT64_MAX;
4680 }
4681 rng_ctr += n + 1;
4682
4683 /* Normal distribution... */
4684 if (method == 1) {
4685#ifdef _OPENACC
4686#pragma acc parallel loop independent gang vector
4687#else
4688#pragma omp parallel for default(shared)
4689#endif
4690 for (size_t i = 0; i < n; i += 2) {
4691 const double r = sqrt(-2.0 * log(rs[i]));
4692 const double phi = 2.0 * M_PI * rs[i + 1];
4693 rs[i] = r * cosf((float) phi);
4694 rs[i + 1] = r * sinf((float) phi);
4695 }
4696 }
4697 }
4698
4699 /* Use cuRAND random number generators... */
4700 else if (ctl->rng_type == 2) {
4701#ifdef CURAND
4702#pragma acc host_data use_device(rs)
4703 {
4704
4705 /* Uniform distribution... */
4706 if (method == 0) {
4707 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
4708 CURAND_STATUS_SUCCESS)
4709 ERRMSG("Cannot create random numbers!");
4710 }
4711
4712 /* Normal distribution... */
4713 else if (method == 1) {
4714 if (curandGenerateNormalDouble
4715 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
4716 1.0) != CURAND_STATUS_SUCCESS)
4717 ERRMSG("Cannot create random numbers!");
4718 }
4719 }
4720#else
4721 ERRMSG("MPTRAC was compiled without cuRAND!");
4722#endif
4723 }
4724}
4725
4726/*****************************************************************************/
4727
4729 const ctl_t *ctl,
4730 const cache_t *cache,
4731 met_t *met0,
4732 met_t *met1,
4733 atm_t *atm) {
4734
4735 /* Set timer... */
4736 SELECT_TIMER("MODULE_SEDI", "PHYSICS");
4737
4738 /* Loop over particles... */
4739 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4740
4741 /* Get temperature... */
4742 double t;
4744 INTPOL_3D(t, 1);
4745
4746 /* Sedimentation velocity... */
4747 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
4748 atm->q[ctl->qnt_rhop][ip]);
4749
4750 /* Calculate pressure change... */
4751 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
4752 }
4753}
4754
4755/*****************************************************************************/
4756
4758 const ctl_t *ctl,
4759 met_t *met0,
4760 atm_t *atm) {
4761
4762 /* Set timer... */
4763 SELECT_TIMER("MODULE_SORT", "PHYSICS");
4764
4765 /* Allocate... */
4766 const int np = atm->np;
4767 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
4768 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
4769 if (a == NULL || p == NULL)
4770 ERRMSG("Out of memory!");
4771
4772#ifdef _OPENACC
4773#pragma acc enter data create(a[0:np],p[0:np])
4774#pragma acc data present(ctl,met0,atm,a,p)
4775#endif
4776
4777 /* Get box index... */
4778#ifdef _OPENACC
4779#pragma acc parallel loop independent gang vector
4780#else
4781#pragma omp parallel for default(shared)
4782#endif
4783 for (int ip = 0; ip < np; ip++) {
4784 a[ip] =
4785 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
4786 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
4787 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
4788 p[ip] = ip;
4789 }
4790
4791 /* Sorting... */
4792#ifdef THRUST
4793#ifdef _OPENACC
4794#pragma acc host_data use_device(a,p)
4795#endif
4796 thrustSortWrapper(a, np, p);
4797#else
4798#ifdef _OPENACC
4799 ERRMSG("GSL sort fallback not available on GPU, use THRUST!");
4800#endif
4801 gsl_sort_index((size_t *) p, a, 1, (size_t) np);
4802#endif
4803
4804 /* Sort data... */
4805 module_sort_help(atm->time, p, np);
4806 module_sort_help(atm->p, p, np);
4807 module_sort_help(atm->lon, p, np);
4808 module_sort_help(atm->lat, p, np);
4809 for (int iq = 0; iq < ctl->nq; iq++)
4810 module_sort_help(atm->q[iq], p, np);
4811
4812 /* Free... */
4813#ifdef _OPENACC
4814#pragma acc exit data delete(a,p)
4815#endif
4816 free(a);
4817 free(p);
4818}
4819
4820/*****************************************************************************/
4821
4823 double *a,
4824 const int *p,
4825 const int np) {
4826
4827 /* Allocate... */
4828 double *restrict const help =
4829 (double *) malloc((size_t) np * sizeof(double));
4830 if (help == NULL)
4831 ERRMSG("Out of memory!");
4832
4833 /* Reordering of array... */
4834#ifdef _OPENACC
4835#pragma acc enter data create(help[0:np])
4836#pragma acc data present(a,p,help)
4837#pragma acc parallel loop independent gang vector
4838#else
4839#pragma omp parallel for default(shared)
4840#endif
4841 for (int ip = 0; ip < np; ip++)
4842 help[ip] = a[p[ip]];
4843#ifdef _OPENACC
4844#pragma acc parallel loop independent gang vector
4845#else
4846#pragma omp parallel for default(shared)
4847#endif
4848 for (int ip = 0; ip < np; ip++)
4849 a[ip] = help[ip];
4850
4851 /* Free... */
4852#ifdef _OPENACC
4853#pragma acc exit data delete(help)
4854#endif
4855 free(help);
4856}
4857
4858/*****************************************************************************/
4859
4861 const ctl_t *ctl,
4862 cache_t *cache,
4863 met_t *met0,
4864 atm_t *atm,
4865 const double t) {
4866
4867 /* Set timer... */
4868 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS");
4869
4870 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
4871 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
4872
4873 const int local =
4874 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
4875
4876 /* Loop over particles... */
4877 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
4878
4879 /* Set time step for each air parcel... */
4880 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
4881 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
4882 && ctl->direction * (atm->time[ip] - t) < 0))
4883 cache->dt[ip] = t - atm->time[ip];
4884 else
4885 cache->dt[ip] = 0.0;
4886
4887 /* Check horizontal boundaries of local meteo data... */
4888#ifndef DD
4889 int dd = 1;
4890#else
4891 int dd = 0;
4892#endif
4893 if (dd) {
4894 if (local && (atm->lon[ip] <= met0->lon[0]
4895 || atm->lon[ip] >= met0->lon[met0->nx - 1]
4896 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
4897 cache->dt[ip] = 0.0;
4898 } else {
4899 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
4900 cache->dt[ip] = 0;
4901 }
4902 }
4903}
4904
4905/*****************************************************************************/
4906
4908 ctl_t *ctl,
4909 const atm_t *atm) {
4910
4911 /* Set timer... */
4912 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS");
4913
4914 /* Set start time... */
4915 if (ctl->direction == 1) {
4916 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4917 if (ctl->t_stop > 1e99)
4918 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4919 } else {
4920 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4921 if (ctl->t_stop > 1e99)
4922 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4923 }
4924
4925 /* Check time interval... */
4926 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
4927 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
4928
4929 /* Round start time... */
4930 if (ctl->direction == 1)
4931 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4932 else
4933 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4934}
4935
4936/*****************************************************************************/
4937
4939 const ctl_t *ctl,
4940 const cache_t *cache,
4941 const clim_t *clim,
4942 met_t *met0,
4943 met_t *met1,
4944 atm_t *atm) {
4945
4946 /* Set timer... */
4947 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS");
4948
4949 /* Loop over particles... */
4950 PARTICLE_LOOP(0, atm->np, 1,
4951 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4952
4953 /* Get temperature... */
4954 double t;
4956 INTPOL_3D(t, 1);
4957
4958 /* Get molecular density... */
4959 const double M = MOLEC_DENS(atm->p[ip], t);
4960
4961 /* Get total column ozone... */
4962 double o3c;
4963 INTPOL_2D(o3c, 1);
4964
4965 /* Get solar zenith angle... */
4966 const double sza =
4967 acos(cos_sza(atm->time[ip], atm->lon[ip], atm->lat[ip]));
4968
4969 /* Get O(1D) volume mixing ratio... */
4970 const double o1d =
4971 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4972
4973 /* Reactions for CFC-10... */
4974 if (ctl->qnt_Cccl4 >= 0) {
4975 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4976 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4977 atm->p[ip], sza, o3c);
4978 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4979 }
4980
4981 /* Reactions for CFC-11... */
4982 if (ctl->qnt_Cccl3f >= 0) {
4983 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4984 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4985 atm->p[ip], sza, o3c);
4986 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4987 }
4988
4989 /* Reactions for CFC-12... */
4990 if (ctl->qnt_Cccl2f2 >= 0) {
4991 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4992 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4993 atm->p[ip], sza, o3c);
4994 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4995 }
4996
4997 /* Reactions for N2O... */
4998 if (ctl->qnt_Cn2o >= 0) {
4999 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
5000 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
5001 atm->p[ip], sza, o3c);
5002 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
5003 }
5004 }
5005}
5006
5007/*****************************************************************************/
5008
5010 const ctl_t *ctl,
5011 const cache_t *cache,
5012 met_t *met0,
5013 met_t *met1,
5014 atm_t *atm) {
5015
5016 /* Set timer... */
5017 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS");
5018
5019 /* Check quantity flags... */
5020 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
5021 ERRMSG("Module needs quantity mass or volume mixing ratio!");
5022
5023 /* Loop over particles... */
5024 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
5025
5026 /* Check whether particle is below cloud top... */
5027 double pct;
5029 INTPOL_2D(pct, 1);
5030 if (!isfinite(pct) || atm->p[ip] <= pct)
5031 continue;
5032
5033 /* Get cloud bottom pressure... */
5034 double pcb;
5035 INTPOL_2D(pcb, 0);
5036
5037 /* Estimate precipitation rate (Pisso et al., 2019)... */
5038 double cl;
5039 INTPOL_2D(cl, 0);
5040 const double Is =
5041 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
5042 if (Is < 0.01)
5043 continue;
5044
5045 /* Check whether particle is inside or below cloud... */
5046 double lwc, rwc, iwc, swc;
5047 INTPOL_3D(lwc, 1);
5048 INTPOL_3D(rwc, 0);
5049 INTPOL_3D(iwc, 0);
5050 INTPOL_3D(swc, 0);
5051 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
5052
5053 /* Get temperature... */
5054 double t;
5055 INTPOL_3D(t, 0);
5056
5057 /* Calculate in-cloud scavenging coefficient... */
5058 double lambda = 0;
5059 if (inside) {
5060
5061 /* Calculate retention factor... */
5062 double eta;
5063 if (t > 273.15)
5064 eta = 1;
5065 else if (t <= 238.15)
5066 eta = ctl->wet_depo_ic_ret_ratio;
5067 else
5068 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
5069
5070 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5071 if (ctl->wet_depo_ic_a > 0)
5072 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
5073
5074 /* Use Henry's law for gases... */
5075 else if (ctl->wet_depo_ic_h[0] > 0) {
5076
5077 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5078 double h = ctl->wet_depo_ic_h[0]
5079 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
5080
5081 /* Use effective Henry's constant for SO2
5082 (Berglen, 2004; Simpson, 2012)... */
5083 if (ctl->wet_depo_so2_ph > 0) {
5084 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
5085 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
5086 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
5087 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
5088 }
5089
5090 /* Estimate depth of cloud layer... */
5091 const double dz = 1e3 * (Z(pct) - Z(pcb));
5092
5093 /* Calculate scavenging coefficient... */
5094 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5095 }
5096 }
5097
5098 /* Calculate below-cloud scavenging coefficient... */
5099 else {
5100
5101 /* Calculate retention factor... */
5102 double eta;
5103 if (t > 270)
5104 eta = 1;
5105 else
5106 eta = ctl->wet_depo_bc_ret_ratio;
5107
5108 /* Use exponential dependency for particles (Bakels et al., 2024)... */
5109 if (ctl->wet_depo_bc_a > 0)
5110 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
5111
5112 /* Use Henry's law for gases... */
5113 else if (ctl->wet_depo_bc_h[0] > 0) {
5114
5115 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
5116 const double h = ctl->wet_depo_bc_h[0]
5117 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
5118
5119 /* Estimate depth of cloud layer... */
5120 const double dz = 1e3 * (Z(pct) - Z(pcb));
5121
5122 /* Calculate scavenging coefficient... */
5123 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
5124 }
5125 }
5126
5127 /* Calculate exponential decay of mass... */
5128 const double aux = exp(-cache->dt[ip] * lambda);
5129 if (ctl->qnt_m >= 0) {
5130 if (ctl->qnt_mloss_wet >= 0)
5131 atm->q[ctl->qnt_mloss_wet][ip]
5132 += atm->q[ctl->qnt_m][ip] * (1 - aux);
5133 atm->q[ctl->qnt_m][ip] *= aux;
5134 if (ctl->qnt_loss_rate >= 0)
5135 atm->q[ctl->qnt_loss_rate][ip] += lambda;
5136 }
5137 if (ctl->qnt_vmr >= 0)
5138 atm->q[ctl->qnt_vmr][ip] *= aux;
5139 }
5140}
5141
5142/*****************************************************************************/
5143
5145 ctl_t **ctl,
5146 cache_t **cache,
5147 clim_t **clim,
5148 met_t **met0,
5149 met_t **met1,
5150 atm_t **atm,
5151 dd_t **dd) {
5152
5153 /* Initialize GPU... */
5154#ifdef _OPENACC
5155 SELECT_TIMER("ACC_INIT", "INIT");
5156 int rank = 0;
5157#ifdef MPI
5158 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5159#endif
5160 if (acc_get_num_devices(acc_device_nvidia) <= 0)
5161 ERRMSG("Not running on a GPU device!");
5162 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
5163 acc_device_nvidia);
5164 acc_device_t device_type = acc_get_device_type();
5165 acc_init(device_type);
5166#endif
5167
5168 /* Allocate... */
5169 SELECT_TIMER("ALLOC", "MEMORY");
5170 ALLOC(*ctl, ctl_t, 1);
5171 ALLOC(*cache, cache_t, 1);
5172 ALLOC(*clim, clim_t, 1);
5173 ALLOC(*met0, met_t, 1);
5174 ALLOC(*met1, met_t, 1);
5175 ALLOC(*atm, atm_t, 1);
5176 ALLOC(*dd, dd_t, 1);
5177
5178 /* Create data region on GPU... */
5179#ifdef _OPENACC
5180 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY");
5181 ctl_t *ctlup = *ctl;
5182 cache_t *cacheup = *cache;
5183 clim_t *climup = *clim;
5184 met_t *met0up = *met0;
5185 met_t *met1up = *met1;
5186 atm_t *atmup = *atm;
5187#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
5188#ifdef DD
5189 dd_t *ddup = *dd;
5190#pragma acc enter data create(ddup[:1])
5191#endif
5192#endif
5193}
5194
5195/*****************************************************************************/
5196
5198 ctl_t *ctl,
5199 cache_t *cache,
5200 clim_t *clim,
5201 met_t *met0,
5202 met_t *met1,
5203 atm_t *atm,
5204 dd_t *dd) {
5205
5206 /* Delete data region on GPU... */
5207#ifdef _OPENACC
5208 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY");
5209#pragma acc exit data delete (ctl,cache,clim,met0,met1,atm)
5210#endif
5211
5212 /* Free... */
5213 SELECT_TIMER("FREE", "MEMORY");
5214 free(atm);
5215 free(ctl);
5216 free(cache);
5217 free(clim);
5218 free(met0);
5219 free(met1);
5220
5221 /* Free MPI datatype... */
5222#ifdef DD
5223 MPI_Type_free(&dd->MPI_Particle);
5224#endif
5225 free(dd);
5226}
5227
5228/*****************************************************************************/
5229
5231 ctl_t *ctl,
5232 clim_t *clim,
5233 const double t,
5234 met_t **met0,
5235 met_t **met1,
5236 dd_t *dd) {
5237
5238 static int init;
5239
5240 met_t *mets;
5241
5242 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
5243
5244 /* Set timer... */
5245 SELECT_TIMER("GET_MET", "INPUT");
5246
5247 /* Init... */
5248 if (t == ctl->t_start || !init) {
5249 init = 1;
5250
5251 /* Read meteo data... */
5252 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
5253 ctl->metbase, ctl->dt_met, filename);
5254 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5255 ERRMSG("Cannot open file!");
5256
5257 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
5258 ctl->metbase, ctl->dt_met, filename);
5259 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5260 ERRMSG("Cannot open file!");
5261
5262 /* Update GPU... */
5263 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
5264 SELECT_TIMER("GET_MET", "INPUT");
5265
5266 /* Caching... */
5267 if (ctl->met_cache && t != ctl->t_stop) {
5268 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
5269 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
5270 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5271 LOG(1, "Caching: %s", cachefile);
5272 if (system(cmd) != 0)
5273 WARN("Caching command failed!");
5274 }
5275 }
5276
5277 /* Read new data for forward trajectories... */
5278 if (t > (*met1)->time) {
5279
5280 /* Pointer swap... */
5281 mets = *met1;
5282 *met1 = *met0;
5283 *met0 = mets;
5284
5285 /* Read new meteo data... */
5286 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
5287 if (!mptrac_read_met(filename, ctl, clim, *met1, dd))
5288 ERRMSG("Cannot open file!");
5289
5290 /* Update GPU... */
5291 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
5292 SELECT_TIMER("GET_MET", "INPUT");
5293
5294 /* Caching... */
5295 if (ctl->met_cache && t != ctl->t_stop) {
5296 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
5297 cachefile);
5298 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5299 LOG(1, "Caching: %s", cachefile);
5300 if (system(cmd) != 0)
5301 WARN("Caching command failed!");
5302 }
5303 }
5304
5305 /* Read new data for backward trajectories... */
5306 if (t < (*met0)->time) {
5307
5308 /* Pointer swap... */
5309 mets = *met1;
5310 *met1 = *met0;
5311 *met0 = mets;
5312
5313 /* Read new meteo data... */
5314 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
5315 if (!mptrac_read_met(filename, ctl, clim, *met0, dd))
5316 ERRMSG("Cannot open file!");
5317
5318 /* Update GPU... */
5319 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
5320 SELECT_TIMER("GET_MET", "INPUT");
5321
5322 /* Caching... */
5323 if (ctl->met_cache && t != ctl->t_stop) {
5324 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
5325 cachefile);
5326 sprintf(cmd, "cat %s > /dev/null &", cachefile);
5327 LOG(1, "Caching: %s", cachefile);
5328 if (system(cmd) != 0)
5329 WARN("Caching command failed!");
5330 }
5331 }
5332
5333 /* Check that grids are consistent... */
5334 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
5335 if ((*met0)->nx != (*met1)->nx
5336 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
5337 ERRMSG("Meteo grid dimensions do not match!");
5338 for (int ix = 0; ix < (*met0)->nx; ix++)
5339 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
5340 ERRMSG("Meteo grid longitudes do not match!");
5341 for (int iy = 0; iy < (*met0)->ny; iy++)
5342 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
5343 ERRMSG("Meteo grid latitudes do not match!");
5344 for (int ip = 0; ip < (*met0)->np; ip++)
5345 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
5346 ERRMSG("Meteo grid pressure levels do not match!");
5347 }
5348}
5349
5350/*****************************************************************************/
5351
5353 ctl_t *ctl,
5354 cache_t *cache,
5355 clim_t *clim,
5356 atm_t *atm,
5357 const int ntask) {
5358
5359 /* Initialize timesteps... */
5360 module_timesteps_init(ctl, atm);
5361
5362 /* Initialize random number generator... */
5363 module_rng_init(ntask);
5364
5365 /* Update GPU memory... */
5366 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
5367}
5368
5369/*****************************************************************************/
5370
5372 const char *filename,
5373 const ctl_t *ctl,
5374 atm_t *atm) {
5375
5376 int result;
5377
5378 /* Set timer... */
5379 SELECT_TIMER("READ_ATM", "INPUT");
5380
5381 /* Init... */
5382 atm->np = 0;
5383
5384 /* Write info... */
5385 LOG(1, "Read atmospheric data: %s", filename);
5386
5387 /* Read ASCII data... */
5388 if (ctl->atm_type == 0)
5389 result = read_atm_asc(filename, ctl, atm);
5390
5391 /* Read binary data... */
5392 else if (ctl->atm_type == 1)
5393 result = read_atm_bin(filename, ctl, atm);
5394
5395 /* Read netCDF data... */
5396 else if (ctl->atm_type == 2)
5397 result = read_atm_nc(filename, ctl, atm);
5398
5399 /* Read CLaMS data... */
5400 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
5401 result = read_atm_clams(filename, ctl, atm);
5402
5403 /* Error... */
5404 else
5405 ERRMSG("Atmospheric data type not supported!");
5406
5407 /* Check result... */
5408 if (result != 1)
5409 return 0;
5410
5411 /* Check number of air parcels... */
5412 if (atm->np < 1)
5413 ERRMSG("Can not read any data!");
5414
5415 /* Write info... */
5416 double mini, maxi;
5417 LOG(2, "Number of particles: %d", atm->np);
5418 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5419 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5420 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5421 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5422 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5423 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5424 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5425 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5426 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5427 for (int iq = 0; iq < ctl->nq; iq++) {
5428 char msg[5 * LEN];
5429 sprintf(msg, "Quantity %s range: %s ... %s %s",
5430 ctl->qnt_name[iq], ctl->qnt_format[iq],
5431 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5432 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5433 LOG(2, msg, mini, maxi);
5434 }
5435
5436 /* Return success... */
5437 return 1;
5438}
5439
5440/*****************************************************************************/
5441
5443 const ctl_t *ctl,
5444 clim_t *clim) {
5445
5446 /* Set timer... */
5447 SELECT_TIMER("READ_CLIM", "INPUT");
5448
5449 /* Init tropopause climatology... */
5450 clim_tropo_init(clim);
5451
5452 /* Read photolysis rates... */
5453 if (ctl->clim_photo[0] != '-')
5454 read_clim_photo(ctl->clim_photo, &clim->photo);
5455
5456 /* Read HNO3 climatology... */
5457 if (ctl->clim_hno3_filename[0] != '-')
5458 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
5459
5460 /* Read OH climatology... */
5461 if (ctl->clim_oh_filename[0] != '-') {
5462 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
5463 if (ctl->oh_chem_beta > 0)
5464 clim_oh_diurnal_correction(ctl, clim);
5465 }
5466
5467 /* Read H2O2 climatology... */
5468 if (ctl->clim_h2o2_filename[0] != '-')
5469 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
5470
5471 /* Read HO2 climatology... */
5472 if (ctl->clim_ho2_filename[0] != '-')
5473 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
5474
5475 /* Read O(1D) climatology... */
5476 if (ctl->clim_o1d_filename[0] != '-')
5477 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
5478
5479 /* Read CFC-10 time series... */
5480 if (ctl->clim_ccl4_timeseries[0] != '-')
5482
5483 /* Read CFC-11 time series... */
5484 if (ctl->clim_ccl3f_timeseries[0] != '-')
5486
5487 /* Read CFC-12 time series... */
5488 if (ctl->clim_ccl2f2_timeseries[0] != '-')
5490
5491 /* Read N2O time series... */
5492 if (ctl->clim_n2o_timeseries[0] != '-')
5493 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
5494
5495 /* Read SF6 time series... */
5496 if (ctl->clim_sf6_timeseries[0] != '-')
5497 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
5498}
5499
5500/*****************************************************************************/
5501
5503 const char *filename,
5504 int argc,
5505 char *argv[],
5506 ctl_t *ctl) {
5507
5508 /* Set timer... */
5509 SELECT_TIMER("READ_CTL", "INPUT");
5510
5511 /* Write info... */
5512 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
5513 "(executable: %s | version: %s | compiled: %s, %s)\n",
5514 argv[0], VERSION, __DATE__, __TIME__);
5515
5516 /* Initialize quantity indices... */
5517 ctl->qnt_idx = -1;
5518 ctl->qnt_ens = -1;
5519 ctl->qnt_stat = -1;
5520 ctl->qnt_m = -1;
5521 ctl->qnt_vmr = -1;
5522 ctl->qnt_rp = -1;
5523 ctl->qnt_rhop = -1;
5524 ctl->qnt_ps = -1;
5525 ctl->qnt_ts = -1;
5526 ctl->qnt_zs = -1;
5527 ctl->qnt_us = -1;
5528 ctl->qnt_vs = -1;
5529 ctl->qnt_ess = -1;
5530 ctl->qnt_nss = -1;
5531 ctl->qnt_shf = -1;
5532 ctl->qnt_lsm = -1;
5533 ctl->qnt_sst = -1;
5534 ctl->qnt_pbl = -1;
5535 ctl->qnt_pt = -1;
5536 ctl->qnt_tt = -1;
5537 ctl->qnt_zt = -1;
5538 ctl->qnt_h2ot = -1;
5539 ctl->qnt_zg = -1;
5540 ctl->qnt_p = -1;
5541 ctl->qnt_t = -1;
5542 ctl->qnt_rho = -1;
5543 ctl->qnt_u = -1;
5544 ctl->qnt_v = -1;
5545 ctl->qnt_w = -1;
5546 ctl->qnt_h2o = -1;
5547 ctl->qnt_o3 = -1;
5548 ctl->qnt_lwc = -1;
5549 ctl->qnt_rwc = -1;
5550 ctl->qnt_iwc = -1;
5551 ctl->qnt_swc = -1;
5552 ctl->qnt_cc = -1;
5553 ctl->qnt_pct = -1;
5554 ctl->qnt_pcb = -1;
5555 ctl->qnt_cl = -1;
5556 ctl->qnt_plcl = -1;
5557 ctl->qnt_plfc = -1;
5558 ctl->qnt_pel = -1;
5559 ctl->qnt_cape = -1;
5560 ctl->qnt_cin = -1;
5561 ctl->qnt_o3c = -1;
5562 ctl->qnt_hno3 = -1;
5563 ctl->qnt_oh = -1;
5564 ctl->qnt_h2o2 = -1;
5565 ctl->qnt_ho2 = -1;
5566 ctl->qnt_o1d = -1;
5567 ctl->qnt_mloss_oh = -1;
5568 ctl->qnt_mloss_h2o2 = -1;
5569 ctl->qnt_mloss_kpp = -1;
5570 ctl->qnt_mloss_wet = -1;
5571 ctl->qnt_mloss_dry = -1;
5572 ctl->qnt_mloss_decay = -1;
5573 ctl->qnt_loss_rate = -1;
5574 ctl->qnt_psat = -1;
5575 ctl->qnt_psice = -1;
5576 ctl->qnt_pw = -1;
5577 ctl->qnt_sh = -1;
5578 ctl->qnt_rh = -1;
5579 ctl->qnt_rhice = -1;
5580 ctl->qnt_theta = -1;
5581 ctl->qnt_zeta = -1;
5582 ctl->qnt_zeta_d = -1;
5583 ctl->qnt_zeta_dot = -1;
5584 ctl->qnt_eta = -1;
5585 ctl->qnt_eta_dot = -1;
5586 ctl->qnt_tvirt = -1;
5587 ctl->qnt_lapse = -1;
5588 ctl->qnt_vh = -1;
5589 ctl->qnt_vz = -1;
5590 ctl->qnt_pv = -1;
5591 ctl->qnt_tdew = -1;
5592 ctl->qnt_tice = -1;
5593 ctl->qnt_tsts = -1;
5594 ctl->qnt_tnat = -1;
5595 ctl->qnt_Cx = -1;
5596 ctl->qnt_Ch2o = -1;
5597 ctl->qnt_Co3 = -1;
5598 ctl->qnt_Cco = -1;
5599 ctl->qnt_Coh = -1;
5600 ctl->qnt_Ch = -1;
5601 ctl->qnt_Cho2 = -1;
5602 ctl->qnt_Ch2o2 = -1;
5603 ctl->qnt_Co1d = -1;
5604 ctl->qnt_Co3p = -1;
5605 ctl->qnt_Cccl4 = -1;
5606 ctl->qnt_Cccl3f = -1;
5607 ctl->qnt_Cccl2f2 = -1;
5608 ctl->qnt_Cn2o = -1;
5609 ctl->qnt_Csf6 = -1;
5610 ctl->qnt_aoa = -1;
5611 ctl->qnt_Arn222 = -1;
5612 ctl->qnt_Apb210 = -1;
5613 ctl->qnt_Abe7 = -1;
5614 ctl->qnt_Acs137 = -1;
5615 ctl->qnt_Ai131 = -1;
5616 ctl->qnt_Axe133 = -1;
5617 ctl->qnt_subdomain = -1;
5618 ctl->qnt_destination = -1;
5619
5620 /* Read quantities... */
5621 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
5622 if (ctl->nq > NQ)
5623 ERRMSG("Too many quantities!");
5624 for (int iq = 0; iq < ctl->nq; iq++) {
5625
5626 /* Read quantity name and format... */
5627 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
5628 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
5629 ctl->qnt_longname[iq]);
5630 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
5631 ctl->qnt_format[iq]);
5632 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
5633 sprintf(ctl->qnt_format[iq], "%%.2f");
5634
5635 /* Try to identify quantity... */
5636 SET_QNT(qnt_idx, "idx", "particle index", "-")
5637 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
5638 SET_QNT(qnt_stat, "stat", "station flag", "-")
5639 SET_QNT(qnt_m, "m", "mass", "kg")
5640 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
5641 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
5642 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
5643 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
5644 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
5645 SET_QNT(qnt_zs, "zs", "surface height", "km")
5646 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
5647 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
5648 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
5649 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
5650 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
5651 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
5652 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
5653 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
5654 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
5655 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
5656 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
5657 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
5658 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
5659 SET_QNT(qnt_p, "p", "pressure", "hPa")
5660 SET_QNT(qnt_t, "t", "temperature", "K")
5661 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
5662 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
5663 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
5664 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
5665 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
5666 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
5667 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
5668 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
5669 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
5670 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
5671 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
5672 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
5673 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
5674 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
5675 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
5676 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
5677 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
5678 SET_QNT(qnt_cape, "cape", "convective available potential energy",
5679 "J/kg")
5680 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
5681 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
5682 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
5683 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
5684 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
5685 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
5686 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
5687 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
5688 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
5689 "mass loss due to H2O2 chemistry", "kg")
5690 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
5691 "kg")
5692 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
5693 "kg")
5694 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
5695 "kg")
5696 SET_QNT(qnt_mloss_decay, "mloss_decay",
5697 "mass loss due to exponential decay", "kg")
5698 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
5699 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
5700 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
5701 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
5702 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
5703 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
5704 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
5705 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
5706 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
5707 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
5708 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
5709 "K/day")
5710 SET_QNT(qnt_eta, "eta", "eta coordinate", "1")
5711 SET_QNT(qnt_eta_dot, "eta_dot", "velocity of eta coordinate", "1/s")
5712 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
5713 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
5714 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
5715 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
5716 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
5717 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
5718 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
5719 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
5720 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
5721 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
5722 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
5723 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
5724 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
5725 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
5726 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
5727 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
5728 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
5729 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
5730 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
5731 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
5732 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
5733 "ppv")
5734 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
5735 "ppv")
5736 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
5737 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
5738 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
5739 SET_QNT(qnt_Arn222, "Arn222", "Rn-222 activity", "Bq")
5740 SET_QNT(qnt_Apb210, "Apb210", "Pb-210 activity", "Bq")
5741 SET_QNT(qnt_Abe7, "Abe7", "Be-7 activity", "Bq")
5742 SET_QNT(qnt_Acs137, "Acs137", "Cs-137 activity", "Bq")
5743 SET_QNT(qnt_Ai131, "Ai131", "I-131 activity", "Bq")
5744 SET_QNT(qnt_Axe133, "Axe133", "Xe-133 activity", "Bq")
5745 SET_QNT(qnt_subdomain, "subdomain", "current subdomain index", "-")
5746 SET_QNT(qnt_destination, "destination",
5747 "subdomain index of destination", "-")
5748 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
5749 }
5750
5751 /* Vertical coordinate and velocity... */
5752 ctl->advect_vert_coord =
5753 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
5754 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 3)
5755 ERRMSG("ADVECT_VERT_COORD must be 0, 1, 2, or 3!");
5756
5757 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
5758 ERRMSG("Add quantity zeta for diabatic advection!");
5759 if (ctl->advect_vert_coord == 3 && ctl->qnt_eta < 0)
5760 ERRMSG("Add quantity eta for etadot avection!");
5761
5762 ctl->met_vert_coord =
5763 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
5764 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
5765 ERRMSG("MET_VERT_COORD must be 0, 1, 2, 3, or 4!");
5766
5767 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
5768 ERRMSG
5769 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
5770 if (ctl->advect_vert_coord == 3 && ctl->met_vert_coord != 3)
5771 ERRMSG
5772 ("Using ADVECT_VERT_COORD = 3 requires A and B model level coefficients!");
5773
5774 /* Time steps of simulation... */
5775 ctl->direction =
5776 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
5777 if (ctl->direction != -1 && ctl->direction != 1)
5778 ERRMSG("Set DIRECTION to -1 or 1!");
5779 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
5780 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
5781
5782 /* Meteo data... */
5783 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
5784 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
5785 ctl->met_convention =
5786 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
5787 ctl->met_type =
5788 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
5789 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
5790 ERRMSG
5791 ("Please use meteo files in netcdf format for diabatic calculations.");
5792 if (ctl->advect_vert_coord == 3 && ctl->met_type != 0)
5793 ERRMSG
5794 ("Please use meteo files in netcdf format for etadot calculations.");
5795 ctl->met_clams =
5796 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
5797 ctl->met_nc_scale =
5798 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
5799 ctl->met_nc_level =
5800 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
5801 ctl->met_nc_quant =
5802 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
5803 ctl->met_zstd_level =
5804 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
5805 for (int i = 0; i < METVAR; i++) {
5806 char defprec[LEN] = "0", deftol[LEN] = "0.0";
5807 if (i == 0) /* geopotential height */
5808 sprintf(deftol, "0.5");
5809 else if (i == 1) /* temperature */
5810 sprintf(deftol, "5.0");
5811 else /* other variables */
5812 sprintf(defprec, "8");
5813 ctl->met_comp_prec[i] =
5814 (int) scan_ctl(filename, argc, argv, "MET_COMP_PREC", i, defprec, NULL);
5815 ctl->met_comp_tol[i] =
5816 scan_ctl(filename, argc, argv, "MET_COMP_TOL", i, deftol, NULL);
5817 }
5818 ctl->met_cms_batch =
5819 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
5820 ctl->met_cms_zstd =
5821 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
5822 ctl->met_cms_nd0x =
5823 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0X", -1, "48", NULL);
5824 ctl->met_cms_nd0y =
5825 (int) scan_ctl(filename, argc, argv, "MET_CMS_ND0Y", -1, "24", NULL);
5826 ctl->met_cms_maxlev =
5827 (int) scan_ctl(filename, argc, argv, "MET_CMS_MAXLEV", -1, "6", NULL);
5828 ctl->met_cms_eps_z =
5829 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
5830 ctl->met_cms_eps_t =
5831 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
5832 ctl->met_cms_eps_u =
5833 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
5834 ctl->met_cms_eps_v =
5835 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
5836 ctl->met_cms_eps_w =
5837 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
5838 ctl->met_cms_eps_pv =
5839 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
5840 ctl->met_cms_eps_h2o =
5841 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
5842 ctl->met_cms_eps_o3 =
5843 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
5844 ctl->met_cms_eps_lwc =
5845 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
5846 ctl->met_cms_eps_rwc =
5847 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
5848 ctl->met_cms_eps_iwc =
5849 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
5850 ctl->met_cms_eps_swc =
5851 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
5852 ctl->met_cms_eps_cc =
5853 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
5854 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
5855 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
5856 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
5857 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
5858 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
5859 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
5860 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
5861 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
5862 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
5863 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
5864 ctl->met_detrend =
5865 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
5866 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
5867 if (ctl->met_np > EP)
5868 ERRMSG("Too many pressure levels!");
5869 ctl->met_press_level_def =
5870 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
5871 NULL);
5872 if (ctl->met_press_level_def >= 0) {
5873 level_definitions(ctl);
5874 } else {
5875 if (ctl->met_np > 0) {
5876 for (int ip = 0; ip < ctl->met_np; ip++)
5877 ctl->met_p[ip] =
5878 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
5879 }
5880 }
5881 ctl->met_nlev =
5882 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
5883 if (ctl->met_nlev > EP)
5884 ERRMSG("Too many model levels!");
5885 for (int ip = 0; ip < ctl->met_nlev; ip++)
5886 ctl->met_lev_hyam[ip] =
5887 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
5888 for (int ip = 0; ip < ctl->met_nlev; ip++)
5889 ctl->met_lev_hybm[ip] =
5890 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
5891 ctl->met_geopot_sx =
5892 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
5893 ctl->met_geopot_sy =
5894 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
5895 ctl->met_relhum =
5896 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
5897 ctl->met_cape =
5898 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
5899 if (ctl->met_cape < 0 || ctl->met_cape > 1)
5900 ERRMSG("Set MET_CAPE to 0 or 1!");
5901 ctl->met_pbl =
5902 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
5903 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
5904 ERRMSG("Set MET_PBL to 0 ... 3!");
5905 ctl->met_pbl_min =
5906 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
5907 ctl->met_pbl_max =
5908 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
5909 ctl->met_tropo =
5910 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
5911 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
5912 ERRMSG("Set MET_TROPO to 0 ... 5!");
5913 ctl->met_tropo_pv =
5914 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
5915 ctl->met_tropo_theta =
5916 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
5917 ctl->met_tropo_spline =
5918 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
5919 ctl->met_dt_out =
5920 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
5921 ctl->met_cache =
5922 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
5923 ctl->met_mpi_share =
5924 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
5925
5926 /* Sorting... */
5927 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
5928
5929 /* Isosurface parameters... */
5930 ctl->isosurf =
5931 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
5932 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
5933
5934 /* Random number generator... */
5935 ctl->rng_type =
5936 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
5937 if (ctl->rng_type < 0 || ctl->rng_type > 2)
5938 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
5939
5940 /* Advection parameters... */
5941 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
5942 if (!
5943 (ctl->advect == 0 || ctl->advect == 1 || ctl->advect == 2
5944 || ctl->advect == 4))
5945 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
5946
5947 /* Diffusion parameters... */
5948 ctl->diffusion
5949 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
5950 if (ctl->diffusion < 0 || ctl->diffusion > 2)
5951 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
5952 ctl->turb_dx_pbl =
5953 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
5954 ctl->turb_dx_trop =
5955 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
5956 ctl->turb_dx_strat =
5957 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
5958 ctl->turb_dz_pbl =
5959 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
5960 ctl->turb_dz_trop =
5961 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
5962 ctl->turb_dz_strat =
5963 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
5964 ctl->turb_mesox =
5965 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
5966 ctl->turb_mesoz =
5967 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5968
5969 /* Convection... */
5970 ctl->conv_mix_pbl
5971 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
5972 ctl->conv_pbl_trans
5973 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
5974 ctl->conv_cape
5975 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5976 ctl->conv_cin
5977 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5978 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5979
5980 /* Boundary conditions... */
5981 ctl->bound_mass =
5982 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5983 ctl->bound_mass_trend =
5984 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5985 ctl->bound_vmr =
5986 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5987 ctl->bound_vmr_trend =
5988 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5989 ctl->bound_lat0 =
5990 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5991 ctl->bound_lat1 =
5992 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5993 ctl->bound_p0 =
5994 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5995 ctl->bound_p1 =
5996 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5997 ctl->bound_dps =
5998 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5999 ctl->bound_dzs =
6000 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
6001 ctl->bound_zetas =
6002 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
6003 ctl->bound_pbl =
6004 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
6005
6006 /* Species parameters... */
6007 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
6008 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
6009 ctl->molmass = 120.907;
6010 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
6011 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
6012 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
6013 ctl->molmass = 137.359;
6014 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
6015 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
6016 } else if (strcasecmp(ctl->species, "CH4") == 0) {
6017 ctl->molmass = 16.043;
6018 ctl->oh_chem_reaction = 2;
6019 ctl->oh_chem[0] = 2.45e-12;
6020 ctl->oh_chem[1] = 1775;
6021 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
6022 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6023 } else if (strcasecmp(ctl->species, "CO") == 0) {
6024 ctl->molmass = 28.01;
6025 ctl->oh_chem_reaction = 3;
6026 ctl->oh_chem[0] = 6.9e-33;
6027 ctl->oh_chem[1] = 2.1;
6028 ctl->oh_chem[2] = 1.1e-12;
6029 ctl->oh_chem[3] = -1.3;
6030 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
6031 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
6032 } else if (strcasecmp(ctl->species, "CO2") == 0) {
6033 ctl->molmass = 44.009;
6034 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
6035 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6036 } else if (strcasecmp(ctl->species, "H2O") == 0) {
6037 ctl->molmass = 18.01528;
6038 } else if (strcasecmp(ctl->species, "N2O") == 0) {
6039 ctl->molmass = 44.013;
6040 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
6041 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
6042 } else if (strcasecmp(ctl->species, "NH3") == 0) {
6043 ctl->molmass = 17.031;
6044 ctl->oh_chem_reaction = 2;
6045 ctl->oh_chem[0] = 1.7e-12;
6046 ctl->oh_chem[1] = 710;
6047 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
6048 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
6049 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
6050 ctl->molmass = 63.012;
6051 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
6052 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
6053 } else if (strcasecmp(ctl->species, "NO") == 0) {
6054 ctl->molmass = 30.006;
6055 ctl->oh_chem_reaction = 3;
6056 ctl->oh_chem[0] = 7.1e-31;
6057 ctl->oh_chem[1] = 2.6;
6058 ctl->oh_chem[2] = 3.6e-11;
6059 ctl->oh_chem[3] = 0.1;
6060 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
6061 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
6062 } else if (strcasecmp(ctl->species, "NO2") == 0) {
6063 ctl->molmass = 46.005;
6064 ctl->oh_chem_reaction = 3;
6065 ctl->oh_chem[0] = 1.8e-30;
6066 ctl->oh_chem[1] = 3.0;
6067 ctl->oh_chem[2] = 2.8e-11;
6068 ctl->oh_chem[3] = 0.0;
6069 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
6070 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
6071 } else if (strcasecmp(ctl->species, "O3") == 0) {
6072 ctl->molmass = 47.997;
6073 ctl->oh_chem_reaction = 2;
6074 ctl->oh_chem[0] = 1.7e-12;
6075 ctl->oh_chem[1] = 940;
6076 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
6077 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
6078 } else if (strcasecmp(ctl->species, "SF6") == 0) {
6079 ctl->molmass = 146.048;
6080 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
6081 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
6082 } else if (strcasecmp(ctl->species, "SO2") == 0) {
6083 ctl->molmass = 64.066;
6084 ctl->oh_chem_reaction = 3;
6085 ctl->oh_chem[0] = 2.9e-31;
6086 ctl->oh_chem[1] = 4.1;
6087 ctl->oh_chem[2] = 1.7e-12;
6088 ctl->oh_chem[3] = -0.2;
6089 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
6090 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
6091 }
6092
6093 /* Molar mass... */
6094 char defstr[LEN];
6095 sprintf(defstr, "%g", ctl->molmass);
6096 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
6097
6098 /* OH chemistry... */
6099 sprintf(defstr, "%d", ctl->oh_chem_reaction);
6100 ctl->oh_chem_reaction =
6101 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
6102 NULL);
6103 for (int ip = 0; ip < 4; ip++) {
6104 sprintf(defstr, "%g", ctl->oh_chem[ip]);
6105 ctl->oh_chem[ip] =
6106 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
6107 }
6108 ctl->oh_chem_beta =
6109 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
6110
6111 /* H2O2 chemistry... */
6112 ctl->h2o2_chem_reaction =
6113 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
6114
6115 /* KPP chemistry... */
6116 ctl->kpp_chem =
6117 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
6118 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
6119
6120 /* First order tracer chemistry... */
6121 ctl->tracer_chem =
6122 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
6123
6124 /* Radioactive decay... */
6125 ctl->radio_decay =
6126 (int) scan_ctl(filename, argc, argv, "RADIO_DECAY", -1, "0", NULL);
6127
6128 /* Wet deposition... */
6129 for (int ip = 0; ip < 2; ip++) {
6130 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
6131 ctl->wet_depo_ic_h[ip] =
6132 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
6133 }
6134 for (int ip = 0; ip < 1; ip++) {
6135 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
6136 ctl->wet_depo_bc_h[ip] =
6137 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
6138 }
6139 ctl->wet_depo_so2_ph =
6140 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
6141 ctl->wet_depo_ic_a =
6142 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
6143 ctl->wet_depo_ic_b =
6144 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
6145 ctl->wet_depo_bc_a =
6146 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
6147 ctl->wet_depo_bc_b =
6148 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
6149 ctl->wet_depo_pre[0] =
6150 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
6151 ctl->wet_depo_pre[1] =
6152 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
6154 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
6156 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
6157
6158 /* Dry deposition... */
6159 ctl->dry_depo_vdep =
6160 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
6161 ctl->dry_depo_dp =
6162 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
6163
6164 /* Climatological data... */
6165 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
6166 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
6167 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
6168 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
6169 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
6170 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
6171 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
6172 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
6173 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
6174 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
6175 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
6176 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
6177 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
6178 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
6179 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
6180 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
6181 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
6182 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
6183 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
6184 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
6185 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
6186 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
6187
6188 /* Mixing... */
6189 ctl->mixing_dt =
6190 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
6191 ctl->mixing_trop =
6192 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
6193 ctl->mixing_strat =
6194 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
6195 ctl->mixing_z0 =
6196 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
6197 ctl->mixing_z1 =
6198 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
6199 ctl->mixing_nz =
6200 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
6201 ctl->mixing_lon0 =
6202 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
6203 ctl->mixing_lon1 =
6204 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
6205 ctl->mixing_nx =
6206 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
6207 ctl->mixing_lat0 =
6208 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
6209 ctl->mixing_lat1 =
6210 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
6211 ctl->mixing_ny =
6212 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
6213
6214 /* Chemistry grid... */
6215 ctl->chemgrid_z0 =
6216 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
6217 ctl->chemgrid_z1 =
6218 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
6219 ctl->chemgrid_nz =
6220 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
6221 ctl->chemgrid_lon0 =
6222 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
6223 ctl->chemgrid_lon1 =
6224 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
6225 ctl->chemgrid_nx =
6226 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
6227 ctl->chemgrid_lat0 =
6228 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
6229 ctl->chemgrid_lat1 =
6230 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
6231 ctl->chemgrid_ny =
6232 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
6233
6234 /* Exponential decay... */
6235 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
6236 ctl->tdec_strat =
6237 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
6238
6239 /* PSC analysis... */
6240 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
6241 ctl->psc_hno3 =
6242 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
6243
6244 /* Output of atmospheric data... */
6245 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
6246 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
6247 ctl->atm_dt_out =
6248 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
6249 ctl->atm_filter =
6250 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
6251 ctl->atm_stride =
6252 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
6253 ctl->atm_type =
6254 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
6255 ctl->atm_type_out =
6256 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
6257 if (ctl->atm_type_out == -1)
6258 ctl->atm_type_out = ctl->atm_type;
6259 ctl->atm_nc_level =
6260 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
6261 for (int iq = 0; iq < ctl->nq; iq++)
6262 ctl->atm_nc_quant[iq] =
6263 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
6264 ctl->obs_type =
6265 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
6266
6267 /* Output of CSI data... */
6268 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
6269 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
6270 ctl->csi_dt_out =
6271 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
6272 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
6273 ctl->csi_obsmin =
6274 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
6275 ctl->csi_modmin =
6276 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
6277 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
6278 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
6279 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
6280 ctl->csi_lon0 =
6281 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
6282 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
6283 ctl->csi_nx =
6284 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
6285 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
6286 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
6287 ctl->csi_ny =
6288 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
6289
6290 /* Output of ensemble data... */
6291 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
6292 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
6293 ctl->ens_dt_out =
6294 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
6295
6296 /* Output of grid data... */
6297 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
6298 ctl->grid_basename);
6299 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
6300 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
6301 ctl->grid_dt_out =
6302 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
6303 ctl->grid_sparse =
6304 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
6305 ctl->grid_nc_level =
6306 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
6307 for (int iq = 0; iq < ctl->nq; iq++)
6308 ctl->grid_nc_quant[iq] =
6309 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
6310 ctl->grid_stddev =
6311 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
6312 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
6313 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
6314 ctl->grid_nz =
6315 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
6316 ctl->grid_lon0 =
6317 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
6318 ctl->grid_lon1 =
6319 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
6320 ctl->grid_nx =
6321 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
6322 ctl->grid_lat0 =
6323 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
6324 ctl->grid_lat1 =
6325 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
6326 ctl->grid_ny =
6327 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
6328 ctl->grid_type =
6329 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
6330
6331 /* Output of profile data... */
6332 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
6333 ctl->prof_basename);
6334 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
6335 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
6336 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
6337 ctl->prof_nz =
6338 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
6339 ctl->prof_lon0 =
6340 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
6341 ctl->prof_lon1 =
6342 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
6343 ctl->prof_nx =
6344 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
6345 ctl->prof_lat0 =
6346 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
6347 ctl->prof_lat1 =
6348 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
6349 ctl->prof_ny =
6350 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
6351
6352 /* Output of sample data... */
6353 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
6354 ctl->sample_basename);
6355 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
6356 ctl->sample_kernel);
6357 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
6358 ctl->sample_obsfile);
6359 ctl->sample_dx =
6360 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
6361 ctl->sample_dz =
6362 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
6363
6364 /* Output of station data... */
6365 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
6366 ctl->stat_basename);
6367 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
6368 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
6369 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
6370 ctl->stat_t0 =
6371 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
6372 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
6373
6374 /* Output of VTK data... */
6375 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
6376 ctl->vtk_dt_out =
6377 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
6378 ctl->vtk_stride =
6379 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
6380 ctl->vtk_scale =
6381 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
6382 ctl->vtk_offset =
6383 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
6384 ctl->vtk_sphere =
6385 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
6386
6387 /* Domain decomposition... */
6388 ctl->dd = (int) scan_ctl(filename, argc, argv, "DD", -1, "0", NULL);
6390 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1,
6391 (ctl->dd == 1) ? "2" : "1", NULL);
6392 ctl->dd_subdomains_zonal =
6393 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1,
6394 (ctl->dd == 1) ? "2" : "1", NULL);
6396 ctl->dd = 1;
6397 else if (ctl->dd == 1)
6398 ERRMSG("Please provide zonal and meridional subdomain numbers!")
6399 ctl->dd_nbr_neighbours =
6400 (int) scan_ctl(filename, argc, argv, "DD_NBR_NEIGHBOURS", -1, "8",
6401 NULL);
6402 ctl->dd_halos_size =
6403 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
6404}
6405
6406/*****************************************************************************/
6407
6409 const char *filename,
6410 const ctl_t *ctl,
6411 const clim_t *clim,
6412 met_t *met,
6413 dd_t *dd) {
6414
6415 /* Write info... */
6416 LOG(1, "Read meteo data: %s", filename);
6417
6418 /* Set rank... */
6419 int rank = 0;
6420#ifdef MPI
6421 if (ctl->met_mpi_share)
6422 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
6423#endif
6424
6425 /* Check rank... */
6426 if (!ctl->met_mpi_share || rank == 0) {
6427
6428 /* Read netCDF data... */
6429 if (ctl->met_type == 0) {
6430 if (read_met_nc(filename, ctl, met, dd) != 1)
6431 return 0;
6432 }
6433
6434 /* Read binary data... */
6435 else if ((ctl->met_type >= 1 && ctl->met_type <= 5) || ctl->met_type == 7) {
6436 if (read_met_bin(filename, ctl, met) != 1)
6437 return 0;
6438 }
6439
6440#ifdef ECCODES
6441 /* Read grib data... */
6442 else if (ctl->met_type == 6) {
6443 if (read_met_grib(filename, ctl, met) != 1)
6444 return 0;
6445 }
6446#endif
6447
6448 /* Not implemented... */
6449 else
6450 ERRMSG("MET_TYPE not implemented!");
6451
6452 /* Preprocessing for netCDF and grib files... */
6453 if (ctl->met_type == 0 || ctl->met_type == 6) {
6454
6455 /* Extrapolate data for lower boundary... */
6457
6458 /* Fix polar winds... */
6460
6461 /* Create periodic boundary conditions... */
6462#ifndef DD
6463 read_met_periodic(met);
6464#endif
6465
6466 /* Downsampling... */
6467 read_met_sample(ctl, met);
6468
6469 /* Calculate geopotential heights... */
6470 read_met_geopot(ctl, met);
6471
6472 /* Calculate potential vorticity... */
6473 read_met_pv(met);
6474
6475 /* Calculate boundary layer data... */
6476 read_met_pbl(ctl, met);
6477
6478 /* Calculate tropopause data... */
6479 read_met_tropo(ctl, clim, met);
6480
6481 /* Calculate cloud properties... */
6482 read_met_cloud(met);
6483
6484 /* Calculate convective available potential energy... */
6485 read_met_cape(ctl, clim, met);
6486
6487 /* Calculate total column ozone... */
6488 read_met_ozone(met);
6489
6490 /* Detrending... */
6491 read_met_detrend(ctl, met);
6492
6493 /* Check meteo data and smooth zeta profiles ... */
6494 read_met_monotonize(ctl, met);
6495 }
6496 }
6497
6498 /* Broadcast data via MPI... */
6499#ifdef MPI
6500 if (ctl->met_mpi_share) {
6501
6502 /* Set timer... */
6503 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM");
6504 LOG(2, "Broadcast data on rank %d...", rank);
6505
6506 /* Broadcast... */
6507 broadcast_large_data(met, sizeof(met_t));
6508 }
6509#endif
6510
6511 /* Return success... */
6512 return 1;
6513}
6514
6515/*****************************************************************************/
6516
6518 ctl_t *ctl,
6519 cache_t *cache,
6520 clim_t *clim,
6521 met_t **met0,
6522 met_t **met1,
6523 atm_t *atm,
6524 double t,
6525 dd_t *dd) {
6526
6527 /* Initialize modules... */
6528 if (t == ctl->t_start) {
6529
6530 /* Initialize isosurface data... */
6531 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6532 module_isosurf_init(ctl, cache, *met0, *met1, atm);
6533
6534 /* Initialize advection... */
6535 module_advect_init(ctl, cache, *met0, *met1, atm);
6536
6537 /* Initialize chemistry... */
6538 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
6539 }
6540
6541 /* Set time steps of air parcels... */
6542 module_timesteps(ctl, cache, *met0, atm, t);
6543
6544 /* Sort particles... */
6545 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
6546 module_sort(ctl, *met0, atm);
6547
6548
6549 /* Check positions (initial)... */
6550 module_position(cache, *met0, *met1, atm);
6551
6552 /* Advection... */
6553 if (ctl->advect > 0)
6554 module_advect(ctl, cache, *met0, *met1, atm);
6555
6556 /* Turbulent diffusion... */
6557 if (ctl->diffusion == 1
6558 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
6559 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
6560 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
6561 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
6562
6563 /* Mesoscale diffusion... */
6564 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
6565 module_diff_meso(ctl, cache, *met0, *met1, atm);
6566
6567 /* Diffusion... */
6568 if (ctl->diffusion == 2)
6569 module_diff_pbl(ctl, cache, *met0, *met1, atm);
6570
6571 /* Convection... */
6572 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
6573 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
6574 module_convection(ctl, cache, *met0, *met1, atm);
6575
6576 /* Sedimentation... */
6577 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
6578 module_sedi(ctl, cache, *met0, *met1, atm);
6579
6580 /* Isosurface... */
6581 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
6582 module_isosurf(ctl, cache, *met0, *met1, atm);
6583
6584 /* Check positions (final)... */
6585 module_position(cache, *met0, *met1, atm);
6586
6587 /* Interpolate meteo data... */
6588 if (ctl->met_dt_out > 0
6589 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
6590 module_meteo(ctl, cache, clim, *met0, *met1, atm);
6591
6592 /* Check boundary conditions (initial)... */
6593 if ((ctl->bound_lat0 < ctl->bound_lat1)
6594 && (ctl->bound_p0 > ctl->bound_p1))
6595 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6596
6597 /* Initialize quantity of total loss rate... */
6598 if (ctl->qnt_loss_rate >= 0) {
6599 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
6600 atm->q[ctl->qnt_loss_rate][ip] = 0;
6601 }
6602 }
6603
6604 /* Decay of particle mass... */
6605 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
6606 module_decay(ctl, cache, clim, atm);
6607
6608 /* Interparcel mixing... */
6609 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
6610 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
6611 module_mixing(ctl, clim, atm, t);
6612
6613 /* Calculate the tracer vmr in the chemistry grid... */
6614 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
6615 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
6616 module_chem_grid(ctl, *met0, *met1, atm, t);
6617
6618 /* OH chemistry... */
6619 if (ctl->oh_chem_reaction != 0)
6620 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
6621
6622 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
6623 if (ctl->h2o2_chem_reaction != 0)
6624 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
6625
6626 /* First-order tracer chemistry... */
6627 if (ctl->tracer_chem)
6628 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
6629
6630 /* Radioactive decay... */
6631 if (ctl->radio_decay)
6632 module_radio_decay(ctl, cache, atm);
6633
6634 /* Domain decomposition... */
6635 if (dd->init) {
6636#ifdef DD
6637 module_dd(ctl, atm, cache, dd, met0);
6638#else
6639 ERRMSG("DD initialized, but model is compiled without DD.")
6640#endif
6641 }
6642
6643 /* KPP chemistry... */
6644 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
6645#ifdef KPP
6646 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
6647#else
6648 ERRMSG("Code was compiled without KPP!");
6649#endif
6650 }
6651
6652 /* Wet deposition... */
6653 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
6654 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
6655 module_wet_depo(ctl, cache, *met0, *met1, atm);
6656
6657 /* Dry deposition... */
6658 if (ctl->dry_depo_vdep > 0)
6659 module_dry_depo(ctl, cache, *met0, *met1, atm);
6660
6661 /* Check boundary conditions (final)... */
6662 if ((ctl->bound_lat0 < ctl->bound_lat1)
6663 && (ctl->bound_p0 > ctl->bound_p1))
6664 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
6665}
6666
6667/*****************************************************************************/
6668
6670 const ctl_t *ctl,
6671 const cache_t *cache,
6672 const clim_t *clim,
6673 met_t **met0,
6674 met_t **met1,
6675 const atm_t *atm) {
6676
6677 /* Update GPU... */
6678 if (ctl != NULL) {
6679#ifdef _OPENACC
6680 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6681#pragma acc update device(ctl[:1])
6682#endif
6683 }
6684
6685 if (cache != NULL) {
6686#ifdef _OPENACC
6687 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6688#pragma acc update device(cache[:1])
6689#endif
6690 }
6691
6692 if (clim != NULL) {
6693#ifdef _OPENACC
6694 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6695#pragma acc update device(clim[:1])
6696#endif
6697 }
6698
6699 if (met0 != NULL) {
6700#ifdef _OPENACC
6701 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6702 met_t *met0up = *met0;
6703#pragma acc update device(met0up[:1])
6704#endif
6705 }
6706
6707 if (met1 != NULL) {
6708#ifdef _OPENACC
6709 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6710 met_t *met1up = *met1;
6711#pragma acc update device(met1up[:1])
6712#endif
6713 }
6714
6715 if (atm != NULL) {
6716#ifdef _OPENACC
6717 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6718#pragma acc update device(atm[:1])
6719#endif
6720 }
6721}
6722
6723/*****************************************************************************/
6724
6726 const ctl_t *ctl,
6727 const cache_t *cache,
6728 const clim_t *clim,
6729 met_t **met0,
6730 met_t **met1,
6731 const atm_t *atm) {
6732
6733 /* Update GPU... */
6734 if (ctl != NULL) {
6735#ifdef _OPENACC
6736 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6737#pragma acc update host(ctl[:1])
6738#endif
6739 }
6740
6741 if (cache != NULL) {
6742#ifdef _OPENACC
6743 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6744#pragma acc update host(cache[:1])
6745#endif
6746 }
6747
6748 if (clim != NULL) {
6749#ifdef _OPENACC
6750 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6751#pragma acc update host(clim[:1])
6752#endif
6753 }
6754
6755 if (met0 != NULL) {
6756#ifdef _OPENACC
6757 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6758 met_t *met0up = *met0;
6759#pragma acc update host(met0up[:1])
6760#endif
6761 }
6762
6763 if (met1 != NULL) {
6764#ifdef _OPENACC
6765 SELECT_TIMER("UPDATE_DEVICE", "MEMORY");
6766 met_t *met1up = *met1;
6767#pragma acc update host(met1up[:1])
6768#endif
6769 }
6770
6771 if (atm != NULL) {
6772#ifdef _OPENACC
6773 SELECT_TIMER("UPDATE_HOST", "MEMORY");
6774#pragma acc update host(atm[:1])
6775#endif
6776 }
6777}
6778
6779/*****************************************************************************/
6780
6782 const char *filename,
6783 const ctl_t *ctl,
6784 const atm_t *atm,
6785 const double t) {
6786
6787 /* Set timer... */
6788 SELECT_TIMER("WRITE_ATM", "OUTPUT");
6789
6790 /* Write info... */
6791 LOG(1, "Write atmospheric data: %s", filename);
6792
6793 /* Write ASCII data... */
6794 if (ctl->atm_type_out == 0)
6795 write_atm_asc(filename, ctl, atm, t);
6796
6797 /* Write binary data... */
6798 else if (ctl->atm_type_out == 1)
6799 write_atm_bin(filename, ctl, atm);
6800
6801 /* Write netCDF data... */
6802 else if (ctl->atm_type_out == 2)
6803 write_atm_nc(filename, ctl, atm);
6804
6805 /* Write CLaMS trajectory data... */
6806 else if (ctl->atm_type_out == 3)
6807 write_atm_clams_traj(filename, ctl, atm, t);
6808
6809 /* Write CLaMS pos data... */
6810 else if (ctl->atm_type_out == 4)
6811 write_atm_clams(filename, ctl, atm);
6812
6813 /* Error... */
6814 else
6815 ERRMSG("Atmospheric data type not supported!");
6816
6817 /* Write info... */
6818 double mini, maxi;
6819 LOG(2, "Number of particles: %d", atm->np);
6820 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
6821 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
6822 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
6823 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
6824 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
6825 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
6826 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
6827 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
6828 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
6829 for (int iq = 0; iq < ctl->nq; iq++) {
6830 char msg[5 * LEN];
6831 sprintf(msg, "Quantity %s range: %s ... %s %s",
6832 ctl->qnt_name[iq], ctl->qnt_format[iq],
6833 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
6834 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
6835 LOG(2, msg, mini, maxi);
6836 }
6837}
6838
6839/*****************************************************************************/
6840
6842 const char *filename,
6843 const ctl_t *ctl,
6844 met_t *met) {
6845
6846 /* Set timer... */
6847 SELECT_TIMER("WRITE_MET", "OUTPUT");
6848
6849 /* Write info... */
6850 LOG(1, "Write meteo data: %s", filename);
6851
6852 /* Check compression flags... */
6853#ifndef ZFP
6854 if (ctl->met_type == 3)
6855 ERRMSG("MPTRAC was compiled without ZFP compression!");
6856#endif
6857#ifndef ZSTD
6858 if (ctl->met_type == 4)
6859 ERRMSG("MPTRAC was compiled without ZSTD compression!");
6860#endif
6861#ifndef CMS
6862 if (ctl->met_type == 5)
6863 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6864#endif
6865#ifndef SZ3
6866 if (ctl->met_type == 7)
6867 ERRMSG("MPTRAC was compiled without SZ3 compression!");
6868#endif
6869
6870 /* Write netCDF data... */
6871 if (ctl->met_type == 0)
6872 write_met_nc(filename, ctl, met);
6873
6874 /* Write binary data... */
6875 else if (ctl->met_type >= 1 && ctl->met_type <= 7)
6876 write_met_bin(filename, ctl, met);
6877
6878 /* Not implemented... */
6879 else
6880 ERRMSG("MET_TYPE not implemented!");
6881}
6882
6883/*****************************************************************************/
6884
6886 const char *dirname,
6887 const ctl_t *ctl,
6888 met_t *met0,
6889 met_t *met1,
6890 atm_t *atm,
6891 const double t) {
6892
6893 char ext[10], filename[2 * LEN];
6894
6895 double r;
6896
6897 int year, mon, day, hour, min, sec;
6898
6899 /* Get time... */
6900 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
6901
6902 /* Update host... */
6903 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
6904 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
6905 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
6906 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
6907 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
6908 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
6909 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
6910
6911 /* Write atmospheric data... */
6912 if (ctl->atm_basename[0] != '-' &&
6913 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
6914 if (ctl->atm_type_out == 0)
6915 sprintf(ext, "tab");
6916 else if (ctl->atm_type_out == 1)
6917 sprintf(ext, "bin");
6918 else if (ctl->atm_type_out == 2)
6919 sprintf(ext, "nc");
6920 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6921 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
6922 mptrac_write_atm(filename, ctl, atm, t);
6923 }
6924
6925 /* Write gridded data... */
6926 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
6927 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
6928 dirname, ctl->grid_basename, year, mon, day, hour, min,
6929 ctl->grid_type == 0 ? "tab" : "nc");
6930 write_grid(filename, ctl, met0, met1, atm, t);
6931 }
6932
6933 /* Write CSI data... */
6934 if (ctl->csi_basename[0] != '-') {
6935 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
6936 write_csi(filename, ctl, atm, t);
6937 }
6938
6939 /* Write ensemble data... */
6940 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
6941 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
6942 dirname, ctl->ens_basename, year, mon, day, hour, min);
6943 write_ens(filename, ctl, atm, t);
6944 }
6945
6946 /* Write profile data... */
6947 if (ctl->prof_basename[0] != '-') {
6948 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
6949 write_prof(filename, ctl, met0, met1, atm, t);
6950 }
6951
6952 /* Write sample data... */
6953 if (ctl->sample_basename[0] != '-') {
6954 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
6955 write_sample(filename, ctl, met0, met1, atm, t);
6956 }
6957
6958 /* Write station data... */
6959 if (ctl->stat_basename[0] != '-') {
6960 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
6961 write_station(filename, ctl, atm, t);
6962 }
6963
6964 /* Write VTK data... */
6965 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
6966 static int nvtk;
6967 if (t == ctl->t_start)
6968 nvtk = 0;
6969 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
6970 write_vtk(filename, ctl, atm, t);
6971 }
6972}
6973
6974/*****************************************************************************/
6975
6977 const double p,
6978 const double h2o,
6979 const double hno3) {
6980
6981 /* Check water vapor volume mixing ratio... */
6982 const double h2o_help = MAX(h2o, 0.1e-6);
6983
6984 /* Calculate T_NAT... */
6985 const double p_hno3 = hno3 * p / 1.333224;
6986 const double p_h2o = h2o_help * p / 1.333224;
6987 const double a = 0.009179 - 0.00088 * log10(p_h2o);
6988 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
6989 const double c = -11397.0 / a;
6990 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
6991 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
6992 if (x2 > 0)
6993 tnat = x2;
6994
6995 return tnat;
6996}
6997
6998/*****************************************************************************/
6999
7001 const ctl_t *ctl,
7002 const atm_t *atm,
7003 const int ip,
7004 const double pbl,
7005 const double ps) {
7006
7007 /* Get pressure range... */
7008 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
7009 const double p0 = pbl;
7010
7011 /* Get weighting factor... */
7012 if (atm->p[ip] > p0)
7013 return 1;
7014 else if (atm->p[ip] < p1)
7015 return 0;
7016 else
7017 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
7018}
7019
7020/*****************************************************************************/
7021
7023 const char *filename,
7024 const ctl_t *ctl,
7025 atm_t *atm) {
7026
7027 /* Open file... */
7028 FILE *in;
7029 if (!(in = fopen(filename, "r"))) {
7030 WARN("Cannot open file!");
7031 return 0;
7032 }
7033
7034 /* Read line... */
7035 char line[LEN];
7036 while (fgets(line, LEN, in)) {
7037
7038 /* Read data... */
7039 char *tok;
7040 TOK(line, tok, "%lg", atm->time[atm->np]);
7041 TOK(NULL, tok, "%lg", atm->p[atm->np]);
7042 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
7043 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
7044 for (int iq = 0; iq < ctl->nq; iq++)
7045 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
7046
7047 /* Convert altitude to pressure... */
7048 atm->p[atm->np] = P(atm->p[atm->np]);
7049
7050 /* Increment data point counter... */
7051 if ((++atm->np) > NP)
7052 ERRMSG("Too many data points!");
7053 }
7054
7055 /* Close file... */
7056 fclose(in);
7057
7058 /* Return success... */
7059 return 1;
7060}
7061
7062/*****************************************************************************/
7063
7065 const char *filename,
7066 const ctl_t *ctl,
7067 atm_t *atm) {
7068
7069 /* Open file... */
7070 FILE *in;
7071 if (!(in = fopen(filename, "r")))
7072 return 0;
7073
7074 /* Check version of binary data... */
7075 int version;
7076 FREAD(&version, int,
7077 1,
7078 in);
7079 if (version != 100)
7080 ERRMSG("Wrong version of binary data!");
7081
7082 /* Read data... */
7083 FREAD(&atm->np, int,
7084 1,
7085 in);
7086 FREAD(atm->time, double,
7087 (size_t) atm->np,
7088 in);
7089 FREAD(atm->p, double,
7090 (size_t) atm->np,
7091 in);
7092 FREAD(atm->lon, double,
7093 (size_t) atm->np,
7094 in);
7095 FREAD(atm->lat, double,
7096 (size_t) atm->np,
7097 in);
7098 for (int iq = 0; iq < ctl->nq; iq++)
7099 FREAD(atm->q[iq], double,
7100 (size_t) atm->np,
7101 in);
7102
7103 /* Read final flag... */
7104 int final;
7105 FREAD(&final, int,
7106 1,
7107 in);
7108 if (final != 999)
7109 ERRMSG("Error while reading binary data!");
7110
7111 /* Close file... */
7112 fclose(in);
7113
7114 /* Return success... */
7115 return 1;
7116}
7117
7118/*****************************************************************************/
7119
7121 const char *filename,
7122 const ctl_t *ctl,
7123 atm_t *atm) {
7124
7125 int ncid, varid;
7126
7127 /* Open file... */
7128 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7129 return 0;
7130
7131 /* Get dimensions... */
7132 NC_INQ_DIM("NPARTS", &atm->np, 1, NP, 1);
7133
7134 /* Get time... */
7135 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
7136 NC(nc_get_var_double(ncid, varid, atm->time));
7137 } else {
7138 WARN("TIME_INIT not found use time instead!");
7139 double time_init;
7140 NC_GET_DOUBLE("time", &time_init, 1);
7141 for (int ip = 0; ip < atm->np; ip++) {
7142 atm->time[ip] = time_init;
7143 }
7144 }
7145
7146 /* Read zeta coordinate, pressure is optional... */
7147 if (ctl->advect_vert_coord == 1) {
7148 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
7149 NC_GET_DOUBLE("PRESS", atm->p, 0);
7150 }
7151
7152 /* Read pressure, zeta coordinate is optional... */
7153 else {
7154 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
7155 NC(nc_get_var_double(ncid, varid, atm->p));
7156 } else {
7157 WARN("PRESS_INIT not found use PRESS instead!");
7158 nc_inq_varid(ncid, "PRESS", &varid);
7159 NC(nc_get_var_double(ncid, varid, atm->p));
7160 }
7161 }
7162
7163 /* Read further quantities if requested... */
7164 for (int iq = 0; iq < ctl->nq; iq++)
7165 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7166
7167 /* Read longitude and latitude... */
7168 NC_GET_DOUBLE("LON", atm->lon, 1);
7169 NC_GET_DOUBLE("LAT", atm->lat, 1);
7170
7171 /* Close file... */
7172 NC(nc_close(ncid));
7173
7174 /* Return success... */
7175 return 1;
7176}
7177
7178/*****************************************************************************/
7179
7181 const char *filename,
7182 const ctl_t *ctl,
7183 atm_t *atm) {
7184
7185 int ncid, varid;
7186
7187 /* Open file... */
7188 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
7189 return 0;
7190
7191 /* Get dimensions... */
7192 NC_INQ_DIM("obs", &atm->np, 1, NP, 1);
7193
7194 /* Read geolocations... */
7195 NC_GET_DOUBLE("time", atm->time, 1);
7196 NC_GET_DOUBLE("press", atm->p, 1);
7197 NC_GET_DOUBLE("lon", atm->lon, 1);
7198 NC_GET_DOUBLE("lat", atm->lat, 1);
7199
7200 /* Read variables... */
7201 for (int iq = 0; iq < ctl->nq; iq++)
7202 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
7203
7204 /* Close file... */
7205 NC(nc_close(ncid));
7206
7207 /* Return success... */
7208 return 1;
7209}
7210
7211/*****************************************************************************/
7212
7214 const char *filename,
7215 clim_photo_t *photo) {
7216
7217 int ncid, varid;
7218
7219 /* Write info... */
7220 LOG(1, "Read photolysis rates: %s", filename);
7221
7222 /* Open netCDF file... */
7223 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7224 WARN("Photolysis rate data are missing!");
7225 return;
7226 }
7227
7228 /* Read pressure data... */
7229 NC_INQ_DIM("press", &photo->np, 2, CP, 1);
7230 NC_GET_DOUBLE("press", photo->p, 1);
7231 if (photo->p[0] < photo->p[1])
7232 ERRMSG("Pressure data are not descending!");
7233
7234 /* Read total column ozone data... */
7235 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3, 1);
7236 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
7237 if (photo->o3c[0] > photo->o3c[1])
7238 ERRMSG("Total column ozone data are not ascending!");
7239
7240 /* Read solar zenith angle data... */
7241 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA, 1);
7242 NC_GET_DOUBLE("sza", photo->sza, 1);
7243 if (photo->sza[0] > photo->sza[1])
7244 ERRMSG("Solar zenith angle data are not ascending!");
7245
7246 /* Read data... */
7247 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
7248 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
7249 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
7250 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
7251 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
7252 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
7253 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
7254 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
7255 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
7256
7257 /* Close netCDF file... */
7258 NC(nc_close(ncid));
7259
7260 /* Write info... */
7261 LOG(2, "Number of pressure levels: %d", photo->np);
7262 LOG(2, "Altitude levels: %g, %g ... %g km",
7263 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
7264 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7265 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
7266 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
7267 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
7268 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
7269 RAD2DEG(photo->sza[photo->nsza - 1]));
7270 LOG(2, "Number of total column ozone values: %d", photo->no3c);
7271 LOG(2, "Total column ozone: %g, %g ... %g DU",
7272 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
7273 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
7274 photo->n2o[0][0][0], photo->n2o[1][0][0],
7275 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7276 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
7277 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
7278 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7279 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
7280 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
7281 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7282 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
7283 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
7284 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7285 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
7286 photo->o2[0][0][0], photo->o2[1][0][0],
7287 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7288 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
7289 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
7290 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7291 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
7292 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
7293 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7294 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
7295 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
7296 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7297 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
7298 photo->h2o[0][0][0], photo->h2o[1][0][0],
7299 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
7300}
7301
7302/*****************************************************************************/
7303
7305 const int ncid,
7306 const char *varname,
7307 const clim_photo_t *photo,
7308 double var[CP][CSZA][CO3]) {
7309
7310 /* Allocate... */
7311 double *help;
7312 ALLOC(help, double,
7313 photo->np * photo->nsza * photo->no3c);
7314
7315 /* Read varible... */
7316 int varid;
7317 NC_GET_DOUBLE(varname, help, 1);
7318
7319 /* Copy data... */
7320 for (int ip = 0; ip < photo->np; ip++)
7321 for (int is = 0; is < photo->nsza; is++)
7322 for (int io = 0; io < photo->no3c; io++)
7323 var[ip][is][io] =
7324 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
7325
7326 /* Free... */
7327 free(help);
7328}
7329
7330/*****************************************************************************/
7331
7333 const char *filename,
7334 clim_ts_t *ts) {
7335
7336 /* Write info... */
7337 LOG(1, "Read climatological time series: %s", filename);
7338
7339 /* Open file... */
7340 FILE *in;
7341 if (!(in = fopen(filename, "r"))) {
7342 WARN("Cannot open file!");
7343 return 0;
7344 }
7345
7346 /* Read data... */
7347 char line[LEN];
7348 int nh = 0;
7349 while (fgets(line, LEN, in))
7350 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
7351
7352 /* Convert years to seconds... */
7353 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
7354
7355 /* Check data... */
7356 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
7357 ERRMSG("Time series must be ascending!");
7358
7359 /* Count time steps... */
7360 if ((++nh) >= CTS)
7361 ERRMSG("Too many data points!");
7362 }
7363
7364 /* Close file... */
7365 fclose(in);
7366
7367 /* Check number of data points... */
7368 ts->ntime = nh;
7369 if (nh < 2)
7370 ERRMSG("Not enough data points!");
7371
7372 /* Write info... */
7373 LOG(2, "Number of time steps: %d", ts->ntime);
7374 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
7375 ts->time[nh - 1]);
7376 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
7377 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
7378 (size_t) nh));
7379
7380 /* Exit success... */
7381 return 1;
7382}
7383
7384/*****************************************************************************/
7385
7387 const char *filename,
7388 const char *varname,
7389 clim_zm_t *zm) {
7390
7391 int ncid, varid, it, iy, iz, iz2, nt;
7392
7393 double *help, varmin = 1e99, varmax = -1e99;
7394
7395 /* Write info... */
7396 LOG(1, "Read %s data: %s", varname, filename);
7397
7398 /* Open netCDF file... */
7399 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7400 WARN("%s climatology data are missing!", varname);
7401 return;
7402 }
7403
7404 /* Read pressure data... */
7405 NC_INQ_DIM("press", &zm->np, 2, CP, 1);
7406 NC_GET_DOUBLE("press", zm->p, 1);
7407 if (zm->p[0] < zm->p[1])
7408 ERRMSG("Pressure data are not descending!");
7409
7410 /* Read latitudes... */
7411 NC_INQ_DIM("lat", &zm->nlat, 2, CY, 1);
7412 NC_GET_DOUBLE("lat", zm->lat, 1);
7413 if (zm->lat[0] > zm->lat[1])
7414 ERRMSG("Latitude data are not ascending!");
7415
7416 /* Set time data (for monthly means)... */
7417 zm->ntime = 12;
7418 zm->time[0] = 1209600.00;
7419 zm->time[1] = 3888000.00;
7420 zm->time[2] = 6393600.00;
7421 zm->time[3] = 9072000.00;
7422 zm->time[4] = 11664000.00;
7423 zm->time[5] = 14342400.00;
7424 zm->time[6] = 16934400.00;
7425 zm->time[7] = 19612800.00;
7426 zm->time[8] = 22291200.00;
7427 zm->time[9] = 24883200.00;
7428 zm->time[10] = 27561600.00;
7429 zm->time[11] = 30153600.00;
7430
7431 /* Check number of timesteps... */
7432 NC_INQ_DIM("time", &nt, 12, 12, 1);
7433
7434 /* Read data... */
7435 ALLOC(help, double,
7436 zm->nlat * zm->np * zm->ntime);
7437 NC_GET_DOUBLE(varname, help, 1);
7438 for (it = 0; it < zm->ntime; it++)
7439 for (iz = 0; iz < zm->np; iz++)
7440 for (iy = 0; iy < zm->nlat; iy++)
7441 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
7442 free(help);
7443
7444 /* Fix data gaps... */
7445 for (it = 0; it < zm->ntime; it++)
7446 for (iy = 0; iy < zm->nlat; iy++)
7447 for (iz = 0; iz < zm->np; iz++) {
7448 if (zm->vmr[it][iz][iy] < 0) {
7449 for (iz2 = 0; iz2 < zm->np; iz2++)
7450 if (zm->vmr[it][iz2][iy] >= 0) {
7451 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7452 break;
7453 }
7454 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
7455 if (zm->vmr[it][iz2][iy] >= 0) {
7456 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
7457 break;
7458 }
7459 }
7460 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
7461 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
7462 }
7463
7464 /* Close netCDF file... */
7465 NC(nc_close(ncid));
7466
7467 /* Write info... */
7468 LOG(2, "Number of time steps: %d", zm->ntime);
7469 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
7470 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
7471 LOG(2, "Number of pressure levels: %d", zm->np);
7472 LOG(2, "Altitude levels: %g, %g ... %g km",
7473 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
7474 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
7475 zm->p[1], zm->p[zm->np - 1]);
7476 LOG(2, "Number of latitudes: %d", zm->nlat);
7477 LOG(2, "Latitudes: %g, %g ... %g deg",
7478 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
7479 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
7480 varmax);
7481}
7482
7483/*****************************************************************************/
7484
7486 const char *filename,
7487 double kz[EP],
7488 double kw[EP],
7489 int *nk) {
7490
7491 /* Write info... */
7492 LOG(1, "Read kernel function: %s", filename);
7493
7494 /* Open file... */
7495 FILE *in;
7496 if (!(in = fopen(filename, "r")))
7497 ERRMSG("Cannot open file!");
7498
7499 /* Read data... */
7500 char line[LEN];
7501 int n = 0;
7502 while (fgets(line, LEN, in))
7503 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
7504 if (n > 0 && kz[n] < kz[n - 1])
7505 ERRMSG("Height levels must be ascending!");
7506 if ((++n) >= EP)
7507 ERRMSG("Too many height levels!");
7508 }
7509
7510 /* Close file... */
7511 fclose(in);
7512
7513 /* Check number of data points... */
7514 *nk = n;
7515 if (n < 2)
7516 ERRMSG("Not enough height levels!");
7517
7518 /* Normalize kernel function... */
7519 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
7520 for (int iz = 0; iz < n; iz++)
7521 kw[iz] /= kmax;
7522}
7523
7524/*****************************************************************************/
7525
7527 const char *filename,
7528 const ctl_t *ctl,
7529 met_t *met) {
7530
7531 FILE *in;
7532
7533 double r;
7534
7535 int year, mon, day, hour, min, sec;
7536
7537 /* Set timer... */
7538 SELECT_TIMER("READ_MET_BIN", "INPUT");
7539
7540 /* Open file... */
7541 if (!(in = fopen(filename, "r"))) {
7542 WARN("Cannot open file!");
7543 return 0;
7544 }
7545
7546 /* Check type of binary data... */
7547 int met_type;
7548 FREAD(&met_type, int,
7549 1,
7550 in);
7551 if (met_type != ctl->met_type)
7552 ERRMSG("Wrong MET_TYPE of binary data!");
7553
7554 /* Check version of binary data... */
7555 int version;
7556 FREAD(&version, int,
7557 1,
7558 in);
7559 if (version != 103)
7560 ERRMSG("Wrong version of binary data!");
7561
7562 /* Read time... */
7563 FREAD(&met->time, double,
7564 1,
7565 in);
7566 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7567 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7568 met->time, year, mon, day, hour, min);
7569 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7570 || day < 1 || day > 31 || hour < 0 || hour > 23)
7571 ERRMSG("Error while reading time!");
7572
7573 /* Read dimensions... */
7574 FREAD(&met->nx, int,
7575 1,
7576 in);
7577 LOG(2, "Number of longitudes: %d", met->nx);
7578 if (met->nx < 2 || met->nx > EX)
7579 ERRMSG("Number of longitudes out of range!");
7580
7581 FREAD(&met->ny, int,
7582 1,
7583 in);
7584 LOG(2, "Number of latitudes: %d", met->ny);
7585 if (met->ny < 2 || met->ny > EY)
7586 ERRMSG("Number of latitudes out of range!");
7587
7588 FREAD(&met->np, int,
7589 1,
7590 in);
7591 LOG(2, "Number of levels: %d", met->np);
7592 if (met->np < 2 || met->np > EP)
7593 ERRMSG("Number of levels out of range!");
7594
7595 /* Read grid... */
7596 FREAD(met->lon, double,
7597 (size_t) met->nx,
7598 in);
7599 LOG(2, "Longitudes: %g, %g ... %g deg",
7600 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7601
7602 FREAD(met->lat, double,
7603 (size_t) met->ny,
7604 in);
7605 LOG(2, "Latitudes: %g, %g ... %g deg",
7606 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7607
7608 FREAD(met->p, double,
7609 (size_t) met->np,
7610 in);
7611 LOG(2, "Altitude levels: %g, %g ... %g km",
7612 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7613 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7614 met->p[0], met->p[1], met->p[met->np - 1]);
7615
7616 /* Read surface data... */
7617 read_met_bin_2d(in, met, met->ps, "PS");
7618 read_met_bin_2d(in, met, met->ts, "TS");
7619 read_met_bin_2d(in, met, met->zs, "ZS");
7620 read_met_bin_2d(in, met, met->us, "US");
7621 read_met_bin_2d(in, met, met->vs, "VS");
7622 read_met_bin_2d(in, met, met->ess, "ESS");
7623 read_met_bin_2d(in, met, met->nss, "NSS");
7624 read_met_bin_2d(in, met, met->shf, "SHF");
7625 read_met_bin_2d(in, met, met->lsm, "LSM");
7626 read_met_bin_2d(in, met, met->sst, "SST");
7627 read_met_bin_2d(in, met, met->pbl, "PBL");
7628 read_met_bin_2d(in, met, met->pt, "PT");
7629 read_met_bin_2d(in, met, met->tt, "TT");
7630 read_met_bin_2d(in, met, met->zt, "ZT");
7631 read_met_bin_2d(in, met, met->h2ot, "H2OT");
7632 read_met_bin_2d(in, met, met->pct, "PCT");
7633 read_met_bin_2d(in, met, met->pcb, "PCB");
7634 read_met_bin_2d(in, met, met->cl, "CL");
7635 read_met_bin_2d(in, met, met->plcl, "PLCL");
7636 read_met_bin_2d(in, met, met->plfc, "PLFC");
7637 read_met_bin_2d(in, met, met->pel, "PEL");
7638 read_met_bin_2d(in, met, met->cape, "CAPE");
7639 read_met_bin_2d(in, met, met->cin, "CIN");
7640 read_met_bin_2d(in, met, met->o3c, "O3C");
7641
7642 /* Read level data... */
7643 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
7644 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
7645 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
7646 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
7647 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
7648 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
7649 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
7650 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
7651 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
7652 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
7653 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
7654 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
7655 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
7656
7657 /* Read final flag... */
7658 int final;
7659 FREAD(&final, int,
7660 1,
7661 in);
7662 if (final != 999)
7663 ERRMSG("Error while reading binary data!");
7664
7665 /* Close file... */
7666 fclose(in);
7667
7668 /* Return success... */
7669 return 1;
7670}
7671
7672/*****************************************************************************/
7673
7675 FILE *in,
7676 const met_t *met,
7677 float var[EX][EY],
7678 const char *varname) {
7679
7680 float *help;
7681
7682 /* Allocate... */
7683 ALLOC(help, float,
7684 EX * EY);
7685
7686 /* Read uncompressed... */
7687 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
7688 FREAD(help, float,
7689 (size_t) (met->nx * met->ny),
7690 in);
7691
7692 /* Copy data... */
7693 for (int ix = 0; ix < met->nx; ix++)
7694 for (int iy = 0; iy < met->ny; iy++)
7695 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
7696
7697 /* Free... */
7698 free(help);
7699}
7700
7701/*****************************************************************************/
7702
7704 FILE *in,
7705 const ctl_t *ctl,
7706 const met_t *met,
7707 float var[EX][EY][EP],
7708 const char *varname,
7709 const float bound_min,
7710 const float bound_max) {
7711
7712 float *help;
7713
7714 /* Allocate... */
7715 ALLOC(help, float,
7716 EX * EY * EP);
7717
7718 /* Read uncompressed data... */
7719 if (ctl->met_type == 1) {
7720 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
7721 FREAD(help, float,
7722 (size_t) (met->nx * met->ny * met->np),
7723 in);
7724 }
7725
7726 /* Read packed data... */
7727 else if (ctl->met_type == 2)
7728 compress_pck(varname, help, (size_t) (met->ny * met->nx),
7729 (size_t) met->np, 1, in);
7730
7731 /* Read ZFP data... */
7732 else if (ctl->met_type == 3) {
7733#ifdef ZFP
7734 int precision;
7735 FREAD(&precision, int,
7736 1,
7737 in);
7738
7739 double tolerance;
7740 FREAD(&tolerance, double,
7741 1,
7742 in);
7743
7744 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
7745 tolerance, 1, in);
7746#else
7747 ERRMSG("MPTRAC was compiled without ZFP compression!");
7748#endif
7749 }
7750
7751 /* Read zstd data... */
7752 else if (ctl->met_type == 4) {
7753#ifdef ZSTD
7754 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
7755 ctl->met_zstd_level, in);
7756#else
7757 ERRMSG("MPTRAC was compiled without ZSTD compression!");
7758#endif
7759 }
7760
7761 /* Read cmultiscale data... */
7762 else if (ctl->met_type == 5) {
7763#ifdef CMS
7764 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
7765 (size_t) met->np, met->p, 1, in);
7766#else
7767 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
7768#endif
7769 }
7770
7771 /* Read SZ3 data... */
7772 else if (ctl->met_type == 7) {
7773#ifdef SZ3
7774 int precision;
7775 FREAD(&precision, int,
7776 1,
7777 in);
7778
7779 double tolerance;
7780 FREAD(&tolerance, double,
7781 1,
7782 in);
7783
7784 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
7785 tolerance, 1, in);
7786#else
7787 ERRMSG("MPTRAC was compiled without sz3 compression!");
7788#endif
7789 }
7790
7791 /* Copy data... */
7792#pragma omp parallel for default(shared) collapse(2)
7793 for (int ix = 0; ix < met->nx; ix++)
7794 for (int iy = 0; iy < met->ny; iy++)
7795 for (int ip = 0; ip < met->np; ip++) {
7796 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7797 if (var[ix][iy][ip] < bound_min)
7798 var[ix][iy][ip] = bound_min;
7799 else if (var[ix][iy][ip] > bound_max)
7800 var[ix][iy][ip] = bound_max;
7801 }
7802
7803 /* Free... */
7804 free(help);
7805}
7806
7807/*****************************************************************************/
7808
7810 const ctl_t *ctl,
7811 const clim_t *clim,
7812 met_t *met) {
7813
7814 /* Check parameters... */
7815 if (ctl->met_cape != 1)
7816 return;
7817
7818 /* Set timer... */
7819 SELECT_TIMER("READ_MET_CAPE", "METPROC");
7820 LOG(2, "Calculate CAPE...");
7821
7822 /* Vertical spacing (about 100 m)... */
7823 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
7824
7825 /* Loop over columns... */
7826#pragma omp parallel for default(shared) collapse(2)
7827 for (int ix = 0; ix < met->nx; ix++)
7828 for (int iy = 0; iy < met->ny; iy++) {
7829
7830 /* Get potential temperature and water vapor at lowest 50 hPa... */
7831 int n = 0;
7832 double h2o = 0, t, theta = 0;
7833 double pbot = MIN(met->ps[ix][iy], met->p[0]);
7834 double ptop = pbot - 50.;
7835 for (int ip = 0; ip < met->np; ip++) {
7836 if (met->p[ip] <= pbot) {
7837 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
7838 h2o += met->h2o[ix][iy][ip];
7839 n++;
7840 }
7841 if (met->p[ip] < ptop && n > 0)
7842 break;
7843 }
7844 theta /= n;
7845 h2o /= n;
7846
7847 /* Cannot compute anything if water vapor is missing... */
7848 met->plcl[ix][iy] = NAN;
7849 met->plfc[ix][iy] = NAN;
7850 met->pel[ix][iy] = NAN;
7851 met->cape[ix][iy] = NAN;
7852 met->cin[ix][iy] = NAN;
7853 if (h2o <= 0)
7854 continue;
7855
7856 /* Find lifted condensation level (LCL)... */
7857 ptop = P(20.);
7858 pbot = met->ps[ix][iy];
7859 do {
7860 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
7861 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
7862 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
7863 ptop = met->plcl[ix][iy];
7864 else
7865 pbot = met->plcl[ix][iy];
7866 } while (pbot - ptop > 0.1);
7867
7868 /* Calculate CIN up to LCL... */
7870 double dcape, dz, h2o_env, t_env;
7871 double p = met->ps[ix][iy];
7872 met->cape[ix][iy] = met->cin[ix][iy] = 0;
7873 do {
7874 dz = dz0 * TVIRT(t, h2o);
7875 p /= pfac;
7876 t = theta / pow(1000. / p, 0.286);
7877 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7878 &t_env, ci, cw, 1);
7879 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7880 &h2o_env, ci, cw, 0);
7881 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7882 TVIRT(t_env, h2o_env) * dz;
7883 if (dcape < 0)
7884 met->cin[ix][iy] += fabsf((float) dcape);
7885 } while (p > met->plcl[ix][iy]);
7886
7887 /* Calculate level of free convection (LFC), equilibrium level (EL),
7888 and convective available potential energy (CAPE)... */
7889 dcape = 0;
7890 p = met->plcl[ix][iy];
7891 t = theta / pow(1000. / p, 0.286);
7892 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
7893 do {
7894 dz = dz0 * TVIRT(t, h2o);
7895 p /= pfac;
7896 t -= lapse_rate(t, h2o) * dz;
7897 double psat = PSAT(t);
7898 h2o = psat / (p - (1. - EPS) * psat);
7899 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
7900 &t_env, ci, cw, 1);
7901 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
7902 &h2o_env, ci, cw, 0);
7903 double dcape_old = dcape;
7904 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
7905 TVIRT(t_env, h2o_env) * dz;
7906 if (dcape > 0) {
7907 met->cape[ix][iy] += (float) dcape;
7908 if (!isfinite(met->plfc[ix][iy]))
7909 met->plfc[ix][iy] = (float) p;
7910 } else if (dcape_old > 0)
7911 met->pel[ix][iy] = (float) p;
7912 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
7913 met->cin[ix][iy] += fabsf((float) dcape);
7914 } while (p > ptop);
7915
7916 /* Check results... */
7917 if (!isfinite(met->plfc[ix][iy]))
7918 met->cin[ix][iy] = NAN;
7919 }
7920}
7921
7922/*****************************************************************************/
7923
7925 met_t *met) {
7926
7927 /* Set timer... */
7928 SELECT_TIMER("READ_MET_CLOUD", "METPROC");
7929 LOG(2, "Calculate cloud data...");
7930
7931 /* Thresholds for cloud detection... */
7932 const double ccmin = 0.01, cwmin = 1e-6;
7933
7934 /* Loop over columns... */
7935#pragma omp parallel for default(shared) collapse(2)
7936 for (int ix = 0; ix < met->nx; ix++)
7937 for (int iy = 0; iy < met->ny; iy++) {
7938
7939 /* Init... */
7940 met->pct[ix][iy] = NAN;
7941 met->pcb[ix][iy] = NAN;
7942 met->cl[ix][iy] = 0;
7943
7944 /* Loop over pressure levels... */
7945 for (int ip = 0; ip < met->np - 1; ip++) {
7946
7947 /* Check pressure... */
7948 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
7949 continue;
7950
7951 /* Check ice water and liquid water content... */
7952 if (met->cc[ix][iy][ip] > ccmin
7953 && (met->lwc[ix][iy][ip] > cwmin
7954 || met->rwc[ix][iy][ip] > cwmin
7955 || met->iwc[ix][iy][ip] > cwmin
7956 || met->swc[ix][iy][ip] > cwmin)) {
7957
7958 /* Get cloud top pressure ... */
7959 met->pct[ix][iy]
7960 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
7961
7962 /* Get cloud bottom pressure ... */
7963 if (!isfinite(met->pcb[ix][iy]))
7964 met->pcb[ix][iy]
7965 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
7966 }
7967
7968 /* Get cloud water... */
7969 met->cl[ix][iy] += (float)
7970 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
7971 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
7972 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
7973 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
7974 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
7975 }
7976 }
7977}
7978
7979/*****************************************************************************/
7980
7982 const ctl_t *ctl,
7983 met_t *met) {
7984
7985 met_t *help;
7986
7987 /* Check parameters... */
7988 if (ctl->met_detrend <= 0)
7989 return;
7990
7991 /* Set timer... */
7992 SELECT_TIMER("READ_MET_DETREND", "METPROC");
7993 LOG(2, "Detrend meteo data...");
7994
7995 /* Allocate... */
7996 ALLOC(help, met_t, 1);
7997
7998 /* Calculate standard deviation... */
7999 const double sigma = ctl->met_detrend / 2.355;
8000 const double tssq = 2. * SQR(sigma);
8001
8002 /* Calculate box size in latitude... */
8003 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
8004 sy = MIN(MAX(1, sy), met->ny / 2);
8005
8006 /* Calculate background... */
8007#pragma omp parallel for default(shared) collapse(2)
8008 for (int ix = 0; ix < met->nx; ix++) {
8009 for (int iy = 0; iy < met->ny; iy++) {
8010
8011 /* Calculate Cartesian coordinates... */
8012 double x0[3];
8013 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
8014
8015 /* Calculate box size in longitude... */
8016 int sx =
8017 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
8018 fabs(met->lon[1] - met->lon[0]));
8019 sx = MIN(MAX(1, sx), met->nx / 2);
8020
8021 /* Init... */
8022 float wsum = 0;
8023 for (int ip = 0; ip < met->np; ip++) {
8024 help->t[ix][iy][ip] = 0;
8025 help->u[ix][iy][ip] = 0;
8026 help->v[ix][iy][ip] = 0;
8027 help->w[ix][iy][ip] = 0;
8028 }
8029
8030 /* Loop over neighboring grid points... */
8031 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
8032 int ix3 = ix2;
8033 if (ix3 < 0)
8034 ix3 += met->nx;
8035 else if (ix3 >= met->nx)
8036 ix3 -= met->nx;
8037 for (int iy2 = MAX(iy - sy, 0);
8038 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
8039
8040 /* Calculate Cartesian coordinates... */
8041 double x1[3];
8042 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
8043
8044 /* Calculate weighting factor... */
8045 const float w = (float) exp(-DIST2(x0, x1) / tssq);
8046
8047 /* Add data... */
8048 wsum += w;
8049 for (int ip = 0; ip < met->np; ip++) {
8050 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
8051 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
8052 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
8053 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
8054 }
8055 }
8056 }
8057
8058 /* Normalize... */
8059 for (int ip = 0; ip < met->np; ip++) {
8060 help->t[ix][iy][ip] /= wsum;
8061 help->u[ix][iy][ip] /= wsum;
8062 help->v[ix][iy][ip] /= wsum;
8063 help->w[ix][iy][ip] /= wsum;
8064 }
8065 }
8066 }
8067
8068 /* Subtract background... */
8069#pragma omp parallel for default(shared) collapse(3)
8070 for (int ix = 0; ix < met->nx; ix++)
8071 for (int iy = 0; iy < met->ny; iy++)
8072 for (int ip = 0; ip < met->np; ip++) {
8073 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
8074 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
8075 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
8076 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
8077 }
8078
8079 /* Free... */
8080 free(help);
8081}
8082
8083/*****************************************************************************/
8084
8086 met_t *met) {
8087
8088 /* Set timer... */
8089 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC");
8090 LOG(2, "Extrapolate meteo data...");
8091
8092 /* Loop over columns... */
8093#pragma omp parallel for default(shared) collapse(2)
8094 for (int ix = 0; ix < met->nx; ix++)
8095 for (int iy = 0; iy < met->ny; iy++) {
8096
8097 /* Find lowest valid data point... */
8098 int ip0;
8099 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
8100 if (!isfinite(met->t[ix][iy][ip0])
8101 || !isfinite(met->u[ix][iy][ip0])
8102 || !isfinite(met->v[ix][iy][ip0])
8103 || !isfinite(met->w[ix][iy][ip0]))
8104 break;
8105
8106 /* Extrapolate... */
8107 for (int ip = ip0; ip >= 0; ip--) {
8108 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
8109 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
8110 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
8111 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
8112 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
8113 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
8114 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
8115 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
8116 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
8117 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
8118 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
8119 }
8120 }
8121}
8122
8123/*****************************************************************************/
8124
8126 const ctl_t *ctl,
8127 met_t *met) {
8128
8129 float *help;
8130
8131 double logp[EP];
8132
8133 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
8134
8135 /* Set timer... */
8136 SELECT_TIMER("READ_MET_GEOPOT", "METPROC");
8137 LOG(2, "Calculate geopotential heights...");
8138
8139 /* Allocate... */
8140 ALLOC(help, float,
8141 EX * EY * EP);
8142
8143 /* Calculate log pressure... */
8144#pragma omp parallel for default(shared)
8145 for (int ip = 0; ip < met->np; ip++)
8146 logp[ip] = log(met->p[ip]);
8147
8148 /* Apply hydrostatic equation to calculate geopotential heights... */
8149#pragma omp parallel for default(shared) collapse(2)
8150 for (int ix = 0; ix < met->nx; ix++)
8151 for (int iy = 0; iy < met->ny; iy++) {
8152
8153 /* Get surface height and pressure... */
8154 const double zs = met->zs[ix][iy];
8155 const double lnps = log(met->ps[ix][iy]);
8156
8157 /* Get temperature and water vapor at the surface... */
8158 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
8159 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
8160 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
8161 const double h2os =
8162 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
8163 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
8164
8165 /* Upper part of profile... */
8166 met->z[ix][iy][ip0 + 1]
8167 = (float) (zs +
8168 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
8169 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
8170 for (int ip = ip0 + 2; ip < met->np; ip++)
8171 met->z[ix][iy][ip]
8172 = (float) (met->z[ix][iy][ip - 1] +
8173 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
8174 met->h2o[ix][iy][ip - 1], logp[ip],
8175 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8176
8177 /* Lower part of profile... */
8178 met->z[ix][iy][ip0]
8179 = (float) (zs +
8180 ZDIFF(lnps, ts, h2os, logp[ip0],
8181 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
8182 for (int ip = ip0 - 1; ip >= 0; ip--)
8183 met->z[ix][iy][ip]
8184 = (float) (met->z[ix][iy][ip + 1] +
8185 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
8186 met->h2o[ix][iy][ip + 1], logp[ip],
8187 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
8188 }
8189
8190 /* Check control parameters... */
8191 if (dx == 0 || dy == 0)
8192 return;
8193
8194 /* Default smoothing parameters... */
8195 if (dx < 0 || dy < 0) {
8196 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
8197 dx = 3;
8198 dy = 2;
8199 } else {
8200 dx = 6;
8201 dy = 4;
8202 }
8203 }
8204
8205 /* Calculate weights for smoothing... */
8206 float ws[dx + 1][dy + 1];
8207#pragma omp parallel for default(shared) collapse(2)
8208 for (int ix = 0; ix <= dx; ix++)
8209 for (int iy = 0; iy < dy; iy++)
8210 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
8211 * (1.0f - (float) iy / (float) dy);
8212
8213 /* Copy data... */
8214#pragma omp parallel for default(shared) collapse(3)
8215 for (int ix = 0; ix < met->nx; ix++)
8216 for (int iy = 0; iy < met->ny; iy++)
8217 for (int ip = 0; ip < met->np; ip++)
8218 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
8219
8220 /* Horizontal smoothing... */
8221#pragma omp parallel for default(shared) collapse(3)
8222 for (int ip = 0; ip < met->np; ip++)
8223 for (int ix = 0; ix < met->nx; ix++)
8224 for (int iy = 0; iy < met->ny; iy++) {
8225 float res = 0, wsum = 0;
8226 int iy0 = MAX(iy - dy + 1, 0);
8227 int iy1 = MIN(iy + dy - 1, met->ny - 1);
8228 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
8229 int ix3 = ix2;
8230 if (ix3 < 0)
8231 ix3 += met->nx;
8232 else if (ix3 >= met->nx)
8233 ix3 -= met->nx;
8234 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
8235 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
8236 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
8237 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
8238 wsum += w;
8239 }
8240 }
8241 if (wsum > 0)
8242 met->z[ix][iy][ip] = res / wsum;
8243 else
8244 met->z[ix][iy][ip] = NAN;
8245 }
8246
8247 /* Free... */
8248 free(help);
8249}
8250
8251/*****************************************************************************/
8252
8254 const char *filename,
8255 const int ncid,
8256 const ctl_t *ctl,
8257 met_t *met,
8258 dd_t *dd) {
8259
8260 char levname[LEN], tstr[10];
8261
8262 double rtime = 0, r, r2;
8263
8264 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
8265 year, mon, day, hour, min, sec;
8266
8267 size_t dimlen;
8268
8269 /* Set timer... */
8270 SELECT_TIMER("READ_MET_NC_GRID", "INPUT");
8271 LOG(2, "Read meteo grid information...");
8272
8273 /* MPTRAC meteo files... */
8274 if (!ctl->met_clams) {
8275
8276 /* Get time from filename... */
8277 met->time = time_from_filename(filename, 16);
8278
8279 /* Check time information from data file... */
8280 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
8281 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
8282 NC(nc_get_var_double(ncid, varid, &rtime));
8283 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
8284 WARN("Time information in meteo file does not match filename!");
8285 } else
8286 WARN("Time information in meteo file is missing!");
8287 }
8288
8289 /* CLaMS meteo files... */
8290 else {
8291
8292 /* Read time from file... */
8293 NC_GET_DOUBLE("time", &rtime, 0);
8294
8295 /* Get time from filename (considering the century)... */
8296 if (rtime < 0)
8297 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
8298 else
8299 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
8300 year = atoi(tstr);
8301 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
8302 mon = atoi(tstr);
8303 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
8304 day = atoi(tstr);
8305 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
8306 hour = atoi(tstr);
8307 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
8308 }
8309
8310 /* Check time... */
8311 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
8312 || day < 1 || day > 31 || hour < 0 || hour > 23)
8313 ERRMSG("Cannot read time from filename!");
8314 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
8315 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8316 met->time, year2, mon2, day2, hour2, min2);
8317
8318 /* Get vertical dimension... */
8319 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
8320 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
8321 ERRMSG
8322 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
8323
8324 NC(nc_inq_varndims(ncid, varid, &ndims));
8325 NC(nc_inq_vardimid(ncid, varid, dimids));
8326
8327 if (ndims == 4) {
8328 NC(nc_inq_dim
8329 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
8330 } else if (ndims == 3) {
8331 NC(nc_inq_dim
8332 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
8333 } else
8334 ERRMSG("Cannot determine vertical dimension!")
8335 met->np = (int) dimlen;
8336
8337 LOG(2, "Number of levels: %d", met->np);
8338 if (met->np < 2 || met->np > EP)
8339 ERRMSG("Number of levels out of range!");
8340
8341 if (!ctl->dd) {
8342
8343 /* Get grid dimensions... */
8344 NC_INQ_DIM("lon", &met->nx, 2, EX, 1);
8345 LOG(2, "Number of longitudes: %d", met->nx);
8346
8347 NC_INQ_DIM("lat", &met->ny, 2, EY, 1);
8348 LOG(2, "Number of latitudes: %d", met->ny);
8349
8350 /* Read longitudes and latitudes... */
8351 NC_GET_DOUBLE("lon", met->lon, 1);
8352 LOG(2, "Longitudes: %g, %g ... %g deg",
8353 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
8354 NC_GET_DOUBLE("lat", met->lat, 1);
8355 LOG(2, "Latitudes: %g, %g ... %g deg",
8356 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
8357
8358 } else {
8359
8360 /* Use 'naive', i.e. equidistant lat-lon domain decomposition... */
8361 read_met_nc_grid_dd_naive(dd, ctl, met, ncid);
8362
8363 }
8364
8365 /* Read pressure levels... */
8366 if (ctl->met_np <= 0) {
8367 NC_GET_DOUBLE(levname, met->p, 1);
8368 for (int ip = 0; ip < met->np; ip++)
8369 met->p[ip] /= 100.;
8370 LOG(2, "Altitude levels: %g, %g ... %g km",
8371 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
8372 LOG(2, "Pressure levels: %g, %g ... %g hPa",
8373 met->p[0], met->p[1], met->p[met->np - 1]);
8374 }
8375
8376 /* Read hybrid levels... */
8377 if (strcasecmp(levname, "hybrid") == 0)
8378 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
8379
8380 /* Read model level coefficients from file... */
8381 if (ctl->met_vert_coord == 2) {
8382 NC_GET_DOUBLE("hyam", met->hyam, 1);
8383 NC_GET_DOUBLE("hybm", met->hybm, 1);
8384 }
8385
8386 /* Copy model level coefficients from control parameters... */
8387 else if (ctl->met_vert_coord == 3 || ctl->met_vert_coord == 4) {
8388 if (ctl->met_nlev <= 0)
8389 ERRMSG("You need to specify MET_NLEV, MET_LEV_HYAM, and MET_LEV_HYBM!");
8390 for (int ip = 0; ip < ctl->met_nlev; ip++) {
8391 met->hyam[ip] = ctl->met_lev_hyam[ip];
8392 met->hybm[ip] = ctl->met_lev_hybm[ip];
8393 }
8394 }
8395
8396 /* Calculate eta levels... */
8397 for (int k = 0; k < MAX(met->np, ctl->met_nlev); ++k) {
8398 met->eta[k] = met->hyam[k] / 100000.0 + met->hybm[k];
8399 if (ctl->met_vert_coord >= 2 && k > 0 && met->eta[k] <= met->eta[k - 1])
8400 ERRMSG("Eta levels must be ascending!");
8401 }
8402
8403 /* Check horizontal grid spacing... */
8404 for (int ix = 2; ix < met->nx; ix++)
8405 if (fabs
8406 (fabs(met->lon[ix] - met->lon[ix - 1]) -
8407 fabs(met->lon[1] - met->lon[0])) > 0.001)
8408 ERRMSG("No regular grid spacing in longitudes!");
8409 for (int iy = 2; iy < met->ny; iy++)
8410 if (fabs
8411 (fabs(met->lat[iy] - met->lat[iy - 1]) -
8412 fabs(met->lat[1] - met->lat[0])) > 0.001) {
8413 WARN("No regular grid spacing in latitudes!");
8414 break;
8415 }
8416}
8417
8418/*****************************************************************************/
8419
8421 const int ncid,
8422 const ctl_t *ctl,
8423 met_t *met,
8424 dd_t *dd) {
8425
8426 /* Set timer... */
8427 SELECT_TIMER("READ_MET_SURFACE", "INPUT");
8428 LOG(2, "Read surface data...");
8429
8430 /* Read surface pressure... */
8431 if (read_met_nc_2d
8432 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, dd, met->ps,
8433 1.0f, 1)) {
8434 for (int ix = 0; ix < met->nx; ix++)
8435 for (int iy = 0; iy < met->ny; iy++)
8436 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8437 } else
8438 if (!read_met_nc_2d
8439 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, dd, met->ps,
8440 0.01f, 1)) {
8441 WARN("Cannot not read surface pressure data (use lowest level)!");
8442 for (int ix = 0; ix < met->nx; ix++)
8443 for (int iy = 0; iy < met->ny; iy++)
8444 met->ps[ix][iy]
8445 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
8446 }
8447
8448 /* MPTRAC meteo data... */
8449 if (ctl->met_clams == 0) {
8450
8451 /* Read geopotential height at the surface... */
8452 if (!read_met_nc_2d
8453 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8454 (float) (1. / (1000. * G0)), 1))
8455 if (!read_met_nc_2d
8456 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, dd, met->zs,
8457 (float) (1. / 1000.), 1))
8458 WARN("Cannot read surface geopotential height!");
8459 }
8460
8461 /* CLaMS meteo data... */
8462 else {
8463
8464 /* Read geopotential height at the surface
8465 (use lowermost level of 3-D data field)... */
8466 float *help;
8467 ALLOC(help, float,
8468 EX * EY * EP);
8469 memcpy(help, met->pl, sizeof(met->pl));
8470 if (!read_met_nc_3d
8471 (ncid, "gph", "GPH", NULL, NULL, ctl, met, dd, met->pl,
8472 (float) (1e-3 / G0)))
8473 ERRMSG("Cannot read geopotential height!");
8474 for (int ix = 0; ix < met->nx; ix++)
8475 for (int iy = 0; iy < met->ny; iy++)
8476 met->zs[ix][iy] = met->pl[ix][iy][0];
8477 memcpy(met->pl, help, sizeof(met->pl));
8478 free(help);
8479 }
8480
8481 /* Read temperature at the surface... */
8482 if (!read_met_nc_2d
8483 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, dd, met->ts, 1.0,
8484 1))
8485 WARN("Cannot read surface temperature!");
8486
8487 /* Read zonal wind at the surface... */
8488 if (!read_met_nc_2d
8489 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, dd,
8490 met->us, 1.0, 1))
8491 WARN("Cannot read surface zonal wind!");
8492
8493 /* Read meridional wind at the surface... */
8494 if (!read_met_nc_2d
8495 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, dd,
8496 met->vs, 1.0, 1))
8497 WARN("Cannot read surface meridional wind!");
8498
8499 /* Read eastward turbulent surface stress... */
8500 if (!read_met_nc_2d
8501 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, dd, met->ess,
8502 1.0, 1))
8503 WARN("Cannot read eastward turbulent surface stress!");
8504
8505 /* Read northward turbulent surface stress... */
8506 if (!read_met_nc_2d
8507 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, dd, met->nss,
8508 1.0, 1))
8509 WARN("Cannot read nothward turbulent surface stress!");
8510
8511 /* Read surface sensible heat flux... */
8512 if (!read_met_nc_2d
8513 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, dd, met->shf,
8514 1.0, 1))
8515 WARN("Cannot read surface sensible heat flux!");
8516
8517 /* Read land-sea mask... */
8518 if (!read_met_nc_2d
8519 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, dd, met->lsm,
8520 1.0, 1))
8521 WARN("Cannot read land-sea mask!");
8522
8523 /* Read sea surface temperature... */
8524 if (!read_met_nc_2d
8525 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, dd, met->sst,
8526 1.0, 1))
8527 WARN("Cannot read sea surface temperature!");
8528
8529 /* Read PBL... */
8530 if (ctl->met_pbl == 0)
8531 if (!read_met_nc_2d
8532 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8533 0.01f, 1))
8534 WARN("Cannot read planetary boundary layer pressure!");
8535 if (ctl->met_pbl == 1)
8536 if (!read_met_nc_2d
8537 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, dd, met->pbl,
8538 0.001f, 1))
8539 WARN("Cannot read planetary boundary layer height!");
8540
8541 /* Read CAPE... */
8542 if (ctl->met_cape == 0)
8543 if (!read_met_nc_2d
8544 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, dd,
8545 met->cape, 1.0, 1))
8546 WARN("Cannot read CAPE!");
8547
8548 /* Read CIN... */
8549 if (ctl->met_cape == 0)
8550 if (!read_met_nc_2d
8551 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, dd, met->cin,
8552 1.0, 1))
8553 WARN("Cannot read convective inhibition!");
8554}
8555
8556/*****************************************************************************/
8557
8559 const int ncid,
8560 const ctl_t *ctl,
8561 met_t *met,
8562 dd_t *dd) {
8563
8564 /* Set timer... */
8565 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT");
8566 LOG(2, "Read level data...");
8567
8568 /* Read temperature... */
8569 if (!read_met_nc_3d
8570 (ncid, "t", "T", "temp", "TEMP", ctl, met, dd, met->t, 1.0))
8571 ERRMSG("Cannot read temperature!");
8572
8573 /* Read horizontal wind and vertical velocity... */
8574 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, dd, met->u, 1.0))
8575 ERRMSG("Cannot read zonal wind!");
8576 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, dd, met->v, 1.0))
8577 ERRMSG("Cannot read meridional wind!");
8578 if (!read_met_nc_3d
8579 (ncid, "w", "W", "omega", "OMEGA", ctl, met, dd, met->w, 0.01f))
8580 WARN("Cannot read vertical velocity!");
8581
8582 /* Read water vapor... */
8583 if (!ctl->met_relhum) {
8584 if (!read_met_nc_3d
8585 (ncid, "q", "Q", "sh", "SH", ctl, met, dd, met->h2o,
8586 (float) (MA / MH2O)))
8587 WARN("Cannot read specific humidity!");
8588 } else {
8589 if (!read_met_nc_3d
8590 (ncid, "rh", "RH", NULL, NULL, ctl, met, dd, met->h2o, 0.01f))
8591 WARN("Cannot read relative humidity!");
8592#pragma omp parallel for default(shared) collapse(2)
8593 for (int ix = 0; ix < met->nx; ix++)
8594 for (int iy = 0; iy < met->ny; iy++)
8595 for (int ip = 0; ip < met->np; ip++) {
8596 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
8597 met->h2o[ix][iy][ip] =
8598 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
8599 }
8600 }
8601
8602 /* Read ozone... */
8603 if (!read_met_nc_3d
8604 (ncid, "o3", "O3", NULL, NULL, ctl, met, dd, met->o3,
8605 (float) (MA / MO3)))
8606 WARN("Cannot read ozone data!");
8607
8608 /* Read cloud data... */
8609 if (!read_met_nc_3d
8610 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, dd, met->lwc, 1.0))
8611 WARN("Cannot read cloud liquid water content!");
8612 if (!read_met_nc_3d
8613 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, dd, met->rwc, 1.0))
8614 WARN("Cannot read cloud rain water content!");
8615 if (!read_met_nc_3d
8616 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, dd, met->iwc, 1.0))
8617 WARN("Cannot read cloud ice water content!");
8618 if (!read_met_nc_3d
8619 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, dd, met->swc, 1.0))
8620 WARN("Cannot read cloud snow water content!");
8621 if (!read_met_nc_3d
8622 (ncid, "cc", "CC", NULL, NULL, ctl, met, dd, met->cc, 1.0))
8623 WARN("Cannot read cloud cover!");
8624
8625 /* Read zeta and zeta_dot... */
8626 if (ctl->advect_vert_coord == 1) {
8627 if (!read_met_nc_3d
8628 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, dd, met->zetal, 1.0))
8629 WARN("Cannot read ZETA!");
8630 if (!read_met_nc_3d
8631 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
8632 NULL, ctl, met, dd, met->zeta_dotl, 0.00001157407f))
8633 WARN("Cannot read ZETA_DOT!");
8634 }
8635
8636 /* Read eta and eta_dot... */
8637 else if (ctl->advect_vert_coord == 3) {
8638#pragma omp parallel for default(shared)
8639 for (int ix = 0; ix < met->nx; ix++)
8640 for (int iy = 0; iy < met->ny; iy++)
8641 for (int ip = 0; ip < met->np; ip++)
8642 met->zetal[ix][iy][ip] =
8643 (float) (met->hyam[ip] / 100000.0 + met->hybm[ip]);
8644 if (!read_met_nc_3d
8645 (ncid, "etadot", "ETADOT", NULL, NULL, ctl, met, dd, met->zeta_dotl,
8646 1.0))
8647 WARN("Cannot read eta vertical velocity!");
8648 }
8649
8650 /* Store velocities on model levels... */
8651 if (ctl->met_vert_coord != 0) {
8652#pragma omp parallel for default(shared)
8653 for (int ix = 0; ix < met->nx; ix++)
8654 for (int iy = 0; iy < met->ny; iy++)
8655 for (int ip = 0; ip < met->np; ip++) {
8656 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
8657 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
8658 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
8659 }
8660
8661 /* Save number of model levels... */
8662 met->npl = met->np;
8663 }
8664
8665 /* Get pressure on model levels... */
8666 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
8667
8668 /* Read 3-D pressure field... */
8669 if (ctl->met_vert_coord == 1) {
8670 if (!read_met_nc_3d
8671 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, dd, met->pl,
8672 0.01f))
8673 if (!read_met_nc_3d
8674 (ncid, "press", "PRESS", NULL, NULL, ctl, met, dd, met->pl, 1.0))
8675 ERRMSG("Cannot read pressure on model levels!");
8676 }
8677
8678 /* Use a and b coefficients for full levels (at layer midpoints)... */
8679 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
8680
8681 /* Check number of levels... */
8682 if (ctl->met_vert_coord == 3 && met->np != ctl->met_nlev)
8683 ERRMSG("Mismatch in number of model levels!");
8684
8685 /* Calculate pressure... */
8686 for (int ix = 0; ix < met->nx; ix++)
8687 for (int iy = 0; iy < met->ny; iy++)
8688 for (int ip = 0; ip < met->np; ip++)
8689 met->pl[ix][iy][ip] =
8690 (float) (met->hyam[ip] / 100. +
8691 met->hybm[ip] * met->ps[ix][iy]);
8692 }
8693
8694 /* Use a and b coefficients for half levels (at layer interfaces)... */
8695 else if (ctl->met_vert_coord == 4) {
8696
8697 /* Check number of levels... */
8698 if (met->np + 1 != ctl->met_nlev)
8699 ERRMSG("Mismatch in number of model levels!");
8700
8701 /* Calculate pressure... */
8702#pragma omp parallel for default(shared) collapse(2)
8703 for (int ix = 0; ix < met->nx; ix++)
8704 for (int iy = 0; iy < met->ny; iy++)
8705 for (int ip = 0; ip < met->np; ip++) {
8706 const double p0 =
8707 met->hyam[ip] / 100. + met->hybm[ip] * met->ps[ix][iy];
8708 const double p1 =
8709 met->hyam[ip + 1] / 100. + met->hybm[ip + 1] * met->ps[ix][iy];
8710 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
8711 }
8712 }
8713
8714 /* Check ordering of pressure levels... */
8715 for (int ix = 0; ix < met->nx; ix++)
8716 for (int iy = 0; iy < met->ny; iy++)
8717 for (int ip = 1; ip < met->np; ip++)
8718 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
8719 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
8720 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
8721 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
8722 ERRMSG("Pressure profiles are not monotonic!");
8723 }
8724
8725 /* Interpolate from model levels to pressure levels... */
8726 if (ctl->met_np > 0) {
8727
8728 /* Interpolate variables... */
8729 read_met_ml2pl(ctl, met, met->t, "T");
8730 read_met_ml2pl(ctl, met, met->u, "U");
8731 read_met_ml2pl(ctl, met, met->v, "V");
8732 read_met_ml2pl(ctl, met, met->w, "W");
8733 read_met_ml2pl(ctl, met, met->h2o, "H2O");
8734 read_met_ml2pl(ctl, met, met->o3, "O3");
8735 read_met_ml2pl(ctl, met, met->lwc, "LWC");
8736 read_met_ml2pl(ctl, met, met->rwc, "RWC");
8737 read_met_ml2pl(ctl, met, met->iwc, "IWC");
8738 read_met_ml2pl(ctl, met, met->swc, "SWC");
8739 read_met_ml2pl(ctl, met, met->cc, "CC");
8740
8741 /* Set new pressure levels... */
8742 met->np = ctl->met_np;
8743 for (int ip = 0; ip < met->np; ip++)
8744 met->p[ip] = ctl->met_p[ip];
8745 }
8746
8747 /* Check ordering of pressure levels... */
8748 for (int ip = 1; ip < met->np; ip++)
8749 if (met->p[ip - 1] < met->p[ip])
8750 ERRMSG("Pressure levels must be descending!");
8751}
8752
8753/*****************************************************************************/
8754
8756 const int ncid,
8757 const char *varname,
8758 const char *varname2,
8759 const char *varname3,
8760 const char *varname4,
8761 const char *varname5,
8762 const char *varname6,
8763 const ctl_t *ctl,
8764 const met_t *met,
8765 dd_t *dd,
8766 float dest[EX][EY],
8767 const float scl,
8768 const int init) {
8769
8770 char varsel[LEN];
8771
8772 float offset, scalfac;
8773
8774 int varid;
8775
8776 /* Check if variable exists... */
8777 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8778 sprintf(varsel, "%s", varname);
8779 else if (varname2 != NULL
8780 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8781 sprintf(varsel, "%s", varname2);
8782 else if (varname3 != NULL
8783 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8784 sprintf(varsel, "%s", varname3);
8785 else if (varname4 != NULL
8786 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8787 sprintf(varsel, "%s", varname4);
8788 else if (varname5 != NULL
8789 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
8790 sprintf(varsel, "%s", varname5);
8791 else if (varname6 != NULL
8792 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
8793 sprintf(varsel, "%s", varname6);
8794 else
8795 return 0;
8796
8797 /* Read packed data... */
8798 if (ctl->met_nc_scale && !ctl->dd
8799 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8800 && nc_get_att_float(ncid, varid, "scale_factor",
8801 &scalfac) == NC_NOERR) {
8802
8803 /* Allocate... */
8804 short *help;
8805 ALLOC(help, short,
8806 EX * EY * EP);
8807
8808 /* Read fill value and missing value... */
8809 short fillval, missval;
8810 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8811 fillval = 0;
8812 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
8813 missval = 0;
8814
8815 /* Write info... */
8816 LOG(2, "Read 2-D variable: %s"
8817 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
8818 varsel, fillval, missval, scalfac, offset);
8819
8820 /* Read data... */
8821 NC(nc_get_var_short(ncid, varid, help));
8822
8823 /* Check meteo data layout... */
8824 if (ctl->met_convention != 0)
8825 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
8826
8827 /* Copy and check data... */
8828 omp_set_dynamic(1);
8829#pragma omp parallel for default(shared)
8830 for (int ix = 0; ix < met->nx; ix++)
8831 for (int iy = 0; iy < met->ny; iy++) {
8832 if (init)
8833 dest[ix][iy] = 0;
8834 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
8835 if ((fillval == 0 || aux != fillval)
8836 && (missval == 0 || aux != missval)
8837 && fabsf(aux * scalfac + offset) < 1e14f)
8838 dest[ix][iy] += scl * (aux * scalfac + offset);
8839 else
8840 dest[ix][iy] = NAN;
8841 }
8842 omp_set_dynamic(0);
8843
8844 /* Free... */
8845 free(help);
8846 }
8847
8848 /* Unpacked data... */
8849 else if (!ctl->dd) {
8850
8851 /* Allocate... */
8852 float *help;
8853 ALLOC(help, float,
8854 EX * EY);
8855
8856 /* Read fill value and missing value... */
8857 float fillval, missval;
8858 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8859 fillval = 0;
8860 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8861 missval = 0;
8862
8863 /* Write info... */
8864 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8865 varsel, fillval, missval);
8866
8867 /* Read data... */
8868 NC(nc_get_var_float(ncid, varid, help));
8869
8870 /* Check meteo data layout... */
8871 if (ctl->met_convention == 0) {
8872
8873 /* Copy and check data (ordering: lat, lon)... */
8874 omp_set_dynamic(1);
8875#pragma omp parallel for default(shared)
8876 for (int ix = 0; ix < met->nx; ix++)
8877 for (int iy = 0; iy < met->ny; iy++) {
8878 if (init)
8879 dest[ix][iy] = 0;
8880 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
8881 if ((fillval == 0 || aux != fillval)
8882 && (missval == 0 || aux != missval)
8883 && fabsf(aux) < 1e14f)
8884 dest[ix][iy] += scl * aux;
8885 else
8886 dest[ix][iy] = NAN;
8887 }
8888 omp_set_dynamic(0);
8889
8890 } else {
8891
8892 /* Copy and check data (ordering: lon, lat)... */
8893 omp_set_dynamic(1);
8894#pragma omp parallel for default(shared)
8895 for (int iy = 0; iy < met->ny; iy++)
8896 for (int ix = 0; ix < met->nx; ix++) {
8897 if (init)
8898 dest[ix][iy] = 0;
8899 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
8900 if ((fillval == 0 || aux != fillval)
8901 && (missval == 0 || aux != missval)
8902 && fabsf(aux) < 1e14f)
8903 dest[ix][iy] += scl * aux;
8904 else
8905 dest[ix][iy] = NAN;
8906 }
8907 omp_set_dynamic(0);
8908 }
8909
8910 /* Free... */
8911 free(help);
8912
8913 }
8914 /* Domain decomposed data... */
8915 else {
8916
8917 /* Read fill value and missing value... */
8918 float fillval, missval;
8919 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8920 fillval = 0;
8921 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8922 missval = 0;
8923
8924 /* Write info... */
8925 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8926 varsel, fillval, missval);
8927
8928 /* Define hyperslab... */
8929 float *help;
8930 size_t help_subdomain_start[3];
8931 size_t help_subdomain_count[3];
8932
8933 help_subdomain_start[0] = 0;
8934 help_subdomain_start[1] = dd->subdomain_start[2];
8935 help_subdomain_start[2] = dd->subdomain_start[3];
8936
8937 help_subdomain_count[0] = 1;
8938 help_subdomain_count[1] = dd->subdomain_count[2]; //y
8939 help_subdomain_count[2] = dd->subdomain_count[3]; //x
8940
8941 ALLOC(help, float,
8942 (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]
8943 );
8944
8945 /* Read data... */
8946 NC(nc_get_vara_float
8947 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
8948
8949 /* Read halos at boundaries... */
8950 size_t help_halo_bnd_start[3];
8951 size_t help_halo_bnd_count[3];
8952
8953 help_halo_bnd_start[0] = 0;
8954 help_halo_bnd_start[1] = dd->halo_bnd_start[2];
8955 help_halo_bnd_start[2] = dd->halo_bnd_start[3];
8956
8957 help_halo_bnd_count[0] = 1;
8958 help_halo_bnd_count[1] = dd->halo_bnd_count[2]; //y
8959 help_halo_bnd_count[2] = dd->halo_bnd_count[3]; //x
8960
8961 float *help_halo;
8962 ALLOC(help_halo, float,
8963 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
8964 NC(nc_get_vara_float
8965 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
8966
8967 /* Check meteo data layout... */
8968 if (ctl->met_convention == 0) {
8969 /* Copy and check data (ordering: lat, lon)... */
8970#pragma omp parallel for default(shared) num_threads(12)
8971 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
8972 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
8973 if (init == 1)
8974 dest[ix + dd->halo_offset_start][iy] = 0;
8975 const float aux =
8976 help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
8977 if ((fillval == 0 || aux != fillval)
8978 && (missval == 0 || aux != missval)
8979 && fabsf(aux) < 1e14f) {
8980 dest[ix + dd->halo_offset_start][iy] += scl * aux;
8981 } else
8982 dest[ix + dd->halo_offset_start][iy] = NAN;
8983 }
8984
8985 /* Copy and check data (ordering: lat, lon)... */
8986#pragma omp parallel for default(shared) num_threads(12)
8987 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
8988 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
8989 if (init == 1)
8990 dest[ix + dd->halo_offset_end][iy] = 0;
8991 const float aux =
8992 help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
8993 if ((fillval == 0 || aux != fillval)
8994 && (missval == 0 || aux != missval)
8995 && fabsf(aux) < 1e14f)
8996 dest[ix + dd->halo_offset_end][iy] += scl * aux;
8997 else {
8998 dest[ix + dd->halo_offset_end][iy] = NAN;
8999 }
9000 }
9001
9002 } else {
9003 ERRMSG("Domain decomposition with data convection incompatible!");
9004 }
9005
9006 /* Free... */
9007 free(help);
9008 free(help_halo);
9009 }
9010
9011 /* Return... */
9012 return 1;
9013}
9014
9015/*****************************************************************************/
9016
9018 const int ncid,
9019 const char *varname,
9020 const char *varname2,
9021 const char *varname3,
9022 const char *varname4,
9023 const ctl_t *ctl,
9024 const met_t *met,
9025 dd_t *dd,
9026 float dest[EX][EY][EP],
9027 const float scl) {
9028
9029 SELECT_TIMER("read_met_nc_3d", "INPUT");
9030
9031 char varsel[LEN];
9032
9033 float offset, scalfac;
9034
9035 int varid;
9036
9037 /* Check if variable exists... */
9038 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
9039 sprintf(varsel, "%s", varname);
9040 else if (varname2 != NULL
9041 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
9042 sprintf(varsel, "%s", varname2);
9043 else if (varname3 != NULL
9044 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
9045 sprintf(varsel, "%s", varname3);
9046 else if (varname4 != NULL
9047 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
9048 sprintf(varsel, "%s", varname4);
9049 else
9050 return 0;
9051
9052 if (ctl->met_nc_scale && !ctl->dd
9053 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
9054 && nc_get_att_float(ncid, varid, "scale_factor",
9055 &scalfac) == NC_NOERR) {
9056
9057 /* Allocate... */
9058 short *help;
9059 ALLOC(help, short,
9060 EX * EY * EP);
9061
9062 /* Read fill value and missing value... */
9063 short fillval, missval;
9064 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9065 fillval = 0;
9066 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9067 missval = 0;
9068
9069 /* Write info... */
9070 LOG(2, "Read 3-D variable: %s "
9071 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9072 varsel, fillval, missval, scalfac, offset);
9073
9074 /* Read data... */
9075 NC(nc_get_var_short(ncid, varid, help));
9076
9077 /* Check meteo data layout... */
9078 if (ctl->met_convention != 0)
9079 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9080
9081 /* Copy and check data... */
9082 omp_set_dynamic(1);
9083#pragma omp parallel for default(shared)
9084 for (int ix = 0; ix < met->nx; ix++)
9085 for (int iy = 0; iy < met->ny; iy++)
9086 for (int ip = 0; ip < met->np; ip++) {
9087 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9088 if ((fillval == 0 || aux != fillval)
9089 && (missval == 0 || aux != missval)
9090 && fabsf(aux * scalfac + offset) < 1e14f)
9091 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
9092 else
9093 dest[ix][iy][ip] = NAN;
9094 }
9095 omp_set_dynamic(0);
9096
9097 /* Free... */
9098 free(help);
9099 }
9100
9101 /* Unpacked data... */
9102 else if (!ctl->dd) {
9103
9104 /* Allocate... */
9105 float *help;
9106 ALLOC(help, float,
9107 EX * EY * EP);
9108
9109 /* Read fill value and missing value... */
9110 float fillval, missval;
9111 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9112 fillval = 0;
9113 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9114 missval = 0;
9115
9116 /* Write info... */
9117 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9118 varsel, fillval, missval);
9119
9120 /* Read data... */
9121 NC(nc_get_var_float(ncid, varid, help));
9122
9123 /* Check meteo data layout... */
9124 if (ctl->met_convention == 0) {
9125
9126 /* Copy and check data (ordering: lev, lat, lon)... */
9127 omp_set_dynamic(1);
9128#pragma omp parallel for default(shared)
9129 for (int ix = 0; ix < met->nx; ix++)
9130 for (int iy = 0; iy < met->ny; iy++)
9131 for (int ip = 0; ip < met->np; ip++) {
9132 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9133 if ((fillval == 0 || aux != fillval)
9134 && (missval == 0 || aux != missval)
9135 && fabsf(aux) < 1e14f)
9136 dest[ix][iy][ip] = scl * aux;
9137 else
9138 dest[ix][iy][ip] = NAN;
9139 }
9140 omp_set_dynamic(0);
9141
9142 } else {
9143
9144 /* Copy and check data (ordering: lon, lat, lev)... */
9145 omp_set_dynamic(1);
9146#pragma omp parallel for default(shared)
9147 for (int ip = 0; ip < met->np; ip++)
9148 for (int iy = 0; iy < met->ny; iy++)
9149 for (int ix = 0; ix < met->nx; ix++) {
9150 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9151 if ((fillval == 0 || aux != fillval)
9152 && (missval == 0 || aux != missval)
9153 && fabsf(aux) < 1e14f)
9154 dest[ix][iy][ip] = scl * aux;
9155 else
9156 dest[ix][iy][ip] = NAN;
9157 }
9158 omp_set_dynamic(0);
9159 }
9160
9161 /* Free... */
9162 free(help);
9163
9164 }
9165 /* Domain decomposed data... */
9166 else {
9167
9168 /* Read fill value and missing value... */
9169 float fillval, missval;
9170 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9171 fillval = 0;
9172 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9173 missval = 0;
9174
9175 /* Write info... */
9176 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9177 varsel, fillval, missval);
9178
9179 SELECT_TIMER("read_met_nc_3d_CP1", "INPUT");
9180
9181 /* Define hyperslab... */
9182
9183 /* Allocate... */
9184 float *help;
9185 ALLOC(help, float,
9186 (int) dd->subdomain_count[0] * (int) dd->subdomain_count[1]
9187 * (int) dd->subdomain_count[2] * (int) dd->subdomain_count[3]);
9188
9189 SELECT_TIMER("read_met_nc_3d_CP2", "INPUT");
9190
9191 /* Use default NetCDF parallel I/O behavior */
9192 NC(nc_get_vara_float
9193 (ncid, varid, dd->subdomain_start, dd->subdomain_count, help));
9194
9195 /* Read halos separately at boundaries... */
9196 float *help_halo;
9197 ALLOC(help_halo, float,
9198 dd->halo_bnd_count[0] * dd->halo_bnd_count[1] *
9199 dd->halo_bnd_count[2] * dd->halo_bnd_count[3]);
9200
9201 SELECT_TIMER("read_met_nc_3d_CP3", "INPUT");
9202
9203 /* Halo read also uses independent access */
9204 NC(nc_get_vara_float(ncid,
9205 varid,
9206 dd->halo_bnd_start, dd->halo_bnd_count, help_halo));
9207
9208 SELECT_TIMER("read_met_nc_3d_CP4", "INPUT");
9209
9210 /* Check meteo data layout... */
9211 if (ctl->met_convention == 0) {
9212 /* Copy and check data (ordering: lev, lat, lon)... */
9213#pragma omp parallel for default(shared) num_threads(12)
9214 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
9215 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9216 for (int ip = 0; ip < met->np; ip++) {
9217 const float aux =
9218 help[ARRAY_3D(ip, iy, (int) dd->subdomain_count[2], ix,
9219 (int) dd->subdomain_count[3])];
9220 if ((fillval == 0 || aux != fillval)
9221 && (missval == 0 || aux != missval)
9222 && fabsf(aux) < 1e14f)
9223 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9224 else
9225 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9226 }
9227
9228#pragma omp parallel for default(shared) num_threads(12)
9229 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
9230 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9231 for (int ip = 0; ip < met->np; ip++) {
9232 const float aux =
9233 help_halo[ARRAY_3D(ip, iy, (int) dd->halo_bnd_count[2], ix,
9234 (int) dd->halo_bnd_count[3])];
9235 if ((fillval == 0 || aux != fillval)
9236 && (missval == 0 || aux != missval)
9237 && fabsf(aux) < 1e14f)
9238 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9239 else
9240 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9241 }
9242
9243 } else {
9244
9245 /* Copy and check data (ordering: lon, lat, lev)... */
9246#pragma omp parallel for default(shared) num_threads(12)
9247 for (int ip = 0; ip < met->np; ip++)
9248 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
9249 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++) {
9250 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9251 if ((fillval == 0 || aux != fillval)
9252 && (missval == 0 || aux != missval)
9253 && fabsf(aux) < 1e14f)
9254 dest[ix + dd->halo_offset_end][iy][ip] = scl * aux;
9255 else
9256 dest[ix + dd->halo_offset_end][iy][ip] = NAN;
9257 }
9258
9259#pragma omp parallel for default(shared) num_threads(12)
9260 for (int ip = 0; ip < met->np; ip++)
9261 for (int iy = 0; iy < (int) dd->halo_bnd_count[2]; iy++)
9262 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++) {
9263 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9264 if ((fillval == 0 || aux != fillval)
9265 && (missval == 0 || aux != missval)
9266 && fabsf(aux) < 1e14f)
9267 dest[ix + dd->halo_offset_start][iy][ip] = scl * aux;
9268 else
9269 dest[ix + dd->halo_offset_start][iy][ip] = NAN;
9270 }
9271 }
9272
9273 /* Free... */
9274 free(help);
9275 free(help_halo);
9276 }
9277
9278 /* Return... */
9279 return 1;
9280}
9281
9282/*****************************************************************************/
9283
9284#ifdef ECCODES
9285int read_met_grib(
9286 const char *filename,
9287 const ctl_t *ctl,
9288 met_t *met) {
9289
9290 /* Set filenames... */
9291 size_t filename_len = strlen(filename) + 1;
9292 char sf_filename[filename_len];
9293 char ml_filename[filename_len];
9294 strcpy(sf_filename, filename);
9295 strcpy(ml_filename, filename);
9296 get_met_replace(ml_filename, "XX", "ml");
9297 get_met_replace(sf_filename, "XX", "sf");
9298
9299 /* Open files... */
9300 FILE *ml_file = fopen(ml_filename, "rb");
9301 FILE *sf_file = fopen(sf_filename, "rb");
9302 if (ml_file == NULL || sf_file == NULL) {
9303 if (ml_file != NULL) {
9304 fclose(ml_file);
9305 WARN("Cannot open file: %s", sf_filename);
9306 }
9307 if (sf_file != NULL) {
9308 fclose(sf_file);
9309 WARN("Cannot open file: %s", ml_filename);
9310 }
9311 return 0;
9312 }
9313
9314 /* Get handles for model level data... */
9315 int ml_num_messages = 0, err = 0;
9316 ECC(codes_count_in_file(0, ml_file, &ml_num_messages));
9317 codes_handle **ml_handles =
9318 (codes_handle **) malloc(sizeof(codes_handle *) *
9319 (size_t) ml_num_messages);
9320 for (int i = 0; i < ml_num_messages; i++) {
9321 codes_handle *h = NULL;
9322 if ((h = codes_grib_handle_new_from_file(0, ml_file, &err)) != NULL)
9323 ml_handles[i] = h;
9324 }
9325
9326 /* Get handles for surface data... */
9327 int sf_num_messages = 0;
9328 ECC(codes_count_in_file(0, sf_file, &sf_num_messages));
9329 codes_handle **sf_handles =
9330 (codes_handle **) malloc(sizeof(codes_handle *) *
9331 (size_t) sf_num_messages);
9332 for (int i = 0; i < sf_num_messages; i++) {
9333 codes_handle *h = NULL;
9334 if ((h = codes_grib_handle_new_from_file(0, sf_file, &err)) != NULL)
9335 sf_handles[i] = h;
9336 }
9337
9338 /* Close files... */
9339 fclose(ml_file);
9340 fclose(sf_file);
9341
9342 /* Read grid data... */
9343 read_met_grib_grid(ml_handles, ml_num_messages, met);
9344
9345 /* Read surface data... */
9346 read_met_grib_surface(sf_handles, sf_num_messages, ctl, met);
9347 for (int i = 0; i < sf_num_messages; i++)
9348 codes_handle_delete(sf_handles[i]);
9349 free(sf_handles);
9350
9351 /* Compute 3D pressure field... */
9352 size_t value_count = 0;
9353 ECC(codes_get_size(ml_handles[0], "pv", &value_count));
9354 if (value_count % 2 != 0)
9355 ERRMSG("Unexpected pv array length!");
9356 size_t nlevels = value_count / 2 - 1; /* number of full model levels */
9357 double *values;
9358 ALLOC(values, double,
9359 value_count);
9360 ECC(codes_get_double_array(ml_handles[0], "pv", values, &value_count));
9361 double *a_vals = values;
9362 double *b_vals = values + nlevels;
9363 if (met->npl > (int) nlevels)
9364 ERRMSG("met->npl exceeds number of pressure levels in GRIB!");
9365 for (int nx = 0; nx < met->nx; nx++)
9366 for (int ny = 0; ny < met->ny; ny++)
9367 for (int level = 0; level <= met->npl; level++) {
9368 const float p1 = (float) (a_vals[level] * 0.01f +
9369 met->ps[nx][ny] * b_vals[level]);
9370 const float p2 = (float) (a_vals[level + 1] * 0.01f +
9371 met->ps[nx][ny] * b_vals[level + 1]);
9372 met->pl[nx][ny][level] = 0.5f * (p1 + p2);
9373 }
9374 free(values);
9375
9376 /* Read model level data... */
9377 read_met_grib_levels(ml_handles, ml_num_messages, ctl, met);
9378 for (int i = 0; i < ml_num_messages; i++)
9379 codes_handle_delete(ml_handles[i]);
9380 free(ml_handles);
9381
9382 /* Return success... */
9383 return 1;
9384}
9385#endif
9386
9387/*****************************************************************************/
9388
9389#ifdef ECCODES
9391 codes_handle **handles,
9392 int count_handles,
9393 met_t *met) {
9394
9395 /* Set timer... */
9396 SELECT_TIMER("READ_MET_GRIB_GRID", "INPUT");
9397 LOG(2, "Read meteo grid information...");
9398
9399 /* Read date and time... */
9400 char datestr[LEN], timestr[LEN];
9401 size_t s_date = sizeof(datestr);
9402 ECC(codes_get_string(handles[0], "dataDate", datestr, &s_date));
9403 size_t s_time = sizeof(timestr);
9404 ECC(codes_get_string(handles[0], "dataTime", timestr, &s_time));
9405 int year, month, day, hour;
9406 if (sscanf(datestr, "%4d%2d%2d", &year, &month, &day) != 3)
9407 ERRMSG("Failed to parse dataDate: %s", datestr);
9408 if (sscanf(timestr, "%2d", &hour) != 1)
9409 ERRMSG("Failed to parse dataTime: %s", timestr);
9410 time2jsec(year, month, day, hour, 0, 0, 0, &(met->time));
9411 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)", met->time, year, month,
9412 day, hour, 0);
9413
9414 /* Read grid information... */
9415 long count_lat = 0, count_lon = 0;
9416 ECC(codes_get_long(handles[0], "Nj", &count_lat));
9417 ECC(codes_get_long(handles[0], "Ni", &count_lon));
9418 met->ny = (int) count_lat;
9419 met->nx = (int) count_lon;
9420
9421 /* Check grid dimensions... */
9422 LOG(2, "Number of longitudes: %d", met->nx);
9423 if (met->nx < 2 || met->nx > EX)
9424 ERRMSG("Number of longitudes out of range!");
9425 LOG(2, "Number of latitudes: %d", met->ny);
9426 if (met->ny < 2 || met->ny > EY)
9427 ERRMSG("Number of latitudes out of range!");
9428
9429 double first_lon, last_lon, first_lat, last_lat, inc_lon, inc_lat;
9430 ECC(codes_get_double
9431 (handles[0], "longitudeOfFirstGridPointInDegrees", &first_lon));
9432 ECC(codes_get_double
9433 (handles[0], "latitudeOfFirstGridPointInDegrees", &first_lat));
9434 ECC(codes_get_double
9435 (handles[0], "longitudeOfLastGridPointInDegrees", &last_lon));
9436 ECC(codes_get_double
9437 (handles[0], "latitudeOfLastGridPointInDegrees", &last_lat));
9438 ECC(codes_get_double(handles[0], "iDirectionIncrementInDegrees", &inc_lon));
9439 ECC(codes_get_double(handles[0], "jDirectionIncrementInDegrees", &inc_lat));
9440
9441 long jscanpos, iscanneg;
9442 ECC(codes_get_long(handles[0], "iScansNegatively", &iscanneg));
9443 ECC(codes_get_long(handles[0], "jScansPositively", &jscanpos));
9444
9445 /* Compute longitude-latitude grid... */
9446 int counter = 0;
9447 if (iscanneg == 0)
9448 for (double i = first_lon; i <= last_lon + 1e-6; i += inc_lon) {
9449 met->lon[counter] = i;
9450 counter++;
9451 } else
9452 for (double i = first_lon; i > last_lon - 1e-6; i -= inc_lon) {
9453 met->lon[counter] = i;
9454 counter++;
9455 }
9456
9457 counter = 0;
9458 if (jscanpos == 0)
9459 for (double i = first_lat; i > last_lat - 1e-6; i -= inc_lat) {
9460 met->lat[counter] = i;
9461 counter++;
9462 } else
9463 for (double i = first_lat; i <= last_lat + 1e-6; i += inc_lat) {
9464 met->lat[counter] = i;
9465 counter++;
9466 }
9467
9468 /* Write info... */
9469 LOG(2, "Longitudes: %g, %g ... %g deg",
9470 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9471 LOG(2, "Latitudes: %g, %g ... %g deg",
9472 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9473
9474 /* Read vertical levels... */
9475 int max_level = 0;
9476 for (int i = 0; i < count_handles; i++) {
9477 long level;
9478 ECC(codes_get_long(handles[i], "level", &level));
9479 if (level > max_level)
9480 max_level = (int) level;
9481 }
9482 met->npl = max_level;
9483
9484 /* Check number of levels... */
9485 LOG(2, "Number of levels: %d", met->npl);
9486 if (met->npl < 2 || met->npl > EP)
9487 ERRMSG("Number of levels out of range!");
9488}
9489#endif
9490
9491/*****************************************************************************/
9492
9493#ifdef ECCODES
9495 codes_handle **handles,
9496 const int num_messages,
9497 const ctl_t *ctl,
9498 met_t *met) {
9499
9500 /* Set timer... */
9501 SELECT_TIMER("READ_MET_GRIB_LEVELS", "INPUT");
9502 LOG(2, "Read level data...");
9503
9504 /* Init... */
9505 int t_flag = 0, u_flag = 0, v_flag = 0, w_flag = 0, o3_flag = 0, h2o_flag =
9506 0, lwc_flag = 0, rwc_flag = 0, iwc_flag = 0, swc_flag = 0, cc_flag = 0;
9507
9508 /* Iterate over all messages... */
9509 for (int i = 0; i < num_messages; i++) {
9510
9511 size_t max_size = LEN;
9512 char short_name[max_size];
9513 size_t value_count;
9514 double *values;
9515
9516 /* Get the current level */
9517 long current_level;
9518 ECC(codes_get_long(handles[i], "level", &current_level));
9519 current_level -= 1;
9520
9521 /* Retrieve data from current message */
9522 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
9523 ECC(codes_get_size(handles[i], "values", &value_count));
9524 ALLOC(values, double,
9525 value_count);
9526 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
9527
9528 /* Read temperature... */
9529 ECC_READ_3D("t", current_level, met->t, 1.0, t_flag);
9530
9531 /* Read horizontal wind and vertical velocity... */
9532 ECC_READ_3D("u", current_level, met->u, 1.0, u_flag);
9533 ECC_READ_3D("v", current_level, met->v, 1.0, v_flag);
9534 ECC_READ_3D("w", current_level, met->w, 0.01f, w_flag);
9535
9536 /* Read water vapor and ozone... */
9537 ECC_READ_3D("q", current_level, met->h2o, (float) (MA / MH2O), h2o_flag);
9538 ECC_READ_3D("o3", current_level, met->o3, (float) (MA / MO3), o3_flag);
9539
9540 /* Read cloud data... */
9541 ECC_READ_3D("clwc", current_level, met->lwc, 1.0, lwc_flag);
9542 ECC_READ_3D("crwc", current_level, met->rwc, 1.0, rwc_flag);
9543 ECC_READ_3D("ciwc", current_level, met->iwc, 1.0, iwc_flag);
9544 ECC_READ_3D("cswc", current_level, met->swc, 1.0, swc_flag);
9545 ECC_READ_3D("cc", current_level, met->cc, 1.0, cc_flag);
9546
9547 /*Free allocated array */
9548 free(values);
9549 }
9550
9551 /* Check whether data were found... */
9552 if (t_flag != met->npl)
9553 ERRMSG("Cannot read temperature!");
9554 if (u_flag != met->npl)
9555 ERRMSG("Cannot read zonal wind!");
9556 if (v_flag != met->npl)
9557 ERRMSG("Cannot read meridional wind!");
9558 if (w_flag != met->npl)
9559 WARN("Cannot read vertical velocity!");
9560 if (h2o_flag != met->npl)
9561 WARN("Cannot read specific humidity!");
9562 if (o3_flag != met->npl)
9563 WARN("Cannot read ozone data!");
9564 if (lwc_flag != met->npl)
9565 WARN("Cannot read cloud liquid water content!");
9566 if (rwc_flag != met->npl)
9567 WARN("Cannot read cloud rain water content!");
9568 if (iwc_flag != met->npl)
9569 WARN("Cannot read cloud ice water content!");
9570 if (swc_flag != met->npl)
9571 WARN("Cannot read cloud snow water content!");
9572 if (cc_flag != met->npl)
9573 WARN("Cannot read cloud cover!");
9574
9575 /* Check ordering of pressure levels... */
9576 for (int ix = 0; ix < met->nx; ix++)
9577 for (int iy = 0; iy < met->ny; iy++)
9578 for (int ip = 1; ip < met->np; ip++)
9579 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
9580 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
9581 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
9582 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip])) {
9583 LOG(1, "%f %f %f %f", met->pl[ix][iy][0], met->pl[ix][iy][1],
9584 met->pl[ix][iy][ip - 1], met->pl[ix][iy][ip]);
9585 ERRMSG("Pressure profiles are not monotonic!");
9586 }
9587
9588 /* Interpolate from model levels to pressure levels... */
9589 if (ctl->met_np > 0) {
9590 met->np = ctl->met_np;
9591
9592 /* Interpolate variables... */
9593 read_met_ml2pl(ctl, met, met->t, "T");
9594 read_met_ml2pl(ctl, met, met->u, "U");
9595 read_met_ml2pl(ctl, met, met->v, "V");
9596 read_met_ml2pl(ctl, met, met->w, "W");
9597 read_met_ml2pl(ctl, met, met->h2o, "H2O");
9598 read_met_ml2pl(ctl, met, met->o3, "O3");
9599 read_met_ml2pl(ctl, met, met->lwc, "LWC");
9600 read_met_ml2pl(ctl, met, met->rwc, "RWC");
9601 read_met_ml2pl(ctl, met, met->iwc, "IWC");
9602 read_met_ml2pl(ctl, met, met->swc, "SWC");
9603 read_met_ml2pl(ctl, met, met->cc, "CC");
9604
9605 /* Set new pressure levels... */
9606 for (int ip = 0; ip < met->np; ip++)
9607 met->p[ip] = ctl->met_p[ip];
9608 }
9609
9610 /* Check ordering of pressure levels... */
9611 for (int ip = 1; ip < met->np; ip++)
9612 if (met->p[ip - 1] < met->p[ip])
9613 ERRMSG("Pressure levels must be descending!");
9614}
9615#endif
9616
9617/*****************************************************************************/
9618
9619#ifdef ECCODES
9621 codes_handle **handles,
9622 const int num_messages,
9623 const ctl_t *ctl,
9624 met_t *met) {
9625
9626 /* Set timer... */
9627 SELECT_TIMER("READ_MET_GRIB_SURFACE", "INPUT");
9628 LOG(2, "Read surface data...");
9629
9630 /* Init... */
9631 int sp_flag = 0, z_flag = 0, t_flag = 0, u_flag = 0, v_flag = 0, lsm_flag =
9632 0, sst_flag = 0, cape_flag = 0, cin_flag = 0, pbl_flag = 0;
9633
9634 /* Iterate over all messages... */
9635 for (int i = 0; i < num_messages; i++) {
9636
9637 size_t max_size = LEN, value_count;
9638
9639 char short_name[max_size];
9640
9641 /* Store values with shortname... */
9642 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
9643 ECC(codes_get_size(handles[i], "values", &value_count));
9644 double *values = (double *) malloc(value_count * sizeof(double));
9645 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
9646
9647 /*Read surface pressure... */
9648 ECC_READ_2D("sp", met->ps, 0.01f, sp_flag);
9649
9650 /*Read geopotential height at the surface... */
9651 ECC_READ_2D("z", met->zs, (float) (1. / (1000. * G0)), z_flag);
9652
9653 /* Read temperature at the surface... */
9654 ECC_READ_2D("2t", met->ts, 1.0f, t_flag);
9655
9656 /* Read zonal wind at the surface... */
9657 ECC_READ_2D("10u", met->us, 1.0f, u_flag);
9658
9659 /* Read meridional wind at the surface... */
9660 ECC_READ_2D("10v", met->vs, 1.0f, v_flag);
9661
9662 /* Read land-sea mask... */
9663 ECC_READ_2D("lsm", met->lsm, 1.0f, lsm_flag);
9664
9665 /* Read sea surface temperature... */
9666 ECC_READ_2D("sst", met->sst, 1.0f, sst_flag);
9667 if (ctl->met_cape == 0) {
9668
9669 /* Read CAPE... */
9670 ECC_READ_2D("cape", met->cape, 1.0f, cape_flag);
9671
9672 /* Read CIN... */
9673 ECC_READ_2D("cin", met->cin, 1.0f, cin_flag);
9674 }
9675
9676 /* Read PBL... */
9677 if (ctl->met_pbl == 0)
9678 ECC_READ_2D("blh", met->pbl, 0.0001f, pbl_flag);
9679 }
9680
9681 /* Check whether data have been read... */
9682 if (sp_flag == 0)
9683 WARN("Cannot read surface pressure data!");
9684 if (z_flag == 0)
9685 WARN("Cannot read surface geopotential height!");
9686 if (t_flag == 0)
9687 WARN("Cannot read surface temperature!");
9688 if (u_flag == 0)
9689 WARN("Cannot read surface zonal wind!");
9690 if (v_flag == 0)
9691 WARN("Cannot read surface meridional wind!");
9692 if (lsm_flag == 0)
9693 WARN("Cannot read land-sea mask!");
9694 if (sst_flag == 0)
9695 WARN("Cannot read sea surface temperature!");
9696 if (ctl->met_cape == 0) {
9697 if (cape_flag == 0)
9698 WARN("Cannot read CAPE!");
9699 if (cin_flag == 0)
9700 WARN("Cannot read convective inhibition!");
9701 }
9702 if (ctl->met_pbl == 0 && pbl_flag == 0)
9703 WARN("Cannot read planetary boundary layer!");
9704}
9705#endif
9706
9707/*****************************************************************************/
9708
9710 const ctl_t *ctl,
9711 const met_t *met,
9712 float var[EX][EY][EP],
9713 const char *varname) {
9714
9715 double aux[EP], p[EP];
9716
9717 /* Set timer... */
9718 SELECT_TIMER("READ_MET_ML2PL", "METPROC");
9719 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
9720
9721 /* Loop over columns... */
9722#pragma omp parallel for default(shared) private(aux,p) collapse(2)
9723 for (int ix = 0; ix < met->nx; ix++)
9724 for (int iy = 0; iy < met->ny; iy++) {
9725
9726 /* Copy pressure profile... */
9727 for (int ip = 0; ip < met->np; ip++)
9728 p[ip] = met->pl[ix][iy][ip];
9729
9730 /* Interpolate... */
9731 for (int ip = 0; ip < ctl->met_np; ip++) {
9732 double pt = ctl->met_p[ip];
9733 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
9734 pt = p[0];
9735 else if ((pt > p[met->np - 1] && p[1] > p[0])
9736 || (pt < p[met->np - 1] && p[1] < p[0]))
9737 pt = p[met->np - 1];
9738 const int ip2 = locate_irr(p, met->np, pt);
9739 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
9740 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
9741 }
9742
9743 /* Copy data... */
9744 for (int ip = 0; ip < ctl->met_np; ip++)
9745 var[ix][iy][ip] = (float) aux[ip];
9746 }
9747}
9748
9749/*****************************************************************************/
9750
9752 const ctl_t *ctl,
9753 met_t *met) {
9754
9755 /* Check parameters... */
9756 if (ctl->advect_vert_coord != 1)
9757 return;
9758
9759 /* Set timer... */
9760 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC");
9761 LOG(2, "Make zeta profiles monotone...");
9762
9763 /* Create monotone zeta profiles... */
9764#pragma omp parallel for default(shared) collapse(2)
9765 for (int i = 0; i < met->nx; i++)
9766 for (int j = 0; j < met->ny; j++) {
9767 int k = 1;
9768
9769 while (k < met->npl) { /* Check if there is an inversion at level k... */
9770 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
9771 /* Find the upper level k+l over the inversion... */
9772 int l = 0;
9773 do {
9774 l++;
9775 }
9776 while ((met->zetal[i][j][k - 1] >=
9777 met->zetal[i][j][k + l]) & (k + l < met->npl));
9778
9779 /* Interpolate linear between the top and bottom
9780 of the inversion... */
9781 float s =
9782 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
9783 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9784
9785 for (int m = k; m < k + l; m++) {
9786 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9787 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
9788 }
9789
9790 /* Search for more inversions above the last inversion ... */
9791 k = k + l;
9792 } else {
9793 k++;
9794 }
9795 }
9796 }
9797
9798 /* Create monotone pressure profiles... */
9799#pragma omp parallel for default(shared) collapse(2)
9800 for (int i = 0; i < met->nx; i++)
9801 for (int j = 0; j < met->ny; j++) {
9802 int k = 1;
9803
9804 while (k < met->npl) { /* Check if there is an inversion at level k... */
9805 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
9806
9807 /* Find the upper level k+l over the inversion... */
9808 int l = 0;
9809 do {
9810 l++;
9811 }
9812 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
9813 met->npl));
9814
9815 /* Interpolate linear between the top and bottom
9816 of the inversion... */
9817 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
9818 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
9819
9820 for (int m = k; m < k + l; m++) {
9821 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
9822 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
9823 }
9824
9825 /* Search for more inversions above the last inversion ... */
9826 k += l;
9827 } else {
9828 k++;
9829 }
9830 }
9831 }
9832}
9833
9834/*****************************************************************************/
9835
9837 const char *filename,
9838 const ctl_t *ctl,
9839 met_t *met,
9840 dd_t *dd) {
9841
9842 int ncid;
9843
9844 /* Open file... */
9845#ifdef DD
9846 if (ctl->dd) {
9847 NC(nc_open_par
9848 (filename, NC_NOWRITE | NC_SHARE, MPI_COMM_WORLD, MPI_INFO_NULL,
9849 &ncid))
9850 }
9851#else
9852 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
9853 WARN("Cannot open file!");
9854 return 0;
9855 }
9856#endif
9857
9858 /* Read coordinates of meteo data... */
9859 read_met_nc_grid(filename, ncid, ctl, met, dd);
9860
9861 /* Read surface data... */
9862 read_met_nc_surface(ncid, ctl, met, dd);
9863
9864 /* Read meteo data on vertical levels... */
9865 read_met_nc_levels(ncid, ctl, met, dd);
9866
9867 /* Close file... */
9868 NC(nc_close(ncid));
9869
9870 /* Return success... */
9871 return 1;
9872}
9873
9874/*****************************************************************************/
9875
9877 dd_t *dd,
9878 const ctl_t *ctl,
9879 met_t *met,
9880 const int ncid) {
9881
9882 int varid;
9883
9884 /* Get the MPI information... */
9885#ifdef MPI
9886 MPI_Comm_rank(MPI_COMM_WORLD, &dd->rank);
9887 MPI_Comm_size(MPI_COMM_WORLD, &dd->size);
9888#endif
9889
9890 int help_nx_glob;
9891 int help_ny_glob;
9892
9893 /* Get grid dimensions... */
9894 NC_INQ_DIM("lon", &help_nx_glob, 0, 0, 0);
9895 LOG(2, "Number of longitudes: %d", help_nx_glob);
9896 met->nx = (int) floor(help_nx_glob / ctl->dd_subdomains_zonal);
9897
9898 NC_INQ_DIM("lat", &help_ny_glob, 0, 0, 0);
9899 LOG(2, "Number of latitudes: %d", help_ny_glob);
9900 met->ny = (int) floor(help_ny_glob / ctl->dd_subdomains_meridional);
9901
9902 double *help_lon_glob;
9903 double *help_lat_glob;
9904 ALLOC(help_lon_glob, double,
9905 help_nx_glob);
9906 ALLOC(help_lat_glob, double,
9907 help_ny_glob);
9908
9909 /* Read global longitudes and latitudes... */
9910 NC_GET_DOUBLE("lon", help_lon_glob, 1);
9911 LOG(2, "Longitudes: %g, %g ... %g deg",
9912 help_lon_glob[0], help_lon_glob[1], help_lon_glob[help_nx_glob - 1]);
9913 NC_GET_DOUBLE("lat", help_lat_glob, 1);
9914 LOG(2, "Latitudes: %g, %g ... %g deg",
9915 help_lat_glob[0], help_lat_glob[1], help_lat_glob[help_ny_glob - 1]);
9916
9917 /* Determine hyperslabs for reading the data in parallel... */
9918
9919 /* Check for edge cases... */
9920 int left = (dd->rank <= ctl->dd_subdomains_meridional - 1);
9921 int right = (dd->rank >= dd->size - ctl->dd_subdomains_meridional);
9922 int top = (dd->rank % ctl->dd_subdomains_meridional == 0);
9923 int bottom =
9924 (dd->rank % ctl->dd_subdomains_meridional ==
9925 ctl->dd_subdomains_meridional - 1);
9926
9927 /* Set the hyperslab for the subdomain... */
9928 dd->subdomain_start[0] = 0;
9929 dd->subdomain_start[1] = 0;
9930 dd->subdomain_start[2] =
9931 (size_t) ((dd->rank % ctl->dd_subdomains_meridional) * met->ny);
9932 dd->subdomain_start[3] =
9933 (size_t) (floor(dd->rank / ctl->dd_subdomains_meridional) * met->nx);
9934
9935 /* Extend subdomains at the right and bottom to fit the full domain. */
9936 if (right) {
9937 int gap = help_nx_glob - ctl->dd_subdomains_zonal * met->nx;
9938 if (gap > 0) {
9939 met->nx = met->nx + gap;
9940 WARN("Extended subdomains at the right to fit to full domain.");
9941 }
9942 }
9943 if (bottom) {
9944 int gap = help_ny_glob - ctl->dd_subdomains_meridional * met->ny;
9945 if (gap > 0) {
9946 met->ny = met->ny + gap;
9947 WARN("Extended subdomains at the bottom to fit to full domain.");
9948 }
9949 }
9950
9951 /* Block-size, i.e. count */
9952 dd->subdomain_count[0] = 1;
9953 dd->subdomain_count[1] = (size_t) met->np;
9954 dd->subdomain_count[2] = (size_t) met->ny;
9955 dd->subdomain_count[3] = (size_t) met->nx;
9956
9957 /* Create halos and include them into the subdomain... */
9958 if (!left && !right) {
9959 // If we are not at the left or right edge extend in zonal direction...
9960 // Move the start one point to the left...
9961 dd->subdomain_count[3] =
9962 dd->subdomain_count[3] + (size_t) (ctl->dd_halos_size * 2);
9963 dd->subdomain_start[3] =
9964 dd->subdomain_start[3] - (size_t) ctl->dd_halos_size;
9965 } else {
9966 // If we are at the left or right edge, extend only in one zonal direction...
9967 dd->subdomain_count[3] =
9968 dd->subdomain_count[3] + (size_t) ctl->dd_halos_size;
9969 if (!left)
9970 // If we are not at the left edge, move the start to the left...
9971 dd->subdomain_start[3] =
9972 dd->subdomain_start[3] - (size_t) ctl->dd_halos_size;
9973 }
9974
9975 if (!top && !bottom) {
9976 // If we are not at the upper or lower edge extend in meridional direction...
9977 // Move the start point one point down...
9978 dd->subdomain_count[2] =
9979 dd->subdomain_count[2] + (size_t) (ctl->dd_halos_size * 2);
9980 dd->subdomain_start[2] =
9981 dd->subdomain_start[2] - (size_t) ctl->dd_halos_size;
9982 } else {
9983 // If we are at the top or the lower edge only extend in one mer. direction...
9984 dd->subdomain_count[2] =
9985 dd->subdomain_count[2] + (size_t) ctl->dd_halos_size;
9986 if (!top)
9987 // If we are not at the top, move the start one upward...
9988 dd->subdomain_start[2] =
9989 dd->subdomain_start[2] - (size_t) ctl->dd_halos_size;
9990 }
9991
9992 /* Set boundary halo hyperslabs ... */
9993 double lon_shift = 0;
9994 if (left || right) {
9995
9996 met->nx = met->nx + ctl->dd_halos_size;
9997
9998 dd->halo_bnd_start[0] = 0;
9999 dd->halo_bnd_start[1] = 0;
10000 dd->halo_bnd_start[3] = (size_t) (left ? (help_nx_glob - ctl->dd_halos_size) : (0)); //x
10001 dd->halo_bnd_start[2] = dd->subdomain_start[2]; //y
10002
10003 dd->halo_bnd_count[0] = 1;
10004 dd->halo_bnd_count[1] = (size_t) met->np;
10005 dd->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
10006 dd->halo_bnd_count[2] =
10007 (size_t) met->ny +
10008 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
10009
10010 dd->halo_offset_start = (left ? (int) dd->halo_bnd_count[3] : 0);
10011 dd->halo_offset_end = (left ? 0 : (int) dd->subdomain_count[3]);
10012 lon_shift = (left ? -360 : 360);
10013
10014 } else {
10015
10016 dd->halo_bnd_start[0] = 0;
10017 dd->halo_bnd_start[1] = 0;
10018 dd->halo_bnd_start[3] = 0;
10019 dd->halo_bnd_start[2] = 0;
10020
10021 dd->halo_bnd_count[0] = 0;
10022 dd->halo_bnd_count[1] = 0;
10023 dd->halo_bnd_count[3] = 0;
10024 dd->halo_bnd_count[2] = 0;
10025 }
10026
10027 /* Get the range of the entire meteodata... */
10028 double lon_range = 360;
10029 double lat_range = help_lat_glob[help_ny_glob - 1] - help_lat_glob[0];
10030
10031 /* Focus on subdomain latitudes and longitudes... */
10032 for (int iy = 0; iy < (int) dd->subdomain_count[2]; iy++)
10033 met->lat[iy] = help_lat_glob[(int) dd->subdomain_start[2] + iy];
10034
10035 /* Focus on subdomain longitudes... */
10036 /* Keep space at the beginning or end of the array for halo... */
10037 for (int ix = 0; ix < (int) dd->subdomain_count[3]; ix++)
10038 met->lon[ix + dd->halo_offset_start] =
10039 help_lon_glob[(int) dd->subdomain_start[3] + ix];
10040
10041 for (int ix = 0; ix < (int) dd->halo_bnd_count[3]; ix++)
10042 met->lon[ix + dd->halo_offset_end] =
10043 help_lon_glob[(int) dd->halo_bnd_start[3] + ix] + lon_shift;
10044
10045 /* Reset the grid dimensions... */
10046 met->nx = (int) dd->subdomain_count[3] + (int) dd->halo_bnd_count[3];
10047 met->ny = (int) dd->subdomain_count[2];
10048
10049 /* Determine subdomain edges... */
10050 dd->subdomain_lon_min = floor(dd->rank / ctl->dd_subdomains_meridional)
10051 * (lon_range) / (double) ctl->dd_subdomains_zonal;
10053 + (lon_range) / (double) ctl->dd_subdomains_zonal;
10054
10055 /* Latitudes in descending order (90 to -90) */
10056 if (lat_range < 0) {
10057 dd->subdomain_lat_max = 90 + (dd->rank % ctl->dd_subdomains_meridional)
10058 * (lat_range) / (double) ctl->dd_subdomains_meridional;
10060 + (lat_range) / (double) ctl->dd_subdomains_meridional;
10061 } else {
10062 WARN
10063 ("lat_range > 0, but is expected to be negative, i.e. latitudes should range from 90 to -90")
10064 dd->subdomain_lat_min = -90 + (dd->rank % ctl->dd_subdomains_meridional)
10065 * (lat_range) / (double) ctl->dd_subdomains_meridional;
10067 + (lat_range) / (double) ctl->dd_subdomains_meridional;
10068 }
10069
10070 LOG(2, "Total longitude range: %g deg", lon_range);
10071 LOG(2, "Total latitude range: %g deg", lat_range);
10072
10073 LOG(2, "Define subdomain properties.");
10074 LOG(2, "MPI information: Rank %d, Size %d", dd->rank, dd->size);
10075 LOG(2, "Edge position: l=%d,r=%d,t=%d, b=%d", (int) left, (int) right,
10076 (int) top, (int) bottom);
10077 LOG(2, "Sizes for limits: EX %d EY %d EP %d", EX, EY, EP);
10078 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d", met->nx,
10079 met->ny, met->np);
10080 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
10081 (int) dd->halo_bnd_count[3], (int) dd->halo_bnd_count[2],
10082 (int) dd->halo_bnd_count[1]);
10083 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
10084 (int) dd->subdomain_count[3], (int) dd->subdomain_count[2],
10085 (int) dd->subdomain_count[1]);
10086 LOG(2, "Subdomain start: nx %ld ny %ld np %ld", dd->subdomain_start[3],
10087 dd->subdomain_start[2], dd->subdomain_start[1]);
10088 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld", dd->halo_bnd_start[3],
10089 dd->halo_bnd_start[2], dd->halo_bnd_start[1]);
10090 LOG(2, "Offsets: nx %d ny %d", dd->halo_offset_start, dd->halo_offset_end);
10091
10092 LOG(2, " %d Subdomain longitudes: %g, %g ... %g deg (edges: %g to %g)",
10093 dd->rank, met->lon[0], met->lon[1], met->lon[met->nx - 1],
10095 LOG(2, " %d Subdomain latitudes: %g, %g ... %g deg (edges: %g to %g)",
10096 dd->rank, met->lat[0], met->lat[1], met->lat[met->ny - 1],
10098
10099 free(help_lon_glob);
10100 free(help_lat_glob);
10101}
10102
10103/*****************************************************************************/
10104
10106 const ctl_t *ctl,
10107 met_t *met) {
10108
10109 /* Set timer... */
10110 SELECT_TIMER("READ_MET_PBL", "METPROC");
10111 LOG(2, "Calculate planetary boundary layer...");
10112
10113 /* Convert PBL height from meteo file to pressure... */
10114 if (ctl->met_pbl == 1) {
10115
10116 /* Loop over grid points... */
10117#pragma omp parallel for default(shared) collapse(2)
10118 for (int ix = 0; ix < met->nx; ix++)
10119 for (int iy = 0; iy < met->ny; iy++) {
10120
10121 /* Get pressure at top of PBL... */
10122 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
10123 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
10124 met->pbl[ix][iy] =
10125 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
10126 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
10127 }
10128 }
10129
10130 /* Determine PBL based on Richardson number... */
10131 else if (ctl->met_pbl == 2) {
10132
10133 /* Parameters used to estimate the height of the PBL
10134 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
10135 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
10136
10137 /* Loop over grid points... */
10138#pragma omp parallel for default(shared) collapse(2)
10139 for (int ix = 0; ix < met->nx; ix++)
10140 for (int iy = 0; iy < met->ny; iy++) {
10141
10142 /* Set bottom level of PBL... */
10143 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
10144
10145 /* Find lowest level near the bottom... */
10146 int ip;
10147 for (ip = 1; ip < met->np; ip++)
10148 if (met->p[ip] < pbl_bot)
10149 break;
10150
10151 /* Get near surface data... */
10152 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
10153 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
10154 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
10155
10156 /* Init... */
10157 double rib_old = 0;
10158
10159 /* Loop over levels... */
10160 for (; ip < met->np; ip++) {
10161
10162 /* Get squared horizontal wind speed... */
10163 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
10164 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
10165 vh2 = MAX(vh2, SQR(umin));
10166
10167 /* Calculate bulk Richardson number... */
10168 const double rib =
10169 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
10170 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
10171 met->h2o[ix][iy][ip]) - tvs) / vh2;
10172
10173 /* Check for critical value... */
10174 if (rib >= rib_crit) {
10175 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
10176 rib, met->p[ip], rib_crit));
10177 if (met->pbl[ix][iy] > pbl_bot)
10178 met->pbl[ix][iy] = (float) pbl_bot;
10179 break;
10180 }
10181
10182 /* Save Richardson number... */
10183 rib_old = rib;
10184 }
10185 }
10186 }
10187
10188 /* Determine PBL based on potential temperature... */
10189 if (ctl->met_pbl == 3) {
10190
10191 /* Parameters used to estimate the height of the PBL
10192 (following HYSPLIT model)... */
10193 const double dtheta = 2.0, zmin = 0.1;
10194
10195 /* Loop over grid points... */
10196#pragma omp parallel for default(shared) collapse(2)
10197 for (int ix = 0; ix < met->nx; ix++)
10198 for (int iy = 0; iy < met->ny; iy++) {
10199
10200 /* Potential temperature at the surface... */
10201 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
10202
10203 /* Find topmost level where theta exceeds surface value by 2 K... */
10204 int ip;
10205 for (ip = met->np - 2; ip > 0; ip--)
10206 if (met->p[ip] >= 300.)
10207 if (met->p[ip] > met->ps[ix][iy]
10208 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
10209 break;
10210
10211 /* Interpolate... */
10212 met->pbl[ix][iy]
10213 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
10214 met->p[ip + 1],
10215 THETA(met->p[ip], met->t[ix][iy][ip]),
10216 met->p[ip], theta0 + dtheta));
10217
10218 /* Check minimum value... */
10219 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
10220 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
10221 met->pbl[ix][iy] = (float) pbl_min;
10222 }
10223 }
10224
10225 /* Loop over grid points... */
10226#pragma omp parallel for default(shared) collapse(2)
10227 for (int ix = 0; ix < met->nx; ix++)
10228 for (int iy = 0; iy < met->ny; iy++) {
10229
10230 /* Check minimum value... */
10231 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
10232 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
10233
10234 /* Check maximum value... */
10235 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
10236 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
10237 }
10238}
10239
10240/*****************************************************************************/
10241
10243 met_t *met) {
10244
10245 /* Set timer... */
10246 SELECT_TIMER("READ_MET_PERIODIC", "METPROC");
10247 LOG(2, "Apply periodic boundary conditions...");
10248
10249 /* Check longitudes... */
10250 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
10251 + met->lon[1] - met->lon[0] - 360) < 0.01))
10252 return;
10253
10254 /* Increase longitude counter... */
10255 if ((++met->nx) >= EX)
10256 ERRMSG("Cannot create periodic boundary conditions!");
10257
10258 /* Set longitude... */
10259 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
10260
10261 /* Loop over latitudes and pressure levels... */
10262#pragma omp parallel for default(shared)
10263 for (int iy = 0; iy < met->ny; iy++) {
10264 met->ps[met->nx - 1][iy] = met->ps[0][iy];
10265 met->zs[met->nx - 1][iy] = met->zs[0][iy];
10266 met->ts[met->nx - 1][iy] = met->ts[0][iy];
10267 met->us[met->nx - 1][iy] = met->us[0][iy];
10268 met->vs[met->nx - 1][iy] = met->vs[0][iy];
10269 met->ess[met->nx - 1][iy] = met->ess[0][iy];
10270 met->nss[met->nx - 1][iy] = met->nss[0][iy];
10271 met->shf[met->nx - 1][iy] = met->shf[0][iy];
10272 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
10273 met->sst[met->nx - 1][iy] = met->sst[0][iy];
10274 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
10275 met->cape[met->nx - 1][iy] = met->cape[0][iy];
10276 met->cin[met->nx - 1][iy] = met->cin[0][iy];
10277 for (int ip = 0; ip < met->np; ip++) {
10278 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
10279 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
10280 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
10281 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
10282 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
10283 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
10284 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
10285 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
10286 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
10287 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
10288 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
10289 }
10290 for (int ip = 0; ip < met->npl; ip++) {
10291 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
10292 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
10293 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
10294 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
10295 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
10296 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
10297 }
10298 }
10299}
10300
10301/*****************************************************************************/
10302
10304 met_t *met) {
10305
10306 /* Set timer... */
10307 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC");
10308 LOG(2, "Apply fix for polar winds...");
10309
10310 /* Check latitudes... */
10311 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
10312 return;
10313
10314 /* Loop over hemispheres... */
10315 for (int ihem = 0; ihem < 2; ihem++) {
10316
10317 /* Set latitude indices... */
10318 int i89 = 1, i90 = 0, sign = 1;
10319 if (ihem == 1) {
10320 i89 = met->ny - 2;
10321 i90 = met->ny - 1;
10322 }
10323 if (met->lat[i90] < 0)
10324 sign = -1;
10325
10326 /* Look-up table of cosinus and sinus... */
10327 double clon[EX], slon[EX];
10328#pragma omp parallel for default(shared)
10329 for (int ix = 0; ix < met->nx; ix++) {
10330 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
10331 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
10332 }
10333
10334 /* Loop over levels... */
10335#pragma omp parallel for default(shared)
10336 for (int ip = 0; ip < met->np; ip++) {
10337
10338 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
10339 double vel89x = 0, vel89y = 0;
10340 for (int ix = 0; ix < met->nx; ix++) {
10341 vel89x +=
10342 (met->u[ix][i89][ip] * clon[ix] -
10343 met->v[ix][i89][ip] * slon[ix]) / met->nx;
10344 vel89y +=
10345 (met->u[ix][i89][ip] * slon[ix] +
10346 met->v[ix][i89][ip] * clon[ix]) / met->nx;
10347 }
10348
10349 /* Replace 90 degree winds by 89 degree mean... */
10350 for (int ix = 0; ix < met->nx; ix++) {
10351 met->u[ix][i90][ip]
10352 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
10353 met->v[ix][i90][ip]
10354 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
10355 }
10356 }
10357 }
10358}
10359
10360/*****************************************************************************/
10361
10363 met_t *met) {
10364
10365 double pows[EP];
10366
10367 /* Set timer... */
10368 SELECT_TIMER("READ_MET_PV", "METPROC");
10369 LOG(2, "Calculate potential vorticity...");
10370
10371 /* Set powers... */
10372#pragma omp parallel for default(shared)
10373 for (int ip = 0; ip < met->np; ip++)
10374 pows[ip] = pow(1000. / met->p[ip], 0.286);
10375
10376 /* Loop over grid points... */
10377#pragma omp parallel for default(shared)
10378 for (int ix = 0; ix < met->nx; ix++) {
10379
10380 /* Set indices... */
10381 const int ix0 = MAX(ix - 1, 0);
10382 const int ix1 = MIN(ix + 1, met->nx - 1);
10383
10384 /* Loop over grid points... */
10385 for (int iy = 0; iy < met->ny; iy++) {
10386
10387 /* Set indices... */
10388 const int iy0 = MAX(iy - 1, 0);
10389 const int iy1 = MIN(iy + 1, met->ny - 1);
10390
10391 /* Set auxiliary variables... */
10392 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
10393 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
10394 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
10395 const double c0 = cos(DEG2RAD(met->lat[iy0]));
10396 const double c1 = cos(DEG2RAD(met->lat[iy1]));
10397 const double cr = cos(DEG2RAD(latr));
10398 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
10399
10400 /* Loop over grid points... */
10401 for (int ip = 0; ip < met->np; ip++) {
10402
10403 /* Get gradients in longitude... */
10404 const double dtdx
10405 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
10406 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
10407
10408 /* Get gradients in latitude... */
10409 const double dtdy
10410 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
10411 const double dudy
10412 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
10413
10414 /* Set indices... */
10415 const int ip0 = MAX(ip - 1, 0);
10416 const int ip1 = MIN(ip + 1, met->np - 1);
10417
10418 /* Get gradients in pressure... */
10419 double dtdp, dudp, dvdp;
10420 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
10421 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
10422 if (ip != ip0 && ip != ip1) {
10423 double denom = dp0 * dp1 * (dp0 + dp1);
10424 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
10425 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
10426 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
10427 / denom;
10428 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
10429 - dp1 * dp1 * met->u[ix][iy][ip0]
10430 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
10431 / denom;
10432 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
10433 - dp1 * dp1 * met->v[ix][iy][ip0]
10434 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
10435 / denom;
10436 } else {
10437 const double denom = dp0 + dp1;
10438 dtdp =
10439 (met->t[ix][iy][ip1] * pows[ip1] -
10440 met->t[ix][iy][ip0] * pows[ip0]) / denom;
10441 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
10442 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
10443 }
10444
10445 /* Calculate PV... */
10446 met->pv[ix][iy][ip] = (float)
10447 (1e6 * G0 *
10448 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
10449 }
10450 }
10451 }
10452
10453 /* Fix for polar regions... */
10454#pragma omp parallel for default(shared)
10455 for (int ix = 0; ix < met->nx; ix++)
10456 for (int ip = 0; ip < met->np; ip++) {
10457 met->pv[ix][0][ip]
10458 = met->pv[ix][1][ip]
10459 = met->pv[ix][2][ip];
10460 met->pv[ix][met->ny - 1][ip]
10461 = met->pv[ix][met->ny - 2][ip]
10462 = met->pv[ix][met->ny - 3][ip];
10463 }
10464}
10465
10466/*****************************************************************************/
10467
10469 met_t *met) {
10470
10471 /* Set timer... */
10472 SELECT_TIMER("READ_MET_OZONE", "METPROC");
10473 LOG(2, "Calculate total column ozone...");
10474
10475 /* Loop over columns... */
10476#pragma omp parallel for default(shared) collapse(2)
10477 for (int ix = 0; ix < met->nx; ix++)
10478 for (int iy = 0; iy < met->ny; iy++) {
10479
10480 /* Integrate... */
10481 double cd = 0;
10482 for (int ip = 1; ip < met->np; ip++)
10483 if (met->p[ip - 1] <= met->ps[ix][iy]) {
10484 const double vmr =
10485 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
10486 const double dp = met->p[ip - 1] - met->p[ip];
10487 cd += vmr * MO3 / MA * dp * 1e2 / G0;
10488 }
10489
10490 /* Convert to Dobson units... */
10491 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
10492 }
10493}
10494
10495/*****************************************************************************/
10496
10498 const ctl_t *ctl,
10499 met_t *met) {
10500
10501 met_t *help;
10502
10503 /* Check parameters... */
10504 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
10505 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
10506 return;
10507
10508 /* Set timer... */
10509 SELECT_TIMER("READ_MET_SAMPLE", "METPROC");
10510 LOG(2, "Downsampling of meteo data...");
10511
10512 /* Allocate... */
10513 ALLOC(help, met_t, 1);
10514
10515 /* Copy data... */
10516 help->nx = met->nx;
10517 help->ny = met->ny;
10518 help->np = met->np;
10519 memcpy(help->lon, met->lon, sizeof(met->lon));
10520 memcpy(help->lat, met->lat, sizeof(met->lat));
10521 memcpy(help->p, met->p, sizeof(met->p));
10522
10523 /* Smoothing... */
10524 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
10525 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
10526 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
10527 help->ps[ix][iy] = 0;
10528 help->zs[ix][iy] = 0;
10529 help->ts[ix][iy] = 0;
10530 help->us[ix][iy] = 0;
10531 help->vs[ix][iy] = 0;
10532 help->ess[ix][iy] = 0;
10533 help->nss[ix][iy] = 0;
10534 help->shf[ix][iy] = 0;
10535 help->lsm[ix][iy] = 0;
10536 help->sst[ix][iy] = 0;
10537 help->pbl[ix][iy] = 0;
10538 help->cape[ix][iy] = 0;
10539 help->cin[ix][iy] = 0;
10540 help->t[ix][iy][ip] = 0;
10541 help->u[ix][iy][ip] = 0;
10542 help->v[ix][iy][ip] = 0;
10543 help->w[ix][iy][ip] = 0;
10544 help->h2o[ix][iy][ip] = 0;
10545 help->o3[ix][iy][ip] = 0;
10546 help->lwc[ix][iy][ip] = 0;
10547 help->rwc[ix][iy][ip] = 0;
10548 help->iwc[ix][iy][ip] = 0;
10549 help->swc[ix][iy][ip] = 0;
10550 help->cc[ix][iy][ip] = 0;
10551 float wsum = 0;
10552 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
10553 ix2++) {
10554 int ix3 = ix2;
10555 if (ix3 < 0)
10556 ix3 += met->nx;
10557 else if (ix3 >= met->nx)
10558 ix3 -= met->nx;
10559
10560 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
10561 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
10562 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
10563 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
10564 const float w =
10565 (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
10566 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
10567 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
10568 help->ps[ix][iy] += w * met->ps[ix3][iy2];
10569 help->zs[ix][iy] += w * met->zs[ix3][iy2];
10570 help->ts[ix][iy] += w * met->ts[ix3][iy2];
10571 help->us[ix][iy] += w * met->us[ix3][iy2];
10572 help->vs[ix][iy] += w * met->vs[ix3][iy2];
10573 help->ess[ix][iy] += w * met->ess[ix3][iy2];
10574 help->nss[ix][iy] += w * met->nss[ix3][iy2];
10575 help->shf[ix][iy] += w * met->shf[ix3][iy2];
10576 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
10577 help->sst[ix][iy] += w * met->sst[ix3][iy2];
10578 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
10579 help->cape[ix][iy] += w * met->cape[ix3][iy2];
10580 help->cin[ix][iy] += w * met->cin[ix3][iy2];
10581 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
10582 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
10583 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
10584 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
10585 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
10586 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
10587 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
10588 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
10589 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
10590 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
10591 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
10592 wsum += w;
10593 }
10594 }
10595 help->ps[ix][iy] /= wsum;
10596 help->zs[ix][iy] /= wsum;
10597 help->ts[ix][iy] /= wsum;
10598 help->us[ix][iy] /= wsum;
10599 help->vs[ix][iy] /= wsum;
10600 help->ess[ix][iy] /= wsum;
10601 help->nss[ix][iy] /= wsum;
10602 help->shf[ix][iy] /= wsum;
10603 help->lsm[ix][iy] /= wsum;
10604 help->sst[ix][iy] /= wsum;
10605 help->pbl[ix][iy] /= wsum;
10606 help->cape[ix][iy] /= wsum;
10607 help->cin[ix][iy] /= wsum;
10608 help->t[ix][iy][ip] /= wsum;
10609 help->u[ix][iy][ip] /= wsum;
10610 help->v[ix][iy][ip] /= wsum;
10611 help->w[ix][iy][ip] /= wsum;
10612 help->h2o[ix][iy][ip] /= wsum;
10613 help->o3[ix][iy][ip] /= wsum;
10614 help->lwc[ix][iy][ip] /= wsum;
10615 help->rwc[ix][iy][ip] /= wsum;
10616 help->iwc[ix][iy][ip] /= wsum;
10617 help->swc[ix][iy][ip] /= wsum;
10618 help->cc[ix][iy][ip] /= wsum;
10619 }
10620 }
10621 }
10622
10623 /* Downsampling... */
10624 met->nx = 0;
10625 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
10626 met->lon[met->nx] = help->lon[ix];
10627 met->ny = 0;
10628 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
10629 met->lat[met->ny] = help->lat[iy];
10630 met->ps[met->nx][met->ny] = help->ps[ix][iy];
10631 met->zs[met->nx][met->ny] = help->zs[ix][iy];
10632 met->ts[met->nx][met->ny] = help->ts[ix][iy];
10633 met->us[met->nx][met->ny] = help->us[ix][iy];
10634 met->vs[met->nx][met->ny] = help->vs[ix][iy];
10635 met->ess[met->nx][met->ny] = help->ess[ix][iy];
10636 met->nss[met->nx][met->ny] = help->nss[ix][iy];
10637 met->shf[met->nx][met->ny] = help->shf[ix][iy];
10638 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
10639 met->sst[met->nx][met->ny] = help->sst[ix][iy];
10640 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
10641 met->cape[met->nx][met->ny] = help->cape[ix][iy];
10642 met->cin[met->nx][met->ny] = help->cin[ix][iy];
10643 met->np = 0;
10644 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
10645 met->p[met->np] = help->p[ip];
10646 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
10647 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
10648 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
10649 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
10650 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
10651 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
10652 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
10653 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
10654 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
10655 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
10656 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
10657 met->np++;
10658 }
10659 met->ny++;
10660 }
10661 met->nx++;
10662 }
10663
10664 /* Free... */
10665 free(help);
10666}
10667
10668/*****************************************************************************/
10669
10671 const ctl_t *ctl,
10672 const clim_t *clim,
10673 met_t *met) {
10674
10675 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
10676 th2[200], z[EP], z2[200];
10677
10678 /* Set timer... */
10679 SELECT_TIMER("READ_MET_TROPO", "METPROC");
10680 LOG(2, "Calculate tropopause...");
10681
10682 /* Get altitude and pressure profiles... */
10683#pragma omp parallel for default(shared)
10684 for (int iz = 0; iz < met->np; iz++)
10685 z[iz] = Z(met->p[iz]);
10686#pragma omp parallel for default(shared)
10687 for (int iz = 0; iz <= 190; iz++) {
10688 z2[iz] = 4.5 + 0.1 * iz;
10689 p2[iz] = P(z2[iz]);
10690 }
10691
10692 /* Do not calculate tropopause... */
10693 if (ctl->met_tropo == 0)
10694#pragma omp parallel for default(shared) collapse(2)
10695 for (int ix = 0; ix < met->nx; ix++)
10696 for (int iy = 0; iy < met->ny; iy++)
10697 met->pt[ix][iy] = NAN;
10698
10699 /* Use tropopause climatology... */
10700 else if (ctl->met_tropo == 1) {
10701#pragma omp parallel for default(shared) collapse(2)
10702 for (int ix = 0; ix < met->nx; ix++)
10703 for (int iy = 0; iy < met->ny; iy++)
10704 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
10705 }
10706
10707 /* Use cold point... */
10708 else if (ctl->met_tropo == 2) {
10709
10710 /* Loop over grid points... */
10711#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10712 for (int ix = 0; ix < met->nx; ix++)
10713 for (int iy = 0; iy < met->ny; iy++) {
10714
10715 /* Interpolate temperature profile... */
10716 for (int iz = 0; iz < met->np; iz++)
10717 t[iz] = met->t[ix][iy][iz];
10718 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
10719
10720 /* Find minimum... */
10721 int iz = (int) gsl_stats_min_index(t2, 1, 171);
10722 if (iz > 0 && iz < 170)
10723 met->pt[ix][iy] = (float) p2[iz];
10724 else
10725 met->pt[ix][iy] = NAN;
10726 }
10727 }
10728
10729 /* Use WMO definition... */
10730 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
10731
10732 /* Loop over grid points... */
10733#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10734 for (int ix = 0; ix < met->nx; ix++)
10735 for (int iy = 0; iy < met->ny; iy++) {
10736
10737 /* Interpolate temperature profile... */
10738 int iz;
10739 for (iz = 0; iz < met->np; iz++)
10740 t[iz] = met->t[ix][iy][iz];
10741 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
10742
10743 /* Find 1st tropopause... */
10744 met->pt[ix][iy] = NAN;
10745 for (iz = 0; iz <= 170; iz++) {
10746 int found = 1;
10747 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10748 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10749 found = 0;
10750 break;
10751 }
10752 if (found) {
10753 if (iz > 0 && iz < 170)
10754 met->pt[ix][iy] = (float) p2[iz];
10755 break;
10756 }
10757 }
10758
10759 /* Find 2nd tropopause... */
10760 if (ctl->met_tropo == 4) {
10761 met->pt[ix][iy] = NAN;
10762 for (; iz <= 170; iz++) {
10763 int found = 1;
10764 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
10765 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
10766 found = 0;
10767 break;
10768 }
10769 if (found)
10770 break;
10771 }
10772 for (; iz <= 170; iz++) {
10773 int found = 1;
10774 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10775 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10776 found = 0;
10777 break;
10778 }
10779 if (found) {
10780 if (iz > 0 && iz < 170)
10781 met->pt[ix][iy] = (float) p2[iz];
10782 break;
10783 }
10784 }
10785 }
10786 }
10787 }
10788
10789 /* Use dynamical tropopause... */
10790 else if (ctl->met_tropo == 5) {
10791
10792 /* Loop over grid points... */
10793#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
10794 for (int ix = 0; ix < met->nx; ix++)
10795 for (int iy = 0; iy < met->ny; iy++) {
10796
10797 /* Interpolate potential vorticity profile... */
10798 for (int iz = 0; iz < met->np; iz++)
10799 pv[iz] = met->pv[ix][iy][iz];
10800 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
10801
10802 /* Interpolate potential temperature profile... */
10803 for (int iz = 0; iz < met->np; iz++)
10804 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
10805 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
10806
10807 /* Find dynamical tropopause... */
10808 met->pt[ix][iy] = NAN;
10809 for (int iz = 0; iz <= 170; iz++)
10810 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
10811 || th2[iz] >= ctl->met_tropo_theta) {
10812 if (iz > 0 && iz < 170)
10813 met->pt[ix][iy] = (float) p2[iz];
10814 break;
10815 }
10816 }
10817 }
10818
10819 else
10820 ERRMSG("Cannot calculate tropopause!");
10821
10822 /* Interpolate temperature, geopotential height, and water vapor... */
10823#pragma omp parallel for default(shared) collapse(2)
10824 for (int ix = 0; ix < met->nx; ix++)
10825 for (int iy = 0; iy < met->ny; iy++) {
10826 double h2ot, tt, zt;
10828 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
10829 met->lat[iy], &tt, ci, cw, 1);
10830 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
10831 met->lat[iy], &zt, ci, cw, 0);
10832 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
10833 met->lat[iy], &h2ot, ci, cw, 0);
10834 met->tt[ix][iy] = (float) tt;
10835 met->zt[ix][iy] = (float) zt;
10836 met->h2ot[ix][iy] = (float) h2ot;
10837 }
10838}
10839
10840/*****************************************************************************/
10841
10843 const char *filename,
10844 const ctl_t *ctl,
10845 double *rt,
10846 double *rz,
10847 double *rlon,
10848 double *rlat,
10849 double *robs,
10850 int *nobs) {
10851
10852 /* Write info... */
10853 LOG(1, "Read observation data: %s", filename);
10854
10855 /* Read data... */
10856 if (ctl->obs_type == 0)
10857 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
10858 else if (ctl->obs_type == 1)
10859 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
10860 else
10861 ERRMSG("Set OBS_TYPE to 0 or 1!");
10862
10863 /* Check time... */
10864 for (int i = 1; i < *nobs; i++)
10865 if (rt[i] < rt[i - 1])
10866 ERRMSG("Time must be ascending!");
10867
10868 /* Write info... */
10869 int n = *nobs;
10870 double mini, maxi;
10871 LOG(2, "Number of observations: %d", *nobs);
10872 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
10873 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
10874 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
10875 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
10876 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
10877 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
10878 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
10879 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
10880 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
10881 LOG(2, "Observation range: %g ... %g", mini, maxi);
10882}
10883
10884/*****************************************************************************/
10885
10887 const char *filename,
10888 double *rt,
10889 double *rz,
10890 double *rlon,
10891 double *rlat,
10892 double *robs,
10893 int *nobs) {
10894
10895 /* Open observation data file... */
10896 FILE *in;
10897 if (!(in = fopen(filename, "r")))
10898 ERRMSG("Cannot open file!");
10899
10900 /* Read observations... */
10901 char line[LEN];
10902 while (fgets(line, LEN, in))
10903 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
10904 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
10905 if ((++(*nobs)) >= NOBS)
10906 ERRMSG("Too many observations!");
10907
10908 /* Close observation data file... */
10909 fclose(in);
10910}
10911
10912/*****************************************************************************/
10913
10915 const char *filename,
10916 double *rt,
10917 double *rz,
10918 double *rlon,
10919 double *rlat,
10920 double *robs,
10921 int *nobs) {
10922
10923 int ncid, varid;
10924
10925 /* Open netCDF file... */
10926 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
10927 ERRMSG("Cannot open file!");
10928
10929 /* Read the observations from the NetCDF file... */
10930 NC_INQ_DIM("nobs", nobs, 1, NOBS, 1);
10931 NC_GET_DOUBLE("time", rt, 1);
10932 NC_GET_DOUBLE("alt", rz, 1);
10933 NC_GET_DOUBLE("lon", rlon, 1);
10934 NC_GET_DOUBLE("lat", rlat, 1);
10935 NC_GET_DOUBLE("obs", robs, 1);
10936
10937 /* Close file... */
10938 NC(nc_close(ncid));
10939}
10940
10941/*****************************************************************************/
10942
10944 const char *filename,
10945 int argc,
10946 char *argv[],
10947 const char *varname,
10948 const int arridx,
10949 const char *defvalue,
10950 char *value) {
10951
10952 FILE *in = NULL;
10953
10954 char fullname1[LEN], fullname2[LEN], rval[LEN];
10955
10956 int contain = 0, i;
10957
10958 /* Open file... */
10959 if (filename[strlen(filename) - 1] != '-')
10960 if (!(in = fopen(filename, "r")))
10961 ERRMSG("Cannot open file!");
10962
10963 /* Set full variable name... */
10964 if (arridx >= 0) {
10965 sprintf(fullname1, "%s[%d]", varname, arridx);
10966 sprintf(fullname2, "%s[*]", varname);
10967 } else {
10968 sprintf(fullname1, "%s", varname);
10969 sprintf(fullname2, "%s", varname);
10970 }
10971
10972 /* Read data... */
10973 if (in != NULL) {
10974 char dummy[LEN], line[LEN], rvarname[LEN];
10975 while (fgets(line, LEN, in)) {
10976 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
10977 if (strcasecmp(rvarname, fullname1) == 0 ||
10978 strcasecmp(rvarname, fullname2) == 0) {
10979 contain = 1;
10980 break;
10981 }
10982 }
10983 }
10984 for (i = 1; i < argc - 1; i++)
10985 if (strcasecmp(argv[i], fullname1) == 0 ||
10986 strcasecmp(argv[i], fullname2) == 0) {
10987 sprintf(rval, "%s", argv[i + 1]);
10988 contain = 1;
10989 break;
10990 }
10991
10992 /* Close file... */
10993 if (in != NULL)
10994 fclose(in);
10995
10996 /* Check for missing variables... */
10997 if (!contain) {
10998 if (strlen(defvalue) > 0)
10999 sprintf(rval, "%s", defvalue);
11000 else
11001 ERRMSG("Missing variable %s!\n", fullname1);
11002 }
11003
11004 /* Write info... */
11005 LOG(1, "%s = %s", fullname1, rval);
11006
11007 /* Return values... */
11008 if (value != NULL)
11009 sprintf(value, "%s", rval);
11010 return atof(rval);
11011}
11012
11013/*****************************************************************************/
11014
11015double sedi(
11016 const double p,
11017 const double T,
11018 const double rp,
11019 const double rhop) {
11020
11021 /* Convert particle radius from microns to m... */
11022 const double rp_help = rp * 1e-6;
11023
11024 /* Density of dry air [kg / m^3]... */
11025 const double rho = RHO(p, T);
11026
11027 /* Dynamic viscosity of air [kg / (m s)]... */
11028 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
11029
11030 /* Thermal velocity of an air molecule [m / s]... */
11031 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
11032
11033 /* Mean free path of an air molecule [m]... */
11034 const double lambda = 2. * eta / (rho * v);
11035
11036 /* Knudsen number for air (dimensionless)... */
11037 const double K = lambda / rp_help;
11038
11039 /* Cunningham slip-flow correction (dimensionless)... */
11040 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
11041
11042 /* Sedimentation velocity [m / s]... */
11043 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
11044}
11045
11046/*****************************************************************************/
11047
11049 const double *x,
11050 const double *y,
11051 const int n,
11052 const double *x2,
11053 double *y2,
11054 const int n2,
11055 const int method) {
11056
11057 /* Cubic spline interpolation... */
11058 if (method == 1) {
11059
11060 /* Allocate... */
11061 gsl_interp_accel *acc = gsl_interp_accel_alloc();
11062 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
11063
11064 /* Interpolate profile... */
11065 gsl_spline_init(s, x, y, (size_t) n);
11066 for (int i = 0; i < n2; i++)
11067 if (x2[i] <= x[0])
11068 y2[i] = y[0];
11069 else if (x2[i] >= x[n - 1])
11070 y2[i] = y[n - 1];
11071 else
11072 y2[i] = gsl_spline_eval(s, x2[i], acc);
11073
11074 /* Free... */
11075 gsl_spline_free(s);
11076 gsl_interp_accel_free(acc);
11077 }
11078
11079 /* Linear interpolation... */
11080 else {
11081 for (int i = 0; i < n2; i++)
11082 if (x2[i] <= x[0])
11083 y2[i] = y[0];
11084 else if (x2[i] >= x[n - 1])
11085 y2[i] = y[n - 1];
11086 else {
11087 const int idx = locate_irr(x, n, x2[i]);
11088 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
11089 }
11090 }
11091}
11092
11093/*****************************************************************************/
11094
11096 const float *data,
11097 const int n) {
11098
11099 if (n <= 0)
11100 return 0;
11101
11102 float mean = 0, var = 0;
11103
11104 for (int i = 0; i < n; ++i) {
11105 mean += data[i];
11106 var += SQR(data[i]);
11107 }
11108
11109 var = var / (float) n - SQR(mean / (float) n);
11110
11111 return (var > 0 ? sqrtf(var) : 0);
11112}
11113
11114/*****************************************************************************/
11115
11117 const int year,
11118 const int mon,
11119 const int day,
11120 const int hour,
11121 const int min,
11122 const int sec,
11123 const double remain,
11124 double *jsec) {
11125
11126 struct tm t0, t1;
11127
11128 t0.tm_year = 100;
11129 t0.tm_mon = 0;
11130 t0.tm_mday = 1;
11131 t0.tm_hour = 0;
11132 t0.tm_min = 0;
11133 t0.tm_sec = 0;
11134
11135 t1.tm_year = year - 1900;
11136 t1.tm_mon = mon - 1;
11137 t1.tm_mday = day;
11138 t1.tm_hour = hour;
11139 t1.tm_min = min;
11140 t1.tm_sec = sec;
11141
11142 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
11143}
11144
11145/*****************************************************************************/
11146
11148 const char *name,
11149 const char *group,
11150 const int output) {
11151
11152 static char names[NTIMER][100], groups[NTIMER][100];
11153
11154 static double rt_name[NTIMER], rt_group[NTIMER],
11155 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
11156
11157 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
11158
11159 /* Get time... */
11160 t1 = omp_get_wtime();
11161 dt = t1 - t0;
11162
11163 /* Add elapsed time to current timers... */
11164 if (iname >= 0) {
11165 rt_name[iname] += dt;
11166 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
11167 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
11168 ct_name[iname]++;
11169 }
11170 if (igroup >= 0)
11171 rt_group[igroup] += t1 - t0;
11172
11173 /* Report timers... */
11174 if (output) {
11175 for (int i = 0; i < nname; i++)
11176 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
11177 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
11178 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
11179 for (int i = 0; i < ngroup; i++)
11180 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
11181 double total = 0.0;
11182 for (int i = 0; i < nname; i++)
11183 total += rt_name[i];
11184 LOG(1, "TIMER_TOTAL = %.3f s", total);
11185 }
11186
11187 /* Identify IDs of next timer... */
11188 for (iname = 0; iname < nname; iname++)
11189 if (strcasecmp(name, names[iname]) == 0)
11190 break;
11191 for (igroup = 0; igroup < ngroup; igroup++)
11192 if (strcasecmp(group, groups[igroup]) == 0)
11193 break;
11194
11195 /* Check whether this is a new timer... */
11196 if (iname >= nname) {
11197 sprintf(names[iname], "%s", name);
11198 if ((++nname) >= NTIMER)
11199 ERRMSG("Too many timers!");
11200 }
11201
11202 /* Check whether this is a new group... */
11203 if (igroup >= ngroup) {
11204 sprintf(groups[igroup], "%s", group);
11205 if ((++ngroup) >= NTIMER)
11206 ERRMSG("Too many groups!");
11207 }
11208
11209 /* Save starting time... */
11210 t0 = t1;
11211}
11212
11213/*****************************************************************************/
11214
11216 const char *filename,
11217 const int offset) {
11218
11219 char tstr[10];
11220
11221 double t;
11222
11223 /* Get time from filename... */
11224 int len = (int) strlen(filename);
11225 sprintf(tstr, "%.4s", &filename[len - offset]);
11226 int year = atoi(tstr);
11227 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
11228 int mon = atoi(tstr);
11229 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
11230 int day = atoi(tstr);
11231 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
11232 int hour = atoi(tstr);
11233 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
11234 int min = atoi(tstr);
11235
11236 /* Check time... */
11237 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
11238 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
11239 ERRMSG("Cannot read time from filename!");
11240
11241 /* Convert time to Julian seconds... */
11242 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
11243
11244 /* Return time... */
11245 return t;
11246}
11247
11248/*****************************************************************************/
11249
11251 const clim_t *clim,
11252 const atm_t *atm,
11253 const int ip) {
11254
11255 /* Get tropopause pressure... */
11256 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
11257
11258 /* Get pressure range... */
11259 const double p1 = pt * 0.866877899;
11260 const double p0 = pt / 0.866877899;
11261
11262 /* Get weighting factor... */
11263 if (atm->p[ip] > p0)
11264 return 1;
11265 else if (atm->p[ip] < p1)
11266 return 0;
11267 else
11268 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
11269}
11270
11271/*****************************************************************************/
11272
11274 const char *filename,
11275 const ctl_t *ctl,
11276 const atm_t *atm,
11277 const double t) {
11278
11279 FILE *out;
11280
11281 /* Set time interval for output... */
11282 const double t0 = t - 0.5 * ctl->dt_mod;
11283 const double t1 = t + 0.5 * ctl->dt_mod;
11284
11285 /* Check if gnuplot output is requested... */
11286 if (ctl->atm_gpfile[0] != '-') {
11287
11288 /* Create gnuplot pipe... */
11289 if (!(out = popen("gnuplot", "w")))
11290 ERRMSG("Cannot create pipe to gnuplot!");
11291
11292 /* Set plot filename... */
11293 fprintf(out, "set out \"%s.png\"\n", filename);
11294
11295 /* Set time string... */
11296 double r;
11297 int year, mon, day, hour, min, sec;
11298 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11299 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
11300 year, mon, day, hour, min);
11301
11302 /* Dump gnuplot file to pipe... */
11303 FILE *in;
11304 if (!(in = fopen(ctl->atm_gpfile, "r")))
11305 ERRMSG("Cannot open file!");
11306 char line[LEN];
11307 while (fgets(line, LEN, in))
11308 fprintf(out, "%s", line);
11309 fclose(in);
11310 }
11311
11312 else {
11313
11314 /* Create file... */
11315 if (!(out = fopen(filename, "w")))
11316 ERRMSG("Cannot create file!");
11317 }
11318
11319 /* Write header... */
11320 fprintf(out,
11321 "# $1 = time [s]\n"
11322 "# $2 = altitude [km]\n"
11323 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11324 for (int iq = 0; iq < ctl->nq; iq++)
11325 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
11326 ctl->qnt_unit[iq]);
11327 fprintf(out, "\n");
11328
11329 /* Write data... */
11330 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
11331
11332 /* Check time... */
11333 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11334 continue;
11335
11336 /* Write output... */
11337 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
11338 atm->lon[ip], atm->lat[ip]);
11339 for (int iq = 0; iq < ctl->nq; iq++) {
11340 fprintf(out, " ");
11341 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
11342 fprintf(out, ctl->qnt_format[iq], NAN);
11343 else
11344 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11345 }
11346 fprintf(out, "\n");
11347 }
11348
11349 /* Close file... */
11350 fclose(out);
11351}
11352
11353/*****************************************************************************/
11354
11356 const char *filename,
11357 const ctl_t *ctl,
11358 const atm_t *atm) {
11359
11360 FILE *out;
11361
11362 /* Create file... */
11363 if (!(out = fopen(filename, "w")))
11364 ERRMSG("Cannot create file!");
11365
11366 /* Write version of binary data... */
11367 int version = 100;
11368 FWRITE(&version, int,
11369 1,
11370 out);
11371
11372 /* Write data... */
11373 FWRITE(&atm->np, int,
11374 1,
11375 out);
11376 FWRITE(atm->time, double,
11377 (size_t) atm->np,
11378 out);
11379 FWRITE(atm->p, double,
11380 (size_t) atm->np,
11381 out);
11382 FWRITE(atm->lon, double,
11383 (size_t) atm->np,
11384 out);
11385 FWRITE(atm->lat, double,
11386 (size_t) atm->np,
11387 out);
11388 for (int iq = 0; iq < ctl->nq; iq++)
11389 FWRITE(atm->q[iq], double,
11390 (size_t) atm->np,
11391 out);
11392
11393 /* Write final flag... */
11394 int final = 999;
11395 FWRITE(&final, int,
11396 1,
11397 out);
11398
11399 /* Close file... */
11400 fclose(out);
11401}
11402
11403/*****************************************************************************/
11404
11406 const char *filename,
11407 const ctl_t *ctl,
11408 const atm_t *atm) {
11409
11410 int tid, pid, ncid, varid;
11411 size_t start[2], count[2];
11412
11413 /* Create file... */
11414 NC(nc_create(filename, NC_NETCDF4, &ncid));
11415
11416 /* Define dimensions... */
11417 NC(nc_def_dim(ncid, "time", 1, &tid));
11418 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11419
11420 /* Define variables and their attributes... */
11421 int dim_ids[2] = { tid, pid };
11422 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11423 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11424 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11425 ctl->atm_nc_level, 0);
11426 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11427 ctl->atm_nc_level, 0);
11428 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11429 ctl->atm_nc_level, 0);
11430 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11431 for (int iq = 0; iq < ctl->nq; iq++)
11432 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11433 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11434 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11435
11436 /* Define global attributes... */
11437 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11438 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11439
11440 /* End definitions... */
11441 NC(nc_enddef(ncid));
11442
11443 /* Write data... */
11444 NC_PUT_DOUBLE("time", atm->time, 0);
11445 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11446 NC_PUT_DOUBLE("LON", atm->lon, 0);
11447 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11448 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11449 for (int iq = 0; iq < ctl->nq; iq++)
11450 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11451
11452 /* Close file... */
11453 NC(nc_close(ncid));
11454}
11455
11456/*****************************************************************************/
11457
11459 const char *dirname,
11460 const ctl_t *ctl,
11461 const atm_t *atm,
11462 const double t) {
11463
11464 /* Global Counter... */
11465 static size_t out_cnt = 0;
11466
11467 double r, r_start, r_stop;
11468 int year, mon, day, hour, min, sec;
11469 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
11470 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
11471 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
11472
11473 int ncid, varid, tid, pid, cid;
11474 int dim_ids[2];
11475
11476 /* time, nparc */
11477 size_t start[2];
11478 size_t count[2];
11479
11480 /* Determine start and stop times of calculation... */
11481 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11482 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
11483 &min_start, &sec_start, &r_start);
11484 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
11485 &min_stop, &sec_stop, &r_stop);
11486
11487 sprintf(filename_out,
11488 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
11489 year_start % 100, mon_start, day_start, hour_start,
11490 year_stop % 100, mon_stop, day_stop, hour_stop);
11491 LOG(1, "Write traj file: %s", filename_out);
11492
11493 /* Define hyperslap for the traj_file... */
11494 start[0] = out_cnt;
11495 start[1] = 0;
11496 count[0] = 1;
11497 count[1] = (size_t) atm->np;
11498
11499 /* Create the file at the first timestep... */
11500 if (out_cnt == 0) {
11501
11502 /* Create file... */
11503 NC(nc_create(filename_out, NC_NETCDF4, &ncid));
11504
11505 /* Define dimensions... */
11506 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
11507 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11508 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
11509 dim_ids[0] = tid;
11510 dim_ids[1] = pid;
11511
11512 /* Define variables and their attributes... */
11513 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11514 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11515 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
11516 ctl->atm_nc_level, 0);
11517 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
11518 ctl->atm_nc_level, 0);
11519 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
11520 ctl->atm_nc_level, 0);
11521 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
11522 ctl->atm_nc_level, 0);
11523 for (int iq = 0; iq < ctl->nq; iq++)
11524 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11525 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11526 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11527
11528 /* Define global attributes... */
11529 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11530 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11531
11532 /* End definitions... */
11533 NC(nc_enddef(ncid));
11534 NC(nc_close(ncid));
11535 }
11536
11537 /* Increment global counter to change hyperslap... */
11538 out_cnt++;
11539
11540 /* Open file... */
11541 NC(nc_open(filename_out, NC_WRITE, &ncid));
11542
11543 /* Write data... */
11544 NC_PUT_DOUBLE("time", atm->time, 1);
11545 NC_PUT_DOUBLE("LAT", atm->lat, 1);
11546 NC_PUT_DOUBLE("LON", atm->lon, 1);
11547 NC_PUT_DOUBLE("PRESS", atm->p, 1);
11548 if (ctl->advect_vert_coord == 1) {
11549 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
11550 } else if (ctl->qnt_zeta >= 0) {
11551 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
11552 }
11553 for (int iq = 0; iq < ctl->nq; iq++)
11554 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
11555
11556 /* Close file... */
11557 NC(nc_close(ncid));
11558
11559 /* At the last time step create the init_fix_YYYYMMDDHH file... */
11560 if ((year == year_stop) && (mon == mon_stop)
11561 && (day == day_stop) && (hour == hour_stop)) {
11562
11563 /* Set filename... */
11564 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
11565 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
11566 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
11567 LOG(1, "Write init file: %s", filename_init);
11568
11569 /* Create file... */
11570 NC(nc_create(filename_init, NC_NETCDF4, &ncid));
11571
11572 /* Define dimensions... */
11573 NC(nc_def_dim(ncid, "time", 1, &tid));
11574 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11575 dim_ids[0] = tid;
11576 dim_ids[1] = pid;
11577
11578 /* Define variables and their attributes... */
11579 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11580 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11581 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11582 ctl->atm_nc_level, 0);
11583 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11584 ctl->atm_nc_level, 0);
11585 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11586 ctl->atm_nc_level, 0);
11587 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11588 for (int iq = 0; iq < ctl->nq; iq++)
11589 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11590 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11591 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11592
11593 /* Define global attributes... */
11594 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11595 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11596
11597 /* End definitions... */
11598 NC(nc_enddef(ncid));
11599
11600 /* Write data... */
11601 NC_PUT_DOUBLE("time", atm->time, 0);
11602 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11603 NC_PUT_DOUBLE("LON", atm->lon, 0);
11604 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11605 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11606 for (int iq = 0; iq < ctl->nq; iq++)
11607 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11608
11609 /* Close file... */
11610 NC(nc_close(ncid));
11611 }
11612}
11613
11614/*****************************************************************************/
11615
11617 const char *filename,
11618 const ctl_t *ctl,
11619 const atm_t *atm) {
11620
11621 int ncid, obsid, varid;
11622
11623 size_t start[2], count[2];
11624
11625 /* Create file... */
11626 NC(nc_create(filename, NC_NETCDF4, &ncid));
11627
11628 /* Define dimensions... */
11629 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
11630
11631 /* Define variables and their attributes... */
11632 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
11633 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11634 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
11635 ctl->atm_nc_level, 0);
11636 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
11637 ctl->atm_nc_level, 0);
11638 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
11639 ctl->atm_nc_level, 0);
11640 for (int iq = 0; iq < ctl->nq; iq++)
11641 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
11642 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
11643 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11644
11645 /* Define global attributes... */
11646 NC_PUT_ATT_GLOBAL("featureType", "point");
11647
11648 /* End definitions... */
11649 NC(nc_enddef(ncid));
11650
11651 /* Write data... */
11652 NC_PUT_DOUBLE("time", atm->time, 0);
11653 NC_PUT_DOUBLE("press", atm->p, 0);
11654 NC_PUT_DOUBLE("lon", atm->lon, 0);
11655 NC_PUT_DOUBLE("lat", atm->lat, 0);
11656 for (int iq = 0; iq < ctl->nq; iq++)
11657 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11658
11659 /* Close file... */
11660 NC(nc_close(ncid));
11661}
11662
11663/*****************************************************************************/
11664
11666 const char *filename,
11667 const ctl_t *ctl,
11668 const atm_t *atm,
11669 const double t) {
11670
11671 static FILE *out;
11672
11673 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
11674 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
11675
11676 static int *obscount, nobs, nk;
11677
11678 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
11679
11680 const int ensemble = (ctl->nens > 0);
11681
11682 /* Set timer */
11683 SELECT_TIMER("WRITE_CSI", "OUTPUT");
11684
11685 /* Check quantities... */
11686 if (ctl->qnt_m < 0)
11687 ERRMSG("Need quantity mass!");
11688 if (ensemble) {
11689 if (ctl->qnt_ens < 0)
11690 ERRMSG("Missing ensemble IDs!");
11691 if (ctl->nens > NENS)
11692 ERRMSG("Too many ensembles!");
11693 }
11694
11695 /* Init... */
11696 if (t == ctl->t_start) {
11697
11698 /* Allocate.. */
11699 ALLOC(area, double,
11700 ctl->csi_ny);
11701 ALLOC(rt, double,
11702 NOBS);
11703 ALLOC(rz, double,
11704 NOBS);
11705 ALLOC(rlon, double,
11706 NOBS);
11707 ALLOC(rlat, double,
11708 NOBS);
11709 ALLOC(robs, double,
11710 NOBS);
11711
11712 /* Read observation data... */
11713 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11714
11715 /* Read kernel data... */
11716 if (ctl->csi_kernel[0] != '-')
11717 read_kernel(ctl->csi_kernel, kz, kw, &nk);
11718
11719 /* Create new file... */
11720 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
11721 if (!(out = fopen(filename, "w")))
11722 ERRMSG("Cannot create file!");
11723
11724 /* Write header... */
11725 fprintf(out,
11726 "# $1 = time [s]\n"
11727 "# $2 = ensemble ID\n"
11728 "# $3 = number of hits (cx)\n"
11729 "# $4 = number of misses (cy)\n"
11730 "# $5 = number of false alarms (cz)\n"
11731 "# $6 = number of observations (cx + cy)\n"
11732 "# $7 = number of forecasts (cx + cz)\n"
11733 "# $8 = bias (%%)\n"
11734 "# $9 = POD (%%)\n"
11735 "# $10 = FAR (%%)\n"
11736 "# $11 = CSI (%%)\n"
11737 "# $12 = hits by random chance\n"
11738 "# $13 = ETS (%%)\n"
11739 "# $14 = Pearson R\n"
11740 "# $15 = Spearman R\n"
11741 "# $16 = mean error [kg/m²]\n"
11742 "# $17 = RMSE [kg/m²]\n"
11743 "# $18 = MAE [kg/m²]\n"
11744 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
11745
11746 /* Set grid box size... */
11747 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
11748 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
11749 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
11750
11751 /* Set horizontal coordinates... */
11752 for (int iy = 0; iy < ctl->csi_ny; iy++) {
11753 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
11754 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
11755 }
11756 }
11757
11758 /* Set time interval... */
11759 const double t0 = t - 0.5 * ctl->dt_mod;
11760 const double t1 = t + 0.5 * ctl->dt_mod;
11761
11762 /* Allocate... */
11763 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
11764 ALLOC(modmean, double,
11765 (ensemble ? ctl->nens : 1) * grid_size);
11766 ALLOC(obsmean, double,
11767 grid_size);
11768 ALLOC(obscount, int,
11769 grid_size);
11770 ALLOC(obsstd, double,
11771 grid_size);
11772
11773 /* Init... */
11774 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
11775 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
11776
11777 /* Loop over observations... */
11778 for (int i = 0; i < nobs; i++) {
11779 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
11780 continue;
11781
11782 /* Calculate indices... */
11783 const int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
11784 const int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
11785 const int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
11786 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11787 || iz >= ctl->csi_nz)
11788 continue;
11789
11790 /* Get mean observation index... */
11791 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11792 obsmean[idx] += robs[i];
11793 obsstd[idx] += SQR(robs[i]);
11794 obscount[idx]++;
11795 }
11796
11797 /* Analyze model data... */
11798 for (int ip = 0; ip < atm->np; ip++) {
11799
11800 /* Check time... */
11801 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11802 continue;
11803
11804 /* Get ensemble ID... */
11805 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
11806 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
11807 ERRMSG("Ensemble ID out of range!");
11808
11809 /* Get indices... */
11810 const int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
11811 const int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
11812 const int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
11813 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11814 || iz >= ctl->csi_nz)
11815 continue;
11816
11817 /* Get total mass in grid cell... */
11818 const int idx =
11819 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11820 modmean[idx] +=
11821 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11822 }
11823 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11824 /* Analyze all grid cells... */
11825 for (int ix = 0; ix < ctl->csi_nx; ix++)
11826 for (int iy = 0; iy < ctl->csi_ny; iy++)
11827 for (int iz = 0; iz < ctl->csi_nz; iz++) {
11828
11829 /* Calculate mean observation index... */
11830 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11831 if (e == 0)
11832 if (obscount[idx]) {
11833 obsmean[idx] /= obscount[idx];
11834 obsstd[idx] =
11835 sqrt(obsstd[idx] / obscount[idx] - SQR(obsmean[idx]));
11836 }
11837
11838 /* Calculate model mean per ensemble... */
11839 const int midx = e * grid_size + idx;
11840 if (modmean[midx] > 0)
11841 modmean[midx] /= (1e6 * area[iy]);
11842
11843 /* Check number of observations... */
11844 if (obscount[idx]) {
11845
11846 /* Calculate CSI... */
11847 ct[e]++;
11848 if (obsmean[idx] >= ctl->csi_obsmin
11849 && modmean[midx] >= ctl->csi_modmin)
11850 cx[e]++;
11851 else if (obsmean[idx] >= ctl->csi_obsmin)
11852 cy[e]++;
11853 else if (modmean[midx] >= ctl->csi_modmin)
11854 cz[e]++;
11855
11856 /* Save data for other verification statistics... */
11857 if (obsmean[idx] >= ctl->csi_obsmin
11858 || modmean[midx] >= ctl->csi_modmin) {
11859 x[n[e]] = modmean[midx];
11860 y[n[e]] = obsmean[idx];
11861 if (modmean[midx] >= ctl->csi_modmin)
11862 obsstdn[n[e]] = obsstd[idx];
11863 if ((++n[e]) >= NCSI)
11864 ERRMSG("Too many points for statistics!");
11865 }
11866 }
11867 }
11868 /* Write output... */
11869 if (fmod(t, ctl->csi_dt_out) == 0) {
11870
11871 if (n[e] == 0)
11872 continue;
11873
11874 /* Calculate verification statistics
11875 (https://www.cawcr.gov.au/projects/verification/) ... */
11876 static double work[2 * NCSI], work2[2 * NCSI];
11877 const int n_obs = cx[e] + cy[e];
11878 const int n_for = cx[e] + cz[e];
11879 const double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
11880 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
11881 const double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
11882 const double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
11883 const double csi =
11884 (cx[e] + cy[e] + cz[e] >
11885 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
11886 const double ets =
11887 (cx[e] + cy[e] + cz[e] - cx_rd >
11888 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
11889 const double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
11890 const double rho_s =
11891 gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
11892 for (int i = 0; i < n[e]; i++) {
11893 work[i] = x[i] - y[i];
11894 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
11895 }
11896 const double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
11897 const double rmse =
11898 gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
11899 const double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
11900 const double loglikelihood =
11901 gsl_stats_tss_m(work2, 1, (size_t) n[e], 0.0) * -0.5;
11902
11903 /* Write... */
11904 fprintf(out,
11905 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
11906 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
11907 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
11908 loglikelihood, n[e]);
11909
11910 /* Set counters to zero... */
11911 for (int i = 0; i < n[e]; i++)
11912 work[i] = work2[i] = x[i] = y[i] = obsstdn[i] = 0;
11913 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
11914 }
11915 }
11916 /* Free... */
11917 free(modmean);
11918 free(obsmean);
11919 free(obscount);
11920 free(obsstd);
11921
11922 /* Finalize... */
11923 if (t == ctl->t_stop) {
11924
11925 /* Close output file... */
11926 fclose(out);
11927
11928 /* Free... */
11929 free(area);
11930 free(rt);
11931 free(rz);
11932 free(rlon);
11933 free(rlat);
11934 free(robs);
11935 }
11936}
11937
11938/*****************************************************************************/
11939
11941 const char *filename,
11942 const ctl_t *ctl,
11943 const atm_t *atm,
11944 const double t) {
11945
11946 static FILE *out;
11947
11948 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
11949 x[3], zm[NENS];
11950
11951 static int n[NENS];
11952
11953 /* Set timer... */
11954 SELECT_TIMER("WRITE_ENS", "OUTPUT");
11955
11956 /* Check quantities... */
11957 if (ctl->qnt_ens < 0)
11958 ERRMSG("Missing ensemble IDs!");
11959
11960 /* Set time interval... */
11961 const double t0 = t - 0.5 * ctl->dt_mod;
11962 const double t1 = t + 0.5 * ctl->dt_mod;
11963
11964 /* Init... */
11965 for (int i = 0; i < NENS; i++) {
11966 for (int iq = 0; iq < ctl->nq; iq++)
11967 qm[iq][i] = qs[iq][i] = 0;
11968 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
11969 n[i] = 0;
11970 }
11971
11972 /* Loop over air parcels... */
11973 for (int ip = 0; ip < atm->np; ip++) {
11974
11975 /* Check time... */
11976 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11977 continue;
11978
11979 /* Check ensemble ID... */
11980 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
11981 ERRMSG("Ensemble ID is out of range!");
11982
11983 /* Get means... */
11984 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
11985 for (int iq = 0; iq < ctl->nq; iq++) {
11986 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
11987 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
11988 }
11989 xm[ctl->qnt_ens][0] += x[0];
11990 xm[ctl->qnt_ens][1] += x[1];
11991 xm[ctl->qnt_ens][2] += x[2];
11992 zm[ctl->qnt_ens] += Z(atm->p[ip]);
11993 n[ctl->qnt_ens]++;
11994 }
11995
11996 /* Create file... */
11997 LOG(1, "Write ensemble data: %s", filename);
11998 if (!(out = fopen(filename, "w")))
11999 ERRMSG("Cannot create file!");
12000
12001 /* Write header... */
12002 fprintf(out,
12003 "# $1 = time [s]\n"
12004 "# $2 = altitude [km]\n"
12005 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12006 for (int iq = 0; iq < ctl->nq; iq++)
12007 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
12008 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12009 for (int iq = 0; iq < ctl->nq; iq++)
12010 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
12011 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12012 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
12013
12014 /* Write data... */
12015 for (int i = 0; i < NENS; i++)
12016 if (n[i] > 0) {
12017 cart2geo(xm[i], &dummy, &lon, &lat);
12018 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
12019 for (int iq = 0; iq < ctl->nq; iq++) {
12020 fprintf(out, " ");
12021 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
12022 }
12023 for (int iq = 0; iq < ctl->nq; iq++) {
12024 fprintf(out, " ");
12025 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
12026 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
12027 }
12028 fprintf(out, " %d\n", n[i]);
12029 }
12030
12031 /* Close file... */
12032 fclose(out);
12033}
12034
12035/*****************************************************************************/
12036
12038 const char *filename,
12039 const ctl_t *ctl,
12040 met_t *met0,
12041 met_t *met1,
12042 const atm_t *atm,
12043 const double t) {
12044
12045 static double kz[EP], kw[EP];
12046
12047 static int nk;
12048
12049 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
12050
12051 int *ixs, *iys, *izs, *np;
12052
12053 /* Set timer... */
12054 SELECT_TIMER("WRITE_GRID", "OUTPUT");
12055
12056 /* Write info... */
12057 LOG(1, "Write grid data: %s", filename);
12058
12059 /* Init... */
12060 if (t == ctl->t_start) {
12061
12062 /* Read kernel data... */
12063 if (ctl->grid_kernel[0] != '-')
12064 read_kernel(ctl->grid_kernel, kz, kw, &nk);
12065 }
12066
12067 /* Allocate... */
12068 ALLOC(cd, double,
12069 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12070 for (int iq = 0; iq < ctl->nq; iq++) {
12071 ALLOC(mean[iq], double,
12072 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12073 ALLOC(sigma[iq], double,
12074 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12075 }
12076 ALLOC(vmr_impl, double,
12077 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12078 ALLOC(z, double,
12079 ctl->grid_nz);
12080 ALLOC(lon, double,
12081 ctl->grid_nx);
12082 ALLOC(lat, double,
12083 ctl->grid_ny);
12084 ALLOC(area, double,
12085 ctl->grid_ny);
12086 ALLOC(press, double,
12087 ctl->grid_nz);
12088 ALLOC(np, int,
12089 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12090 ALLOC(ixs, int,
12091 atm->np);
12092 ALLOC(iys, int,
12093 atm->np);
12094 ALLOC(izs, int,
12095 atm->np);
12096
12097 /* Set grid box size... */
12098 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
12099 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
12100 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
12101
12102 /* Set vertical coordinates... */
12103#pragma omp parallel for default(shared)
12104 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12105 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
12106 press[iz] = P(z[iz]);
12107 }
12108
12109 /* Set horizontal coordinates... */
12110 for (int ix = 0; ix < ctl->grid_nx; ix++)
12111 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
12112#pragma omp parallel for default(shared)
12113 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12114 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
12115 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
12116 }
12117
12118 /* Set time interval for output... */
12119 const double t0 = t - 0.5 * ctl->dt_mod;
12120 const double t1 = t + 0.5 * ctl->dt_mod;
12121
12122 /* Get grid box indices... */
12123#pragma omp parallel for default(shared)
12124 for (int ip = 0; ip < atm->np; ip++) {
12125 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
12126 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
12127 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
12128 if (atm->time[ip] < t0 || atm->time[ip] > t1
12129 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
12130 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
12131 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
12132 izs[ip] = -1;
12133 }
12134
12135 /* Average data... */
12136 for (int ip = 0; ip < atm->np; ip++)
12137 if (izs[ip] >= 0) {
12138 const int idx =
12139 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
12140 const double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
12141 np[idx]++;
12142 for (int iq = 0; iq < ctl->nq; iq++) {
12143 mean[iq][idx] += kernel * atm->q[iq][ip];
12144 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
12145 }
12146 }
12147
12148 /* Calculate column density and volume mixing ratio... */
12149#pragma omp parallel for default(shared)
12150 for (int ix = 0; ix < ctl->grid_nx; ix++)
12151 for (int iy = 0; iy < ctl->grid_ny; iy++)
12152 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12153
12154 /* Get grid index... */
12155 const int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12156
12157 /* Calculate column density... */
12158 cd[idx] = NAN;
12159 if (ctl->qnt_m >= 0)
12160 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
12161
12162 /* Calculate volume mixing ratio (implicit)... */
12163 vmr_impl[idx] = NAN;
12164 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
12165 && met1 != NULL) {
12166 vmr_impl[idx] = 0;
12167 if (mean[ctl->qnt_m][idx] > 0) {
12168
12169 /* Get temperature... */
12170 double temp;
12172 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
12173 lon[ix], lat[iy], &temp, ci, cw, 1);
12174
12175 /* Calculate volume mixing ratio... */
12176 vmr_impl[idx] =
12177 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
12178 }
12179 }
12180
12181 /* Calculate mean... */
12182 if (np[idx] > 0)
12183 for (int iq = 0; iq < ctl->nq; iq++) {
12184 mean[iq][idx] /= np[idx];
12185 const double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
12186 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
12187 } else
12188 for (int iq = 0; iq < ctl->nq; iq++) {
12189 mean[iq][idx] = NAN;
12190 sigma[iq][idx] = NAN;
12191 }
12192 }
12193
12194 /* Write ASCII data... */
12195 if (ctl->grid_type == 0)
12196 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
12197 t, z, lon, lat, area, dz, np);
12198
12199 /* Write netCDF data... */
12200 else if (ctl->grid_type == 1)
12201 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
12202 t, z, lon, lat, area, dz, np);
12203
12204 /* Error message... */
12205 else
12206 ERRMSG("Grid data format GRID_TYPE unknown!");
12207
12208 /* Free... */
12209 free(cd);
12210 for (int iq = 0; iq < ctl->nq; iq++) {
12211 free(mean[iq]);
12212 free(sigma[iq]);
12213 }
12214 free(vmr_impl);
12215 free(z);
12216 free(lon);
12217 free(lat);
12218 free(area);
12219 free(press);
12220 free(np);
12221 free(ixs);
12222 free(iys);
12223 free(izs);
12224}
12225
12226/*****************************************************************************/
12227
12229 const char *filename,
12230 const ctl_t *ctl,
12231 const double *cd,
12232 double *mean[NQ],
12233 double *sigma[NQ],
12234 const double *vmr_impl,
12235 const double t,
12236 const double *z,
12237 const double *lon,
12238 const double *lat,
12239 const double *area,
12240 const double dz,
12241 const int *np) {
12242
12243 FILE *out;
12244
12245 /* Check if gnuplot output is requested... */
12246 if (ctl->grid_gpfile[0] != '-') {
12247
12248 /* Create gnuplot pipe... */
12249 if (!(out = popen("gnuplot", "w")))
12250 ERRMSG("Cannot create pipe to gnuplot!");
12251
12252 /* Set plot filename... */
12253 fprintf(out, "set out \"%s.png\"\n", filename);
12254
12255 /* Set time string... */
12256 double r;
12257 int year, mon, day, hour, min, sec;
12258 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
12259 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
12260 year, mon, day, hour, min);
12261
12262 /* Dump gnuplot file to pipe... */
12263 FILE *in;
12264 char line[LEN];
12265 if (!(in = fopen(ctl->grid_gpfile, "r")))
12266 ERRMSG("Cannot open file!");
12267 while (fgets(line, LEN, in))
12268 fprintf(out, "%s", line);
12269 fclose(in);
12270 }
12271
12272 else {
12273
12274 /* Create file... */
12275 if (!(out = fopen(filename, "w")))
12276 ERRMSG("Cannot create file!");
12277 }
12278
12279 /* Write header... */
12280 fprintf(out,
12281 "# $1 = time [s]\n"
12282 "# $2 = altitude [km]\n"
12283 "# $3 = longitude [deg]\n"
12284 "# $4 = latitude [deg]\n"
12285 "# $5 = surface area [km^2]\n"
12286 "# $6 = layer depth [km]\n"
12287 "# $7 = column density (implicit) [kg/m^2]\n"
12288 "# $8 = volume mixing ratio (implicit) [ppv]\n"
12289 "# $9 = number of particles [1]\n");
12290 for (int iq = 0; iq < ctl->nq; iq++)
12291 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
12292 ctl->qnt_unit[iq]);
12293 if (ctl->grid_stddev)
12294 for (int iq = 0; iq < ctl->nq; iq++)
12295 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
12296 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12297 fprintf(out, "\n");
12298
12299 /* Write data... */
12300 for (int ix = 0; ix < ctl->grid_nx; ix++) {
12301 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
12302 fprintf(out, "\n");
12303 for (int iy = 0; iy < ctl->grid_ny; iy++) {
12304 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
12305 fprintf(out, "\n");
12306 for (int iz = 0; iz < ctl->grid_nz; iz++) {
12307 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
12308 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
12309 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
12310 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
12311 for (int iq = 0; iq < ctl->nq; iq++) {
12312 fprintf(out, " ");
12313 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
12314 }
12315 if (ctl->grid_stddev)
12316 for (int iq = 0; iq < ctl->nq; iq++) {
12317 fprintf(out, " ");
12318 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
12319 }
12320 fprintf(out, "\n");
12321 }
12322 }
12323 }
12324 }
12325
12326 /* Close file... */
12327 fclose(out);
12328}
12329
12330/*****************************************************************************/
12331
12333 const char *filename,
12334 const ctl_t *ctl,
12335 const double *cd,
12336 double *mean[NQ],
12337 double *sigma[NQ],
12338 const double *vmr_impl,
12339 const double t,
12340 const double *z,
12341 const double *lon,
12342 const double *lat,
12343 const double *area,
12344 const double dz,
12345 const int *np) {
12346
12347 char longname[2 * LEN], varname[2 * LEN];
12348
12349 double *help;
12350
12351 int *help2, ncid, dimid[10], varid;
12352
12353 size_t start[2], count[2];
12354
12355 /* Allocate... */
12356 ALLOC(help, double,
12357 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12358 ALLOC(help2, int,
12359 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
12360
12361 /* Create file... */
12362 NC(nc_create(filename, NC_NETCDF4, &ncid));
12363
12364 /* Define dimensions... */
12365 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
12366 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
12367 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
12368 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
12369 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
12370
12371 /* Define variables and their attributes... */
12372 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
12373 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12374 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
12375 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
12376 0);
12377 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
12378 0);
12379 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
12380 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
12381
12382 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
12383 ctl->grid_nc_level, 0);
12384 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
12385 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
12386 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
12387 for (int iq = 0; iq < ctl->nq; iq++) {
12388 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12389 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
12390 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12391 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12392 if (ctl->grid_stddev) {
12393 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12394 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
12395 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
12396 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
12397 }
12398 }
12399 /* End definitions... */
12400 NC(nc_enddef(ncid));
12401
12402 /* Write data... */
12403 NC_PUT_DOUBLE("time", &t, 0);
12404 NC_PUT_DOUBLE("lon", lon, 0);
12405 NC_PUT_DOUBLE("lat", lat, 0);
12406 NC_PUT_DOUBLE("z", z, 0);
12407 NC_PUT_DOUBLE("area", area, 0);
12408 NC_PUT_DOUBLE("dz", &dz, 0);
12409
12410 for (int ix = 0; ix < ctl->grid_nx; ix++)
12411 for (int iy = 0; iy < ctl->grid_ny; iy++)
12412 for (int iz = 0; iz < ctl->grid_nz; iz++)
12413 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12414 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12415 NC_PUT_DOUBLE("cd", help, 0);
12416
12417 for (int ix = 0; ix < ctl->grid_nx; ix++)
12418 for (int iy = 0; iy < ctl->grid_ny; iy++)
12419 for (int iz = 0; iz < ctl->grid_nz; iz++)
12420 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12421 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12422 NC_PUT_DOUBLE("vmr_impl", help, 0);
12423
12424 for (int ix = 0; ix < ctl->grid_nx; ix++)
12425 for (int iy = 0; iy < ctl->grid_ny; iy++)
12426 for (int iz = 0; iz < ctl->grid_nz; iz++)
12427 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12428 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12429 NC_PUT_INT("np", help2, 0);
12430
12431 for (int iq = 0; iq < ctl->nq; iq++) {
12432 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12433 for (int ix = 0; ix < ctl->grid_nx; ix++)
12434 for (int iy = 0; iy < ctl->grid_ny; iy++)
12435 for (int iz = 0; iz < ctl->grid_nz; iz++)
12436 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12437 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12438 NC_PUT_DOUBLE(varname, help, 0);
12439 }
12440
12441 if (ctl->grid_stddev)
12442 for (int iq = 0; iq < ctl->nq; iq++) {
12443 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12444 for (int ix = 0; ix < ctl->grid_nx; ix++)
12445 for (int iy = 0; iy < ctl->grid_ny; iy++)
12446 for (int iz = 0; iz < ctl->grid_nz; iz++)
12447 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12448 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12449 NC_PUT_DOUBLE(varname, help, 0);
12450 }
12451
12452 /* Close file... */
12453 NC(nc_close(ncid));
12454
12455 /* Free... */
12456 free(help);
12457 free(help2);
12458}
12459
12460/*****************************************************************************/
12461
12463 const char *filename,
12464 const ctl_t *ctl,
12465 met_t *met) {
12466
12467 /* Create file... */
12468 FILE *out;
12469 if (!(out = fopen(filename, "w")))
12470 ERRMSG("Cannot create file!");
12471
12472 /* Write type of binary data... */
12473 FWRITE(&ctl->met_type, int,
12474 1,
12475 out);
12476
12477 /* Write version of binary data... */
12478 int version = 103;
12479 FWRITE(&version, int,
12480 1,
12481 out);
12482
12483 /* Write grid data... */
12484 FWRITE(&met->time, double,
12485 1,
12486 out);
12487 FWRITE(&met->nx, int,
12488 1,
12489 out);
12490 FWRITE(&met->ny, int,
12491 1,
12492 out);
12493 FWRITE(&met->np, int,
12494 1,
12495 out);
12496 FWRITE(met->lon, double,
12497 (size_t) met->nx,
12498 out);
12499 FWRITE(met->lat, double,
12500 (size_t) met->ny,
12501 out);
12502 FWRITE(met->p, double,
12503 (size_t) met->np,
12504 out);
12505
12506 /* Write surface data... */
12507 write_met_bin_2d(out, met, met->ps, "PS");
12508 write_met_bin_2d(out, met, met->ts, "TS");
12509 write_met_bin_2d(out, met, met->zs, "ZS");
12510 write_met_bin_2d(out, met, met->us, "US");
12511 write_met_bin_2d(out, met, met->vs, "VS");
12512 write_met_bin_2d(out, met, met->ess, "ESS");
12513 write_met_bin_2d(out, met, met->nss, "NSS");
12514 write_met_bin_2d(out, met, met->shf, "SHF");
12515 write_met_bin_2d(out, met, met->lsm, "LSM");
12516 write_met_bin_2d(out, met, met->sst, "SST");
12517 write_met_bin_2d(out, met, met->pbl, "PBL");
12518 write_met_bin_2d(out, met, met->pt, "PT");
12519 write_met_bin_2d(out, met, met->tt, "TT");
12520 write_met_bin_2d(out, met, met->zt, "ZT");
12521 write_met_bin_2d(out, met, met->h2ot, "H2OT");
12522 write_met_bin_2d(out, met, met->pct, "PCT");
12523 write_met_bin_2d(out, met, met->pcb, "PCB");
12524 write_met_bin_2d(out, met, met->cl, "CL");
12525 write_met_bin_2d(out, met, met->plcl, "PLCL");
12526 write_met_bin_2d(out, met, met->plfc, "PLFC");
12527 write_met_bin_2d(out, met, met->pel, "PEL");
12528 write_met_bin_2d(out, met, met->cape, "CAPE");
12529 write_met_bin_2d(out, met, met->cin, "CIN");
12530 write_met_bin_2d(out, met, met->o3c, "O3C");
12531
12532 /* Write level data... */
12533 write_met_bin_3d(out, ctl, met, met->z, "Z",
12534 ctl->met_comp_prec[0], ctl->met_comp_tol[0]);
12535 write_met_bin_3d(out, ctl, met, met->t, "T",
12536 ctl->met_comp_prec[1], ctl->met_comp_tol[1]);
12537 write_met_bin_3d(out, ctl, met, met->u, "U",
12538 ctl->met_comp_prec[2], ctl->met_comp_tol[2]);
12539 write_met_bin_3d(out, ctl, met, met->v, "V",
12540 ctl->met_comp_prec[3], ctl->met_comp_tol[3]);
12541 write_met_bin_3d(out, ctl, met, met->w, "W",
12542 ctl->met_comp_prec[4], ctl->met_comp_tol[4]);
12543 write_met_bin_3d(out, ctl, met, met->pv, "PV",
12544 ctl->met_comp_prec[5], ctl->met_comp_tol[5]);
12545 write_met_bin_3d(out, ctl, met, met->h2o, "H2O",
12546 ctl->met_comp_prec[6], ctl->met_comp_tol[6]);
12547 write_met_bin_3d(out, ctl, met, met->o3, "O3",
12548 ctl->met_comp_prec[7], ctl->met_comp_tol[7]);
12549 write_met_bin_3d(out, ctl, met, met->lwc, "LWC",
12550 ctl->met_comp_prec[8], ctl->met_comp_tol[8]);
12551 write_met_bin_3d(out, ctl, met, met->rwc, "RWC",
12552 ctl->met_comp_prec[9], ctl->met_comp_tol[9]);
12553 write_met_bin_3d(out, ctl, met, met->iwc, "IWC",
12554 ctl->met_comp_prec[10], ctl->met_comp_tol[10]);
12555 write_met_bin_3d(out, ctl, met, met->swc, "SWC",
12556 ctl->met_comp_prec[11], ctl->met_comp_tol[11]);
12557 write_met_bin_3d(out, ctl, met, met->cc, "CC",
12558 ctl->met_comp_prec[12], ctl->met_comp_tol[12]);
12559 if (METVAR != 13)
12560 ERRMSG("Number of meteo variables doesn't match!");
12561
12562 /* Write final flag... */
12563 int final = 999;
12564 FWRITE(&final, int,
12565 1,
12566 out);
12567
12568 /* Close file... */
12569 fclose(out);
12570}
12571
12572/*****************************************************************************/
12573
12575 FILE *out,
12576 met_t *met,
12577 float var[EX][EY],
12578 const char *varname) {
12579
12580 float *help;
12581
12582 /* Allocate... */
12583 ALLOC(help, float,
12584 EX * EY);
12585
12586 /* Copy data... */
12587 for (int ix = 0; ix < met->nx; ix++)
12588 for (int iy = 0; iy < met->ny; iy++)
12589 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
12590
12591 /* Write uncompressed data... */
12592 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
12593 FWRITE(help, float,
12594 (size_t) (met->nx * met->ny),
12595 out);
12596
12597 /* Free... */
12598 free(help);
12599}
12600
12601/*****************************************************************************/
12602
12604 FILE *out,
12605 const ctl_t *ctl,
12606 met_t *met,
12607 float var[EX][EY][EP],
12608 const char *varname,
12609 const int precision,
12610 const double tolerance) {
12611
12612 float *help;
12613
12614 /* Allocate... */
12615 ALLOC(help, float,
12616 EX * EY * EP);
12617
12618 /* Copy data... */
12619#pragma omp parallel for default(shared) collapse(2)
12620 for (int ix = 0; ix < met->nx; ix++)
12621 for (int iy = 0; iy < met->ny; iy++)
12622 for (int ip = 0; ip < met->np; ip++)
12623 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
12624
12625 /* Write uncompressed data... */
12626 if (ctl->met_type == 1) {
12627 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
12628 FWRITE(help, float,
12629 (size_t) (met->nx * met->ny * met->np),
12630 out);
12631 }
12632
12633 /* Write packed data... */
12634 else if (ctl->met_type == 2)
12635 compress_pck(varname, help, (size_t) (met->ny * met->nx),
12636 (size_t) met->np, 0, out);
12637
12638 /* Write ZFP data... */
12639#ifdef ZFP
12640 else if (ctl->met_type == 3) {
12641 FWRITE(&precision, int,
12642 1,
12643 out);
12644 FWRITE(&tolerance, double,
12645 1,
12646 out);
12647 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
12648 tolerance, 0, out);
12649 }
12650#endif
12651
12652 /* Write zstd data... */
12653#ifdef ZSTD
12654 else if (ctl->met_type == 4)
12655 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
12656 ctl->met_zstd_level, out);
12657#endif
12658
12659 /* Write cmultiscale data... */
12660#ifdef CMS
12661 else if (ctl->met_type == 5) {
12662 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
12663 (size_t) met->np, met->p, 0, out);
12664 }
12665#endif
12666
12667 /* Write SZ3 data... */
12668#ifdef SZ3
12669 else if (ctl->met_type == 7) {
12670 FWRITE(&precision, int,
12671 1,
12672 out);
12673 FWRITE(&tolerance, double,
12674 1,
12675 out);
12676 compress_sz3(varname, help, met->np, met->ny, met->nx, precision,
12677 tolerance, 0, out);
12678 }
12679#endif
12680
12681 /* Unknown method... */
12682 else {
12683 ERRMSG("MET_TYPE not supported!");
12684 LOG(3, "%d %g", precision, tolerance);
12685 }
12686
12687 /* Free... */
12688 free(help);
12689}
12690
12691/*****************************************************************************/
12692
12694 const char *filename,
12695 const ctl_t *ctl,
12696 met_t *met) {
12697
12698 /* Create file... */
12699 int ncid, varid;
12700 size_t start[4], count[4];
12701 NC(nc_create(filename, NC_NETCDF4, &ncid));
12702
12703 /* Define dimensions... */
12704 int tid, lonid, latid, levid;
12705 NC(nc_def_dim(ncid, "time", 1, &tid));
12706 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
12707 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
12708 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
12709
12710 /* Define grid... */
12711 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
12712 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12713 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
12714 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
12715 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
12716
12717 /* Define surface variables... */
12718 int dimid2[2] = { latid, lonid };
12719 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
12720 ctl->met_nc_level, 0);
12721 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
12722 ctl->met_nc_level, 0);
12723 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
12724 ctl->met_nc_level, 0);
12725 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
12726 "m s**-1", ctl->met_nc_level, 0);
12727 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
12728 "m s**-1", ctl->met_nc_level, 0);
12729 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
12730 "Instantaneous eastward turbulent surface stress", "N m**-2",
12731 ctl->met_nc_level, 0);
12732 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
12733 "Instantaneous northward turbulent surface stress", "N m**-2",
12734 ctl->met_nc_level, 0);
12735 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
12736 "Instantaneous surface sensible heat flux", "W m**-1",
12737 ctl->met_nc_level, 0);
12738 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
12739 ctl->met_nc_level, 0);
12740 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
12741 ctl->met_nc_level, 0);
12742 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
12743 ctl->met_nc_level, 0);
12744 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
12745 ctl->met_nc_level, 0);
12746 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
12747 ctl->met_nc_level, 0);
12748 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
12749 ctl->met_nc_level, 0);
12750 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
12751 ctl->met_nc_level, 0);
12752 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
12753 ctl->met_nc_level, 0);
12754 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
12755 ctl->met_nc_level, 0);
12756 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water",
12757 "kg m**2", ctl->met_nc_level, 0);
12758 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
12759 "Pressure at lifted condensation level (LCL)", "Pa",
12760 ctl->met_nc_level, 0);
12761 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
12762 "Pressure at level of free convection (LFC)", "Pa",
12763 ctl->met_nc_level, 0);
12764 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2,
12765 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
12766 0);
12767 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
12768 "Convective available potential energy", "J kg**-1",
12769 ctl->met_nc_level, 0);
12770 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition",
12771 "J kg**-1", ctl->met_nc_level, 0);
12772 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
12773 ctl->met_nc_level, 0);
12774
12775 /* Define level data... */
12776 int dimid3[3] = { levid, latid, lonid };
12777 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
12778 ctl->met_nc_level, ctl->met_nc_quant);
12779 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
12780 ctl->met_nc_level, ctl->met_nc_quant);
12781 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
12782 ctl->met_nc_level, ctl->met_nc_quant);
12783 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
12784 ctl->met_nc_level, ctl->met_nc_quant);
12785 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
12786 ctl->met_nc_level, ctl->met_nc_quant);
12787 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
12788 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12789 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
12790 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12791 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
12792 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12793 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
12794 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12795 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
12796 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12797 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
12798 ctl->met_nc_level, ctl->met_nc_quant);
12799
12800 /* End definitions... */
12801 NC(nc_enddef(ncid));
12802
12803 /* Write grid data... */
12804 NC_PUT_DOUBLE("time", &met->time, 0);
12805 NC_PUT_DOUBLE("lon", met->lon, 0);
12806 NC_PUT_DOUBLE("lat", met->lat, 0);
12807 double phelp[EP];
12808 for (int ip = 0; ip < met->np; ip++)
12809 phelp[ip] = 100. * met->p[ip];
12810 NC_PUT_DOUBLE("lev", phelp, 0);
12811
12812 /* Write surface data... */
12813 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
12814 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
12815 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
12816 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
12817 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
12818 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
12819 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
12820 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
12821 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
12822 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
12823 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
12824 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
12825 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
12826 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
12827 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
12828 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
12829 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
12830 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
12831 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
12832 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
12833 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
12834 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
12835 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
12836 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
12837
12838 /* Write level data... */
12839 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
12840 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
12841 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
12842 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
12843 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
12844 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
12845 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
12846 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
12847 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
12848 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
12849 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
12850
12851 /* Close file... */
12852 NC(nc_close(ncid));
12853}
12854
12855/*****************************************************************************/
12856
12858 const int ncid,
12859 const char *varname,
12860 met_t *met,
12861 float var[EX][EY],
12862 const float scl) {
12863
12864 int varid;
12865 size_t start[4], count[4];
12866
12867 /* Allocate... */
12868 float *help;
12869 ALLOC(help, float,
12870 EX * EY);
12871
12872 /* Copy data... */
12873 for (int ix = 0; ix < met->nx; ix++)
12874 for (int iy = 0; iy < met->ny; iy++)
12875 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
12876
12877 /* Write data... */
12878 NC_PUT_FLOAT(varname, help, 0);
12879
12880 /* Free... */
12881 free(help);
12882}
12883
12884/*****************************************************************************/
12885
12887 const int ncid,
12888 const char *varname,
12889 met_t *met,
12890 float var[EX][EY][EP],
12891 const float scl) {
12892
12893 int varid;
12894 size_t start[4], count[4];
12895
12896 /* Allocate... */
12897 float *help;
12898 ALLOC(help, float,
12899 EX * EY * EP);
12900
12901 /* Copy data... */
12902 for (int ix = 0; ix < met->nx; ix++)
12903 for (int iy = 0; iy < met->ny; iy++)
12904 for (int ip = 0; ip < met->np; ip++)
12905 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
12906
12907 /* Write data... */
12908 NC_PUT_FLOAT(varname, help, 0);
12909
12910 /* Free... */
12911 free(help);
12912}
12913
12914/*****************************************************************************/
12915
12917 const char *filename,
12918 const ctl_t *ctl,
12919 met_t *met0,
12920 met_t *met1,
12921 const atm_t *atm,
12922 const double t) {
12923
12924 static FILE *out;
12925
12926 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
12927 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
12928
12929 static int nobs, *obscount, ip, okay;
12930
12931 /* Set timer... */
12932 SELECT_TIMER("WRITE_PROF", "OUTPUT");
12933
12934 /* Init... */
12935 if (t == ctl->t_start) {
12936
12937 /* Check quantity index for mass... */
12938 if (ctl->qnt_m < 0)
12939 ERRMSG("Need quantity mass!");
12940
12941 /* Check molar mass... */
12942 if (ctl->molmass <= 0)
12943 ERRMSG("Specify molar mass!");
12944
12945 /* Allocate... */
12946 ALLOC(lon, double,
12947 ctl->prof_nx);
12948 ALLOC(lat, double,
12949 ctl->prof_ny);
12950 ALLOC(area, double,
12951 ctl->prof_ny);
12952 ALLOC(z, double,
12953 ctl->prof_nz);
12954 ALLOC(press, double,
12955 ctl->prof_nz);
12956 ALLOC(rt, double,
12957 NOBS);
12958 ALLOC(rz, double,
12959 NOBS);
12960 ALLOC(rlon, double,
12961 NOBS);
12962 ALLOC(rlat, double,
12963 NOBS);
12964 ALLOC(robs, double,
12965 NOBS);
12966
12967 /* Read observation data... */
12968 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12969
12970 /* Create new output file... */
12971 LOG(1, "Write profile data: %s", filename);
12972 if (!(out = fopen(filename, "w")))
12973 ERRMSG("Cannot create file!");
12974
12975 /* Write header... */
12976 fprintf(out,
12977 "# $1 = time [s]\n"
12978 "# $2 = altitude [km]\n"
12979 "# $3 = longitude [deg]\n"
12980 "# $4 = latitude [deg]\n"
12981 "# $5 = pressure [hPa]\n"
12982 "# $6 = temperature [K]\n"
12983 "# $7 = volume mixing ratio [ppv]\n"
12984 "# $8 = H2O volume mixing ratio [ppv]\n"
12985 "# $9 = O3 volume mixing ratio [ppv]\n"
12986 "# $10 = observed BT index [K]\n"
12987 "# $11 = number of observations\n");
12988
12989 /* Set grid box size... */
12990 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
12991 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
12992 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
12993
12994 /* Set vertical coordinates... */
12995 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12996 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
12997 press[iz] = P(z[iz]);
12998 }
12999
13000 /* Set horizontal coordinates... */
13001 for (int ix = 0; ix < ctl->prof_nx; ix++)
13002 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
13003 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13004 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
13005 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
13006 }
13007 }
13008
13009 /* Set time interval... */
13010 const double t0 = t - 0.5 * ctl->dt_mod;
13011 const double t1 = t + 0.5 * ctl->dt_mod;
13012
13013 /* Allocate... */
13014 ALLOC(mass, double,
13015 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
13016 ALLOC(obsmean, double,
13017 ctl->prof_nx * ctl->prof_ny);
13018 ALLOC(obscount, int,
13019 ctl->prof_nx * ctl->prof_ny);
13020
13021 /* Loop over observations... */
13022 for (int i = 0; i < nobs; i++) {
13023
13024 /* Check time... */
13025 if (rt[i] < t0)
13026 continue;
13027 else if (rt[i] >= t1)
13028 break;
13029
13030 /* Check observation data... */
13031 if (!isfinite(robs[i]))
13032 continue;
13033
13034 /* Calculate indices... */
13035 const int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
13036 const int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
13037
13038 /* Check indices... */
13039 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
13040 continue;
13041
13042 /* Get mean observation index... */
13043 const int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
13044 obsmean[idx] += robs[i];
13045 obscount[idx]++;
13046 }
13047
13048 /* Analyze model data... */
13049 for (ip = 0; ip < atm->np; ip++) {
13050
13051 /* Check time... */
13052 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13053 continue;
13054
13055 /* Get indices... */
13056 const int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
13057 const int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
13058 const int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
13059
13060 /* Check indices... */
13061 if (ix < 0 || ix >= ctl->prof_nx ||
13062 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
13063 continue;
13064
13065 /* Get total mass in grid cell... */
13066 const int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13067 mass[idx] += atm->q[ctl->qnt_m][ip];
13068 }
13069
13070 /* Extract profiles... */
13071 for (int ix = 0; ix < ctl->prof_nx; ix++)
13072 for (int iy = 0; iy < ctl->prof_ny; iy++) {
13073 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
13074 if (obscount[idx2] > 0) {
13075
13076 /* Check profile... */
13077 okay = 0;
13078 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13079 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13080 if (mass[idx3] > 0) {
13081 okay = 1;
13082 break;
13083 }
13084 }
13085 if (!okay)
13086 continue;
13087
13088 /* Write output... */
13089 fprintf(out, "\n");
13090
13091 /* Loop over altitudes... */
13092 for (int iz = 0; iz < ctl->prof_nz; iz++) {
13093
13094 /* Get temperature, water vapor, and ozone... */
13096 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
13097 lon[ix], lat[iy], &temp, ci, cw, 1);
13098 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
13099 lon[ix], lat[iy], &h2o, ci, cw, 0);
13100 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
13101 lon[ix], lat[iy], &o3, ci, cw, 0);
13102
13103 /* Calculate volume mixing ratio... */
13104 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
13105 vmr = MA / ctl->molmass * mass[idx3]
13106 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
13107
13108 /* Write output... */
13109 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
13110 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
13111 obsmean[idx2] / obscount[idx2], obscount[idx2]);
13112 }
13113 }
13114 }
13115
13116 /* Free... */
13117 free(mass);
13118 free(obsmean);
13119 free(obscount);
13120
13121 /* Finalize... */
13122 if (t == ctl->t_stop) {
13123
13124 /* Close output file... */
13125 fclose(out);
13126
13127 /* Free... */
13128 free(lon);
13129 free(lat);
13130 free(area);
13131 free(z);
13132 free(press);
13133 free(rt);
13134 free(rz);
13135 free(rlon);
13136 free(rlat);
13137 free(robs);
13138 }
13139}
13140
13141/*****************************************************************************/
13142
13144 const char *filename,
13145 const ctl_t *ctl,
13146 met_t *met0,
13147 met_t *met1,
13148 const atm_t *atm,
13149 const double t) {
13150
13151 static FILE *out;
13152
13153 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
13154 kw[EP];
13155
13156 static int nobs, nk;
13157
13158 /* Set timer... */
13159 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT");
13160
13161 /* Init... */
13162 if (t == ctl->t_start) {
13163
13164 /* Allocate... */
13165 ALLOC(rt, double,
13166 NOBS);
13167 ALLOC(rz, double,
13168 NOBS);
13169 ALLOC(rlon, double,
13170 NOBS);
13171 ALLOC(rlat, double,
13172 NOBS);
13173 ALLOC(robs, double,
13174 NOBS);
13175
13176 /* Read observation data... */
13177 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
13178
13179 /* Read kernel data... */
13180 if (ctl->sample_kernel[0] != '-')
13181 read_kernel(ctl->sample_kernel, kz, kw, &nk);
13182
13183 /* Create output file... */
13184 LOG(1, "Write sample data: %s", filename);
13185 if (!(out = fopen(filename, "w")))
13186 ERRMSG("Cannot create file!");
13187
13188 /* Write header... */
13189 fprintf(out,
13190 "# $1 = time [s]\n"
13191 "# $2 = altitude [km]\n"
13192 "# $3 = longitude [deg]\n"
13193 "# $4 = latitude [deg]\n"
13194 "# $5 = surface area [km^2]\n"
13195 "# $6 = layer depth [km]\n"
13196 "# $7 = number of particles [1]\n"
13197 "# $8 = column density [kg/m^2]\n"
13198 "# $9 = volume mixing ratio [ppv]\n"
13199 "# $10 = observed BT index [K]\n\n");
13200
13201 /* Set latitude range, squared radius, and area... */
13202 dlat = DY2DEG(ctl->sample_dx);
13203 rmax2 = SQR(ctl->sample_dx);
13204 area = M_PI * rmax2;
13205 }
13206
13207 /* Set time interval for output... */
13208 const double t0 = t - 0.5 * ctl->dt_mod;
13209 const double t1 = t + 0.5 * ctl->dt_mod;
13210
13211 /* Loop over observations... */
13212 for (int i = 0; i < nobs; i++) {
13213
13214 /* Check time... */
13215 if (rt[i] < t0)
13216 continue;
13217 else if (rt[i] >= t1)
13218 break;
13219
13220 /* Calculate Cartesian coordinates... */
13221 double x0[3];
13222 geo2cart(0, rlon[i], rlat[i], x0);
13223
13224 /* Set pressure range... */
13225 const double rp = P(rz[i]);
13226 const double ptop = P(rz[i] + ctl->sample_dz);
13227 const double pbot = P(rz[i] - ctl->sample_dz);
13228
13229 /* Init... */
13230 double mass = 0;
13231 int np = 0;
13232
13233 /* Loop over air parcels... */
13234 //#pragma omp parallel for default(shared) reduction(+:mass,np)
13235 for (int ip = 0; ip < atm->np; ip++) {
13236
13237 /* Check time... */
13238 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13239 continue;
13240
13241 /* Check latitude... */
13242 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
13243 continue;
13244
13245 /* Check horizontal distance... */
13246 double x1[3];
13247 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13248 if (DIST2(x0, x1) > rmax2)
13249 continue;
13250
13251 /* Check pressure... */
13252 if (ctl->sample_dz > 0)
13253 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
13254 continue;
13255
13256 /* Add mass... */
13257 if (ctl->qnt_m >= 0)
13258 mass +=
13259 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
13260 np++;
13261 }
13262
13263 /* Calculate column density... */
13264 const double cd = mass / (1e6 * area);
13265
13266 /* Calculate volume mixing ratio... */
13267 double vmr = 0;
13268 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
13269 if (mass > 0) {
13270
13271 /* Get temperature... */
13272 double temp;
13274 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
13275 rlon[i], rlat[i], &temp, ci, cw, 1);
13276
13277 /* Calculate volume mixing ratio... */
13278 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
13279 }
13280 } else
13281 vmr = NAN;
13282
13283 /* Write output... */
13284 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
13285 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
13286 }
13287
13288 /* Finalize...... */
13289 if (t == ctl->t_stop) {
13290
13291 /* Close output file... */
13292 fclose(out);
13293
13294 /* Free... */
13295 free(rt);
13296 free(rz);
13297 free(rlon);
13298 free(rlat);
13299 free(robs);
13300 }
13301}
13302
13303/*****************************************************************************/
13304
13306 const char *filename,
13307 const ctl_t *ctl,
13308 atm_t *atm,
13309 const double t) {
13310
13311 static FILE *out;
13312
13313 static double rmax2, x0[3], x1[3];
13314
13315 /* Set timer... */
13316 SELECT_TIMER("WRITE_STATION", "OUTPUT");
13317
13318 /* Init... */
13319 if (t == ctl->t_start) {
13320
13321 /* Write info... */
13322 LOG(1, "Write station data: %s", filename);
13323
13324 /* Create new file... */
13325 if (!(out = fopen(filename, "w")))
13326 ERRMSG("Cannot create file!");
13327
13328 /* Write header... */
13329 fprintf(out,
13330 "# $1 = time [s]\n"
13331 "# $2 = altitude [km]\n"
13332 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
13333 for (int iq = 0; iq < ctl->nq; iq++)
13334 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
13335 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
13336 fprintf(out, "\n");
13337
13338 /* Set geolocation and search radius... */
13339 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
13340 rmax2 = SQR(ctl->stat_r);
13341 }
13342
13343 /* Set time interval for output... */
13344 const double t0 = t - 0.5 * ctl->dt_mod;
13345 const double t1 = t + 0.5 * ctl->dt_mod;
13346
13347 /* Loop over air parcels... */
13348 for (int ip = 0; ip < atm->np; ip++) {
13349
13350 /* Check time... */
13351 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13352 continue;
13353
13354 /* Check time range for station output... */
13355 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
13356 continue;
13357
13358 /* Check station flag... */
13359 if (ctl->qnt_stat >= 0)
13360 if ((int) atm->q[ctl->qnt_stat][ip])
13361 continue;
13362
13363 /* Get Cartesian coordinates... */
13364 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
13365
13366 /* Check horizontal distance... */
13367 if (DIST2(x0, x1) > rmax2)
13368 continue;
13369
13370 /* Set station flag... */
13371 if (ctl->qnt_stat >= 0)
13372 atm->q[ctl->qnt_stat][ip] = 1;
13373
13374 /* Write data... */
13375 fprintf(out, "%.2f %g %g %g",
13376 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
13377 for (int iq = 0; iq < ctl->nq; iq++) {
13378 fprintf(out, " ");
13379 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
13380 }
13381 fprintf(out, "\n");
13382 }
13383
13384 /* Close file... */
13385 if (t == ctl->t_stop)
13386 fclose(out);
13387}
13388
13389/*****************************************************************************/
13390
13392 const char *filename,
13393 const ctl_t *ctl,
13394 const atm_t *atm,
13395 const double t) {
13396
13397 FILE *out;
13398
13399 /* Set timer... */
13400 SELECT_TIMER("WRITE_VTK", "OUTPUT");
13401
13402 /* Write info... */
13403 LOG(1, "Write VTK data: %s", filename);
13404
13405 /* Set time interval for output... */
13406 const double t0 = t - 0.5 * ctl->dt_mod;
13407 const double t1 = t + 0.5 * ctl->dt_mod;
13408
13409 /* Create file... */
13410 if (!(out = fopen(filename, "w")))
13411 ERRMSG("Cannot create file!");
13412
13413 /* Count data points... */
13414 int np = 0;
13415 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13416 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13417 continue;
13418 np++;
13419 }
13420
13421 /* Write header... */
13422 fprintf(out,
13423 "# vtk DataFile Version 3.0\n"
13424 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
13425
13426 /* Write point coordinates... */
13427 fprintf(out, "POINTS %d float\n", np);
13428 if (ctl->vtk_sphere) {
13429 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13430 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13431 continue;
13432 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
13433 + ctl->vtk_offset) / RE;
13434 const double coslat = cos(DEG2RAD(atm->lat[ip]));
13435 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
13436 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
13437 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
13438 fprintf(out, "%g %g %g\n", x, y, z);
13439 }
13440 } else
13441 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13442 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13443 continue;
13444 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
13445 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
13446 }
13447
13448 /* Write point data... */
13449 fprintf(out, "POINT_DATA %d\n", np);
13450 for (int iq = 0; iq < ctl->nq; iq++) {
13451 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
13452 ctl->qnt_name[iq]);
13453 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13454 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13455 continue;
13456 fprintf(out, "%g\n", atm->q[iq][ip]);
13457 }
13458 }
13459
13460 /* Close file... */
13461 fclose(out);
13462}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:8125
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:5144
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:6781
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:8085
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:11458
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:8755
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:12857
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:10497
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:12603
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:10842
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:2901
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:4860
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:4118
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:7213
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:7924
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:3504
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:11015
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:2359
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:9017
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:7180
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:10105
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:7981
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:10670
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:10886
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:3349
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:2862
void get_tropo(const int met_tropo, ctl_t *ctl, clim_t *clim, met_t *met, const double *lons, const int nx, const double *lats, const int ny, double *pt, double *zt, double *tt, double *qt, double *o3t, double *ps, double *zs)
Calculate tropopause data.
Definition: mptrac.c:2059
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:8558
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:9751
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:7332
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:10242
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:6517
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:4907
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:11940
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:4225
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:4297
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:7304
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:9709
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:10914
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:7674
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:2798
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:3942
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:2647
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:12228
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:6669
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:11116
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:5352
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:2417
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:1911
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:5009
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:6976
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:11048
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:3187
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:7386
void read_met_nc_grid_dd_naive(dd_t *dd, const ctl_t *ctl, met_t *met, const int ncid)
Read meteorological grid data from a NetCDF file and set up subdomain decomposition with halos.
Definition: mptrac.c:9876
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:4728
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:9836
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:11147
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:11273
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:2301
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:3391
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:7485
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:3091
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:10943
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:3064
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:4534
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:5230
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:4822
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:11095
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:2479
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:7703
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:2828
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:11215
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:12916
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:5442
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:11250
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:12693
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:4592
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:5371
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:6725
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:6885
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:10468
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:8420
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:4623
void get_met_help(const ctl_t *ctl, const double t, const int direct, const char *metbase, const double dt_met, char *filename)
Generates a formatted filename for meteorological data files based on the input parameters.
Definition: mptrac.c:1968
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:13305
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:1881
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:2129
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:2446
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:4483
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:2881
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:12574
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:10362
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:7064
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:2035
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:3543
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:4757
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:2570
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:7526
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:11405
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:3745
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:7120
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:6408
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:13391
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:4938
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:5502
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:5197
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:10303
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:3860
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:12332
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:7000
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:3620
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:12886
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:4012
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:4399
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:1950
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:8253
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:2603
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:7022
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:2102
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:13143
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:12037
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:3797
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:12462
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:11355
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:7809
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:6841
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:2629
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:11665
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:11616
MPTRAC library declarations.
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1436
int dd_init(ctl_t *ctl, dd_t *dd, atm_t *atm)
Initializes domain decomposition for parallel processing.
void compress_zstd(const char *varname, float *array, const size_t n, const int decompress, const int level, FILE *inout)
Compresses or decompresses a float array using Zstandard (ZSTD).
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:348
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:314
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1908
#define DD_NPOLE
Constant indicating the North pole [-].
Definition: mptrac.h:428
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:508
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1463
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:289
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:249
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:284
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:294
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:353
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:373
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:868
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1568
#define H0
Scale height [km].
Definition: mptrac.h:269
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1416
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1203
void dd_sort(const ctl_t *ctl, met_t *met0, atm_t *atm, dd_t *dd, int *nparticles, int *rank)
Sort particles according to box index and target rank for neighbours.
#define DD_SPOLE
Constant indicating the South pole [-].
Definition: mptrac.h:433
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:1041
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1217
#define SELECT_TIMER(id, group)
Select and start a timer with specific attributes.
Definition: mptrac.h:2189
#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:805
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:749
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:309
#define KARMAN
Karman's constant.
Definition: mptrac.h:279
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:883
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:1188
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2115
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1377
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:343
void dd_particles2atm(atm_t *atm, particle_t *particles, ctl_t *ctl, int *nparticles, cache_t *cache)
Converts particle data to atmospheric data.
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1733
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:914
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:378
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:383
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:489
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:1952
#define codes_handle
Placeholder when ECCODES is not available.
Definition: mptrac.h:240
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1493
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:274
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:264
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:398
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:363
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:848
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:664
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:600
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:338
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:259
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1541
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1833
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:319
int dd_is_periodic_longitude(met_t *met, int nx_glob)
Check whether the longitude grid is periodic (global coverage).
int read_met_grib(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a grib file and processes it.
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1712
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1809
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1883
void dd_get_rect_neighbour(const ctl_t ctl, dd_t *dd)
Determines rectangular neighbouring ranks for MPI processes.
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1983
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1862
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:701
void dd_atm2particles(atm_t *atm, particle_t *particles, ctl_t *ctl, int *nparticles, cache_t *cache, int rank)
Extracts particles from an atmospheric state and prepares them for inter-domain transfer.
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:2082
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:2002
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1645
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:987
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:466
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:1689
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:413
#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:782
int dd_calc_subdomain_from_coords(double lon, double lat, met_t *met, ctl_t *ctl, int mpi_size, int nx_glob, int ny_glob)
Computes the destination subdomain (MPI rank) for a particle based on its geographic coordinates.
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:617
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:299
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1746
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1585
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:358
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2159
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:897
void dd_communicate_particles(particle_t *particles, int *nparticles, MPI_Datatype MPI_Particle, int *neighbours, int nneighbours, ctl_t ctl)
Communicates particles between MPI processes.
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1615
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1354
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:388
void module_dd(ctl_t *ctl, atm_t *atm, cache_t *cache, dd_t *dd, met_t **met)
Manages domain decomposition and particle communication in parallel processing.
void dd_sort_help(double *a, dd_t *dd, const int np)
Reorder an array according to a permutation vector.
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:2045
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1246
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1784
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:533
void dd_assign_rect_subdomains_atm(atm_t *atm, ctl_t *ctl, dd_t *dd, int init)
Assign atmospheric particles to rectangular subdomains.
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:368
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1276
#define MPI_Datatype
Placeholder when MPI is not available.
Definition: mptrac.h:195
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:333
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1517
#define DD_NPART
Maximum number of particles to send and recieve in domain decomposition.
Definition: mptrac.h:418
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1670
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:393
void read_met_grib_grid(codes_handle **handles, int count_handles, met_t *met)
Reads global meteorological information from a grib file.
void compress_sz3(const char *varname, float *array, const int nx, const int ny, const int nz, const int precision, const double tolerance, const int decompress, FILE *inout)
Compresses or decompresses a 3-D float array using the SZ3 library.
void dd_register_MPI_type_particle(MPI_Datatype *MPI_Particle)
Registers a custom MPI datatype for particle structures.
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1330
#define ECC(cmd)
Execute an ECCODES command and check for errors.
Definition: mptrac.h:763
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:1060
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:733
#define NC_INQ_DIM(dimname, ptr, min, max, check)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1306
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:579
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:254
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:403
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:682
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1087
#define DD_NNMAX
Maximum number of neighbours to communicate with in domain decomposition.
Definition: mptrac.h:423
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:830
Air parcel data.
Definition: mptrac.h:3257
double time[NP]
Time [s].
Definition: mptrac.h:3263
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3272
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3269
int np
Number of air parcels.
Definition: mptrac.h:3260
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3275
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3266
Cache data structure.
Definition: mptrac.h:3312
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3333
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3321
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3324
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3318
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3330
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3327
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3315
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3344
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3350
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3359
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3380
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3356
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3374
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3377
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3371
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3365
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3386
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3389
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3368
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3383
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3362
int np
Number of pressure levels.
Definition: mptrac.h:3347
int no3c
Number of total ozone columns.
Definition: mptrac.h:3353
Climatological data.
Definition: mptrac.h:3452
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3494
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3470
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3482
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3473
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3455
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3500
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3488
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3491
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3485
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3464
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3479
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3458
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3476
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3467
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3461
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3497
Climatological data in the form of time series.
Definition: mptrac.h:3400
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3409
double time[CTS]
Time [s].
Definition: mptrac.h:3406
int ntime
Number of timesteps.
Definition: mptrac.h:3403
Climatological data in the form of zonal means.
Definition: mptrac.h:3420
double time[CT]
Time [s].
Definition: mptrac.h:3432
int np
Number of pressure levels.
Definition: mptrac.h:3429
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3438
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3441
int ntime
Number of timesteps.
Definition: mptrac.h:3423
int nlat
Number of latitudes.
Definition: mptrac.h:3426
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3435
Control parameters.
Definition: mptrac.h:2203
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3118
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2315
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3079
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3046
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2471
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2967
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2567
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2348
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3055
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2826
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2294
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2495
int dd_halos_size
Domain decomposition size of halos given in grid-points.
Definition: mptrac.h:3245
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:3007
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2889
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2913
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2222
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2234
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2504
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2243
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2327
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3049
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2336
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2865
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2814
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3070
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2303
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3196
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2874
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2725
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2886
double stat_r
Search radius around station [km].
Definition: mptrac.h:3202
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2961
int met_zstd_level
ZSTD compression level (from -5 to 22).
Definition: mptrac.h:2576
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3073
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3226
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2910
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2693
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2324
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2928
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2778
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2483
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2615
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2402
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3145
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3121
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2531
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2732
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2489
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2645
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2712
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2366
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2438
char species[LEN]
Species.
Definition: mptrac.h:2823
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3064
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3076
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2760
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2690
double met_comp_tol[METVAR]
Compression tolerance for SZ3 or ZFP.
Definition: mptrac.h:2582
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2318
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2769
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3106
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3124
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3020
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2787
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3136
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2249
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2393
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2618
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2345
int qnt_Acs137
Quantity array index for radioactive activity of Cs-137.
Definition: mptrac.h:2516
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3127
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2372
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2709
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3181
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2432
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2550
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2847
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2931
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2681
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3097
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2606
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2754
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2237
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2270
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2414
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2802
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3208
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3040
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2751
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3142
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3067
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2276
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2937
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3112
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2399
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2919
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2820
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2384
int radio_decay
Switch for radioactive decay module (0=off, 1=on).
Definition: mptrac.h:2955
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2678
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2651
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2246
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2742
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3148
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2729
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2808
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2252
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3151
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3043
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2687
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3052
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2648
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2922
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2766
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2630
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2633
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3094
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2609
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3154
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2309
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2793
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2703
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3160
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2231
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2700
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2240
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2718
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2877
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2441
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2369
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3061
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3205
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2940
int dd
Domain decomposition (0=no, 1=yes, with 2x2 if not specified).
Definition: mptrac.h:3233
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2850
int qnt_eta
Quantity array index for eta vertical coordinate.
Definition: mptrac.h:2426
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2835
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:2979
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2883
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2390
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3025
int met_cms_nd0x
cmultiscale number of cells of coarsest grid in x-direction.
Definition: mptrac.h:2591
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2669
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2949
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3037
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2988
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2267
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2258
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2468
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3214
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2537
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2784
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3184
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2360
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3091
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2564
int met_comp_prec[METVAR]
Compression precision for SZ3 or ZFP.
Definition: mptrac.h:2579
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2288
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2408
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2636
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2799
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2696
int met_dx
Stride for longitudes.
Definition: mptrac.h:2639
int qnt_destination
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2528
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2898
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2553
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2420
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2844
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2952
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2540
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2745
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2456
int qnt_eta_dot
Quantity array index for velocity of eta vertical coordinate.
Definition: mptrac.h:2429
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2450
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2291
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3223
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2306
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2387
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2796
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2715
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2363
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2219
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2474
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2666
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2934
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2312
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3169
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2411
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2300
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3190
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2832
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3034
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3109
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2624
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2255
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2600
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3130
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2498
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2492
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2213
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:3004
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2901
int nens
Number of ensembles.
Definition: mptrac.h:3082
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2279
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2339
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2735
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3157
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2672
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2297
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3013
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2946
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2417
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2775
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3085
int qnt_Ai131
Quantity array index for radioactive activity of I-131.
Definition: mptrac.h:2519
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2958
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:2557
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3058
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2435
int qnt_Apb210
Quantity array index for radioactive activity of Pb-210.
Definition: mptrac.h:2510
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3199
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2477
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2976
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3133
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2501
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2462
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2657
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2772
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2547
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2811
int dd_nbr_neighbours
Domain decomposition number of neighbours to communicate with.
Definition: mptrac.h:3242
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2603
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2907
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2351
int qnt_zeta_dot
Quantity array index for velocity of zeta vertical coordinate.
Definition: mptrac.h:2423
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2790
int met_cms_nd0y
cmultiscale number of cells of coarsest grid in y-direction.
Definition: mptrac.h:2594
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2880
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2357
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2805
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2892
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2856
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2465
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2453
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3115
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2841
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2264
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3088
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3178
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3016
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2684
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2904
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:3010
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2868
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3175
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2585
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2994
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2654
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3163
int qnt_Axe133
Quantity array index for radioactive activity of Xe-133.
Definition: mptrac.h:2522
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2916
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2333
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2381
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2396
int qnt_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2525
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2675
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3172
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2354
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2997
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3166
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2627
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2573
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2943
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2486
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3031
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2985
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2925
int qnt_Abe7
Quantity array index for radioactive activity of Be-7.
Definition: mptrac.h:2513
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2859
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2621
int met_cms_zstd
cmultiscale ZSTD compression (0=off, 1=on).
Definition: mptrac.h:2588
int met_cms_maxlev
cmultiscale maximum refinement level.
Definition: mptrac.h:2597
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3103
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3211
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2991
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2282
int met_np
Number of target pressure levels.
Definition: mptrac.h:2660
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2228
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2570
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2871
int qnt_Arn222
Quantity array index for radioactive activity of Rn-222.
Definition: mptrac.h:2507
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2378
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3220
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2862
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2612
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2973
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2748
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2781
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2444
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev,...
Definition: mptrac.h:2739
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2375
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2480
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2273
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2895
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3028
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2838
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2982
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2405
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2261
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2970
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2964
int met_dy
Stride for latitudes.
Definition: mptrac.h:2642
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2459
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2763
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2817
int dd_subdomains_zonal
Domain decomposition zonal subdomain number.
Definition: mptrac.h:3236
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2225
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2706
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2321
double t_start
Start time of simulation [s].
Definition: mptrac.h:2534
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2216
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2663
int nq
Number of quantities.
Definition: mptrac.h:2210
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2829
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3187
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3217
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3193
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2757
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3139
int dd_subdomains_meridional
Domain decomposition meridional subdomain number.
Definition: mptrac.h:3239
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2285
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:2561
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2330
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2342
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3100
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2447
Domain decomposition data structure.
Definition: mptrac.h:3685
size_t halo_bnd_count[4]
Hyperslab of boundary halos count.
Definition: mptrac.h:3731
int halo_offset_end
Hyperslab of boundary halos count.
Definition: mptrac.h:3737
int rank
Rank of node.
Definition: mptrac.h:3692
int neighbours[DD_NNMAX]
Rank of neighbouring nodes.
Definition: mptrac.h:3698
double subdomain_lon_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3713
size_t halo_bnd_start[4]
Hyperslab of boundary halos start.
Definition: mptrac.h:3728
double subdomain_lat_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3716
int init
Shows if domain decomposition was initialized.
Definition: mptrac.h:3744
double subdomain_lon_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3710
int halo_offset_start
Hyperslab of boundary halos count.
Definition: mptrac.h:3734
size_t subdomain_count[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3725
size_t subdomain_start[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3722
int size
Size of node.
Definition: mptrac.h:3695
double subdomain_lat_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3719
Meteo data structure.
Definition: mptrac.h:3511
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3589
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3577
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3649
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3619
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3676
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3640
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3613
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3634
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3595
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3538
int nx
Number of longitudes.
Definition: mptrac.h:3517
int ny
Number of latitudes.
Definition: mptrac.h:3520
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3571
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3550
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3646
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3559
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3670
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3667
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3556
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3643
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3658
int np
Number of pressure levels.
Definition: mptrac.h:3523
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3625
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3553
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3628
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3565
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3664
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3598
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3610
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3616
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3604
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3529
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3583
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3586
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3580
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3562
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3622
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3631
int npl
Number of model levels.
Definition: mptrac.h:3526
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3574
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3652
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3592
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3637
double eta[EP]
Model level eta values.
Definition: mptrac.h:3547
double time
Time [s].
Definition: mptrac.h:3514
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3601
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3568
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3661
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3607
double hyam[EP]
Model level a coefficients [Pa].
Definition: mptrac.h:3541
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3532
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3655
double hybm[EP]
Model level b coefficients.
Definition: mptrac.h:3544
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3673
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3535
Particle data.
Definition: mptrac.h:3286
double p
Pressure [hPa].
Definition: mptrac.h:3292
double lat
Latitude [deg].
Definition: mptrac.h:3298
double time
Time [s].
Definition: mptrac.h:3289
double lon
Longitude [deg].
Definition: mptrac.h:3295
double q[NQ]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3301