MPTRAC
mptrac.c
Go to the documentation of this file.
1/*
2 This file is part of MPTRAC.
3
4 MPTRAC is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 MPTRAC is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with MPTRAC. If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright (C) 2013-2025 Forschungszentrum Juelich GmbH
18*/
19
25#include "mptrac.h"
26
27#ifdef KPP
28#include "kpp_chem.h"
29#endif
30
32static gsl_rng *rng[NTHREADS];
33
35static uint64_t rng_ctr;
36
38#ifdef CURAND
39static curandGenerator_t rng_curand;
40#endif
41
42/*****************************************************************************/
43
44#ifdef MPI
46 void *data,
47 size_t N) {
48
49#define CHUNK_SIZE 2147483647
50
51 /* Broadcast the size of the data first... */
52 MPI_Bcast(&N, 1, MPI_UINT64_T, 0, MPI_COMM_WORLD);
53
54 /* Calculate the number of chunks... */
55 const size_t num_chunks = (N + CHUNK_SIZE - 1) / CHUNK_SIZE;
56
57 /* Loop over chunks... */
58 for (size_t i = 0; i < num_chunks; i++) {
59
60 /* Determine the start and end indices for the current chunk... */
61 const size_t start = i * CHUNK_SIZE;
62 const size_t end = (start + CHUNK_SIZE > N) ? N : start + CHUNK_SIZE;
63 const size_t chunk_size = end - start;
64
65 /* Broadcast the current chunk... */
66 MPI_Bcast((char *) data + start, (int) chunk_size, MPI_BYTE, 0,
67 MPI_COMM_WORLD);
68 }
69}
70#endif
71
72/*****************************************************************************/
73
75 const double *x,
76 double *z,
77 double *lon,
78 double *lat) {
79
80 const double radius = NORM(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.), cos_sza_thresh = cos(sza_thresh);
99
100 /* Get OH data from climatology... */
101 const double oh = clim_zm(&clim->oh, t, lat, p);
102
103 /* Apply diurnal correction... */
104 if (ctl->oh_chem_beta > 0) {
105 double sza = sza_calc(t, lon, lat);
106 if (sza <= sza_thresh)
107 return oh * exp(-ctl->oh_chem_beta / cos(sza));
108 else
109 return oh * exp(-ctl->oh_chem_beta / cos_sza_thresh);
110 } else
111 return oh;
112}
113
114/*****************************************************************************/
115
117 const ctl_t *ctl,
118 clim_t *clim) {
119
120 /* Set SZA threshold... */
121 const double sza_thresh = DEG2RAD(85.), cos_sza_thresh = cos(sza_thresh);
122
123 /* Loop over climatology data points... */
124 for (int it = 0; it < clim->oh.ntime; it++)
125 for (int iz = 0; iz < clim->oh.np; iz++)
126 for (int iy = 0; iy < clim->oh.nlat; iy++) {
127
128 /* Init... */
129 int n = 0;
130 double sum = 0;
131
132 /* Integrate day/night correction factor over longitude... */
133 for (double lon = -180; lon < 180; lon += 1.0) {
134 double sza = sza_calc(clim->oh.time[it], lon, clim->oh.lat[iy]);
135 if (sza <= sza_thresh)
136 sum += exp(-ctl->oh_chem_beta / cos(sza));
137 else
138 sum += exp(-ctl->oh_chem_beta / cos_sza_thresh);
139 n++;
140 }
141
142 /* Apply scaling factor to OH data... */
143 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
144 }
145}
146
147/*****************************************************************************/
148
150 const double rate[CP][CSZA][CO3],
151 const clim_photo_t *photo,
152 const double p,
153 const double sza,
154 const double o3c) {
155
156 /* Check pressure range... */
157 double p_help = p;
158 if (p < photo->p[photo->np - 1])
159 p_help = photo->p[photo->np - 1];
160 else if (p > photo->p[0])
161 p_help = photo->p[0];
162
163 /* Check sza range... */
164 double sza_help = sza;
165 if (sza < photo->sza[0])
166 sza_help = photo->sza[0];
167 else if (sza > photo->sza[photo->nsza - 1])
168 sza_help = photo->sza[photo->nsza - 1];
169
170 /* Check ozone column range... */
171 double o3c_help = o3c;
172 if (o3c < photo->o3c[0])
173 o3c_help = photo->o3c[0];
174 else if (o3c > photo->o3c[photo->no3c - 1])
175 o3c_help = photo->o3c[photo->no3c - 1];
176
177 /* Get indices... */
178 const int ip = locate_irr(photo->p, photo->np, p_help);
179 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
180 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
181
182 /* Interpolate photolysis rate... */
183 double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
184 photo->p[ip + 1], rate[ip + 1][isza][io3c], p_help);
185 double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
186 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1], p_help);
187 double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
188 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c], p_help);
189 double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
190 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
191 p_help);
192 aux00 = LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
193 aux11 = LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
194 aux00 = LIN(photo->sza[isza], aux00, photo->sza[isza + 1], aux11, sza_help);
195 return MAX(aux00, 0.0);
196}
197
198/*****************************************************************************/
199
201 const clim_t *clim,
202 const double t,
203 const double lat) {
204
205 /* Get seconds since begin of year... */
206 double sec = FMOD(t, 365.25 * 86400.);
207 while (sec < 0)
208 sec += 365.25 * 86400.;
209
210 /* Get indices... */
211 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
212 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
213
214 /* Interpolate tropopause pressure... */
215 const double p0 = LIN(clim->tropo_lat[ilat],
216 clim->tropo[isec][ilat],
217 clim->tropo_lat[ilat + 1],
218 clim->tropo[isec][ilat + 1], lat);
219 const double p1 = LIN(clim->tropo_lat[ilat],
220 clim->tropo[isec + 1][ilat],
221 clim->tropo_lat[ilat + 1],
222 clim->tropo[isec + 1][ilat + 1], lat);
223 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
224}
225
226/*****************************************************************************/
227
229 clim_t *clim) {
230
231 /* Write info... */
232 LOG(1, "Initialize tropopause data...");
233
234 /* Set time [s]... */
235 clim->tropo_ntime = 12;
236 double tropo_time[12] = {
237 1209600.00, 3888000.00, 6393600.00,
238 9072000.00, 11664000.00, 14342400.00,
239 16934400.00, 19612800.00, 22291200.00,
240 24883200.00, 27561600.00, 30153600.00
241 };
242 memcpy(clim->tropo_time, tropo_time, sizeof(clim->tropo_time));
243
244 /* Set latitudes [deg]... */
245 clim->tropo_nlat = 73;
246 double tropo_lat[73] = {
247 -90, -87.5, -85, -82.5, -80, -77.5, -75, -72.5, -70, -67.5,
248 -65, -62.5, -60, -57.5, -55, -52.5, -50, -47.5, -45, -42.5,
249 -40, -37.5, -35, -32.5, -30, -27.5, -25, -22.5, -20, -17.5,
250 -15, -12.5, -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10, 12.5,
251 15, 17.5, 20, 22.5, 25, 27.5, 30, 32.5, 35, 37.5, 40, 42.5,
252 45, 47.5, 50, 52.5, 55, 57.5, 60, 62.5, 65, 67.5, 70, 72.5,
253 75, 77.5, 80, 82.5, 85, 87.5, 90
254 };
255 memcpy(clim->tropo_lat, tropo_lat, sizeof(clim->tropo_lat));
256
257 /* Set tropopause pressure [hPa] (NCEP/NCAR Reanalysis 1)... */
258 double tropo[12][73] = {
259 {324.1, 325.6, 325, 324.3, 322.5, 319.7, 314, 307.2, 301.8, 299.6,
260 297.1, 292.2, 285.6, 276.1, 264, 248.9, 231.9, 213.5, 194.4,
261 175.3, 157, 140.4, 126.7, 116.3, 109.5, 105.4, 103, 101.4, 100.4,
262 99.69, 99.19, 98.84, 98.56, 98.39, 98.39, 98.42, 98.44, 98.54,
263 98.68, 98.81, 98.89, 98.96, 99.12, 99.65, 101.4, 105.4, 113.5, 128,
264 152.1, 184.7, 214, 234.1, 247.3, 255.8, 262.6, 267.7, 271.7, 275,
265 277.2, 279, 280.1, 280.4, 280.6, 280.1, 279.3, 278.3, 276.8, 275.8,
266 275.3, 275.6, 275.4, 274.1, 273.5},
267 {337.3, 338.7, 337.8, 336.4, 333, 328.8, 321.1, 312.6, 306.6, 303.7,
268 300.2, 293.8, 285.4, 273.8, 259.6, 242.7, 224.4, 205.2, 186, 167.5,
269 150.3, 135, 122.8, 113.9, 108.2, 104.7, 102.5, 101.1, 100.2, 99.42,
270 98.88, 98.52, 98.25, 98.09, 98.07, 98.1, 98.12, 98.2, 98.25, 98.27,
271 98.26, 98.27, 98.36, 98.79, 100.2, 104.2, 113.7, 131.2, 159.5, 193,
272 220.4, 238.1, 250.2, 258.1, 264.7, 269.7, 273.7, 277.3, 280.2, 282.8,
273 284.9, 286.5, 288.1, 288.8, 289, 288.5, 287.2, 286.3, 286.1, 287.2,
274 287.5, 286.2, 285.8},
275 {335, 336, 335.7, 335.1, 332.3, 328.1, 320.6, 311.8, 305.1, 301.9,
276 297.6, 290, 280.4, 268.3, 254.6, 239.6, 223.9, 207.9, 192.2, 176.9,
277 161.7, 146.4, 132.2, 120.6, 112.3, 107.2, 104.3, 102.4, 101.3,
278 100.4, 99.86, 99.47, 99.16, 98.97, 98.94, 98.97, 99, 99.09, 99.2,
279 99.31, 99.35, 99.41, 99.51, 99.86, 101.1, 104.9, 114.3, 131, 156.8,
280 186.3, 209.3, 224.6, 236.8, 246.3, 254.9, 262.3, 268.8, 274.8,
281 279.9, 284.6, 288.6, 291.6, 294.9, 297.5, 299.8, 301.8, 303.1,
282 304.3, 304.9, 306, 306.6, 306.2, 306},
283 {306.2, 306.7, 305.7, 307.1, 307.3, 306.4, 301.8, 296.2, 292.4,
284 290.3, 287.1, 280.9, 273.4, 264.3, 254.1, 242.8, 231, 219, 207.2,
285 195.5, 183.3, 169.7, 154.7, 138.7, 124.1, 113.6, 107.8, 104.7,
286 102.8, 101.7, 100.9, 100.4, 100, 99.79, 99.7, 99.66, 99.68, 99.79,
287 99.94, 100.2, 100.5, 100.9, 101.4, 102.1, 103.4, 107, 115.2, 129.1,
288 148.7, 171, 190.8, 205.6, 218.4, 229.4, 239.6, 248.6, 256.5,
289 263.7, 270.3, 276.6, 282.6, 288.1, 294.5, 300.4, 306.3, 311.4,
290 315.1, 318.3, 320.3, 322.2, 322.8, 321.5, 321.1},
291 {266.5, 264.9, 260.8, 261, 262, 263, 261.3, 259.7, 259.2, 259.8,
292 260.1, 258.6, 256.7, 253.6, 249.5, 243.9, 237.4, 230, 222.1, 213.9,
293 205, 194.4, 180.4, 161.8, 140.7, 122.9, 112.1, 106.7, 104.1, 102.7,
294 101.8, 101.4, 101.1, 101, 101, 101, 101.1, 101.2, 101.5, 101.9,
295 102.4, 103, 103.8, 104.9, 106.8, 110.1, 115.6, 124, 135.2, 148.9,
296 165.2, 181.3, 198, 211.8, 223.5, 233.8, 242.9, 251.5, 259, 266.2,
297 273.1, 279.2, 286.2, 292.8, 299.6, 306, 311.1, 315.5, 318.8, 322.6,
298 325.3, 325.8, 325.8},
299 {220.1, 218.1, 210.8, 207.2, 207.6, 210.5, 211.4, 213.5, 217.3,
300 222.4, 227.9, 232.8, 237.4, 240.8, 242.8, 243, 241.5, 238.6, 234.2,
301 228.5, 221, 210.7, 195.1, 172.9, 147.8, 127.6, 115.6, 109.9, 107.1,
302 105.7, 105, 104.8, 104.8, 104.9, 105, 105.1, 105.3, 105.5, 105.8,
303 106.4, 107, 107.6, 108.1, 108.8, 110, 111.8, 114.2, 117.4, 121.6,
304 127.9, 137.3, 151.2, 169.5, 189, 205.8, 218.9, 229.1, 237.8, 245,
305 251.5, 257.1, 262.3, 268.2, 274, 280.4, 286.7, 292.4, 297.9, 302.9,
306 308.5, 312.2, 313.1, 313.3},
307 {187.4, 184.5, 173.3, 166.1, 165.4, 167.8, 169.6, 173.6, 179.6,
308 187.9, 198.9, 210, 220.5, 229.2, 235.7, 239.9, 241.8, 241.6, 239.6,
309 235.8, 229.4, 218.6, 200.9, 175.9, 149.4, 129.4, 118.3, 113.1,
310 110.8, 109.7, 109.3, 109.4, 109.7, 110, 110.2, 110.4, 110.5, 110.7,
311 111, 111.4, 111.8, 112.1, 112.3, 112.7, 113.2, 113.9, 115, 116.4,
312 117.9, 120.4, 124.1, 130.9, 142.2, 159.6, 179.6, 198.5, 212.9,
313 224.2, 232.7, 239.1, 243.8, 247.7, 252.4, 257.3, 263.2, 269.5,
314 275.4, 281.1, 286.3, 292, 296.3, 298.2, 298.8},
315 {166, 166.4, 155.7, 148.3, 147.1, 149, 152.1, 157, 163.6, 172.4,
316 185.3, 199.2, 212.6, 224, 233.2, 239.6, 243.3, 244.6, 243.6, 240.3,
317 233.9, 222.6, 203.7, 177, 149.5, 129.7, 119, 114, 111.7, 110.7,
318 110.3, 110.3, 110.6, 110.9, 111.1, 111.3, 111.5, 111.6, 111.9,
319 112.2, 112.5, 112.6, 112.8, 113, 113.4, 114, 115.1, 116.5, 118.3,
320 120.9, 124.4, 130.2, 139.4, 154.6, 173.8, 193.1, 208.1, 220.4,
321 230.1, 238.2, 244.7, 249.5, 254.5, 259.3, 264.5, 269.4, 273.7,
322 278.2, 282.6, 287.4, 290.9, 292.5, 293},
323 {171.9, 172.8, 166.2, 162.3, 161.4, 162.5, 165.2, 169.6, 175.3,
324 183.1, 193.8, 205.9, 218.3, 229.6, 238.5, 244.3, 246.9, 246.7,
325 243.8, 238.4, 230.2, 217.9, 199.6, 174.9, 148.9, 129.8, 119.5,
326 114.8, 112.3, 110.9, 110.3, 110.1, 110.2, 110.3, 110.4, 110.5,
327 110.6, 110.8, 111, 111.4, 111.8, 112, 112.2, 112.4, 112.9, 113.6,
328 114.7, 116.3, 118.4, 121.9, 127.1, 136.1, 149.8, 168.4, 186.9,
329 203.3, 217, 229.1, 238.7, 247, 254, 259.3, 264.3, 268.3, 272.5,
330 276.6, 280.4, 284.4, 288.4, 293.3, 297.2, 298.7, 299.1},
331 {191.6, 192.2, 189, 188.1, 190.2, 193.7, 197.8, 202.9, 208.5,
332 215.6, 224.2, 233.1, 241.2, 247.3, 250.8, 251.3, 248.9, 244.2,
333 237.3, 228.4, 217.2, 202.9, 184.5, 162.5, 140.7, 124.8, 116.2,
334 111.8, 109.4, 107.9, 107, 106.7, 106.6, 106.6, 106.7, 106.7,
335 106.8, 107, 107.4, 108, 108.7, 109.3, 109.8, 110.4, 111.2,
336 112.4, 114.2, 116.9, 121.1, 127.9, 139.3, 155.2, 173.6, 190.7,
337 206.1, 220.1, 232.3, 243, 251.8, 259.2, 265.7, 270.6, 275.3,
338 279.3, 283.3, 286.9, 289.7, 292.8, 296.1, 300.5, 303.9, 304.8,
339 305.1},
340 {241.5, 239.6, 236.8, 237.4, 239.4, 242.3, 244.2, 246.4, 249.2,
341 253.6, 258.6, 262.7, 264.8, 264.2, 260.6, 254.1, 245.5, 235.3,
342 223.9, 211.7, 198.3, 183.1, 165.6, 147.1, 130.5, 118.7, 111.9,
343 108.1, 105.8, 104.3, 103.4, 102.8, 102.5, 102.4, 102.5, 102.5,
344 102.5, 102.7, 103.1, 103.8, 104.6, 105.4, 106.1, 107, 108.2,
345 109.9, 112.8, 117.5, 126, 140.4, 161, 181.9, 201.2, 216.8, 230.4,
346 241.8, 251.4, 259.9, 266.9, 272.8, 277.4, 280.4, 282.9, 284.6,
347 286.1, 287.4, 288.3, 289.5, 290.9, 294.2, 296.9, 297.5, 297.6},
348 {301.2, 300.3, 296.6, 295.4, 295, 294.3, 291.2, 287.4, 284.9, 284.7,
349 284.1, 281.5, 277.1, 270.4, 261.7, 250.6, 237.6, 223.1, 207.9, 192,
350 175.8, 158.8, 142.1, 127.6, 116.8, 109.9, 106, 103.6, 102.1, 101.1,
351 100.4, 99.96, 99.6, 99.37, 99.32, 99.32, 99.31, 99.46, 99.77, 100.2,
352 100.7, 101.3, 101.8, 102.7, 104.1, 106.8, 111.9, 121, 136.7, 160,
353 186.9, 209.9, 228.1, 241.2, 251.5, 259.5, 265.7, 270.9, 274.8, 278,
354 280.3, 281.8, 283, 283.3, 283.7, 283.8, 283, 282.2, 281.2, 281.4,
355 281.7, 281.1, 281.2}
356 };
357 memcpy(clim->tropo, tropo, sizeof(clim->tropo));
358
359 /* Get range... */
360 double tropomin = 1e99, tropomax = -1e99;
361 for (int it = 0; it < clim->tropo_ntime; it++)
362 for (int iy = 0; iy < clim->tropo_nlat; iy++) {
363 tropomin = MIN(tropomin, clim->tropo[it][iy]);
364 tropomax = MAX(tropomax, clim->tropo[it][iy]);
365 }
366
367 /* Write info... */
368 LOG(2, "Number of time steps: %d", clim->tropo_ntime);
369 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
370 clim->tropo_time[0], clim->tropo_time[1],
371 clim->tropo_time[clim->tropo_ntime - 1]);
372 LOG(2, "Number of latitudes: %d", clim->tropo_nlat);
373 LOG(2, "Latitudes: %g, %g ... %g deg",
374 clim->tropo_lat[0], clim->tropo_lat[1],
375 clim->tropo_lat[clim->tropo_nlat - 1]);
376 LOG(2, "Tropopause altitude range: %g ... %g hPa", Z(tropomax),
377 Z(tropomin));
378 LOG(2, "Tropopause pressure range: %g ... %g hPa", tropomin, tropomax);
379}
380
381/*****************************************************************************/
382
383double clim_ts(
384 const clim_ts_t *ts,
385 const double t) {
386
387 /* Interpolate... */
388 if (t <= ts->time[0])
389 return ts->vmr[0];
390 else if (t >= ts->time[ts->ntime - 1])
391 return ts->vmr[ts->ntime - 1];
392 else {
393 int idx = locate_irr(ts->time, ts->ntime, t);
394 return LIN(ts->time[idx], ts->vmr[idx],
395 ts->time[idx + 1], ts->vmr[idx + 1], t);
396 }
397}
398
399/*****************************************************************************/
400
401double clim_zm(
402 const clim_zm_t *zm,
403 const double t,
404 const double lat,
405 const double p) {
406
407 /* Get seconds since begin of year... */
408 double sec = FMOD(t, 365.25 * 86400.);
409 while (sec < 0)
410 sec += 365.25 * 86400.;
411
412 /* Check pressure range... */
413 double p_help = p;
414 if (p < zm->p[zm->np - 1])
415 p_help = zm->p[zm->np - 1];
416 else if (p > zm->p[0])
417 p_help = zm->p[0];
418
419 /* Check latitude range... */
420 double lat_help = lat;
421 if (lat < zm->lat[0])
422 lat_help = zm->lat[0];
423 else if (lat > zm->lat[zm->nlat - 1])
424 lat_help = zm->lat[zm->nlat - 1];
425
426 /* Get indices... */
427 const int isec = locate_irr(zm->time, zm->ntime, sec);
428 const int ilat = locate_reg(zm->lat, zm->nlat, lat_help);
429 const int ip = locate_irr(zm->p, zm->np, p_help);
430
431 /* Interpolate climatology data... */
432 double aux00 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat],
433 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat], p_help);
434 double aux01 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat + 1],
435 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat + 1], p_help);
436 double aux10 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat],
437 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat], p_help);
438 double aux11 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat + 1],
439 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat + 1],
440 p_help);
441 aux00 = LIN(zm->lat[ilat], aux00, zm->lat[ilat + 1], aux01, lat_help);
442 aux11 = LIN(zm->lat[ilat], aux10, zm->lat[ilat + 1], aux11, lat_help);
443 aux00 = LIN(zm->time[isec], aux00, zm->time[isec + 1], aux11, sec);
444
445 return MAX(aux00, 0.0);
446}
447
448/*****************************************************************************/
449
450#ifdef CMS
451void compress_cms(
452 const ctl_t *ctl,
453 const char *varname,
454 float *array,
455 const size_t nx,
456 const size_t ny,
457 const size_t np,
458 const int decompress,
459 FILE *inout) {
460
461 /* Set lon-lat grid... */
462 const size_t nxy = nx * ny;
463 double lon[EX], lat[EY];
464 for (size_t ix = 0; ix < nx; ix++)
465 lon[ix] = 360. * (double) ix / ((double) nx - 1.);
466 for (size_t iy = 0; iy < ny; iy++)
467 lat[iy] = -(180. * (double) iy / ((double) ny - 1.) - 90.);
468
469 /* Set multiscale parameters... */
470 const char domain[] = "[0.0, 360.0]x[-90.0, 90.0]";
471 const int Nd0_x = 48;
472 const int Nd0_y = 24;
473 const int max_level_grid = 6;
474 cms_param_t *cms_param
475 = cms_set_parameters(nx, ny, max_level_grid, Nd0_x, Nd0_y, domain);
476
477 /* Init... */
478 double cr = 0, t_coars = 0, t_eval = 0;
479
480 /* Read compressed stream and decompress array... */
481 if (decompress) {
482
483 /* Loop over levels... */
484 for (size_t ip = 0; ip < np; ip++) {
485
486 /* Initialize multiscale module... */
487 cms_module_t *cms_ptr = cms_init(cms_param);
488
489 /* Read binary data... */
490 cms_sol_t *cms_sol;
491 if (ctl->met_cms_zstd == 1)
492 cms_sol = cms_read_zstd_sol(cms_ptr, inout);
493 else
494 cms_sol = cms_read_sol(cms_ptr, inout);
495
496 /* Evaluate... */
497#pragma omp parallel for default(shared)
498 for (size_t ix = 0; ix < nx; ix++)
499 for (size_t iy = 0; iy < ny; iy++) {
500 double val;
501 const double x[] = { lon[ix], lat[iy] };
502 cms_eval(cms_ptr, cms_sol, x, &val);
503 array[ARRAY_3D(ix, iy, ny, ip, np)] = (float) val;
504 }
505
506 /* Calculate mean compression ratio... */
507 cr += cms_compression_rate(cms_ptr, cms_sol) / (double) np;
508
509 /* Free... */
510 cms_delete_sol(cms_sol);
511 cms_delete_module(cms_ptr);
512 }
513
514 /* Write info... */
515 LOG(2, "Read 3-D variable: %s (cms, RATIO= %g)", varname, cr);
516 }
517
518 /* Compress array and output compressed stream... */
519 else {
520
521 /* Init... */
522 cms_module_t *cms_ptr[EP];
523 cms_sol_t *cms_sol[EP];
524
525 /* Loop over batches... */
526 const size_t dip = (ctl->met_cms_batch <= 0
527 ? (size_t) omp_get_max_threads()
528 : (size_t) ctl->met_cms_batch);
529 for (size_t ip0 = 0; ip0 < np; ip0 += dip) {
530
531 /* Measure time... */
532 double t0 = omp_get_wtime();
533
534 /* Loop over levels... */
535#pragma omp parallel for default(shared)
536 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
537
538 /* Allocate... */
539 float *tmp_arr;
540 ALLOC(tmp_arr, float,
541 nxy);
542
543 /* Copy level data... */
544 for (size_t ix = 0; ix < nx; ++ix)
545 for (size_t iy = 0; iy < ny; ++iy)
546 tmp_arr[ARRAY_2D(ix, iy, ny)] =
547 array[ARRAY_3D(ix, iy, ny, ip, np)];
548
549 /* Set eps threshold value... */
550 double c_thresh_test;
551 if (strcasecmp(varname, "Z") == 0)
552 c_thresh_test = ctl->met_cms_eps_z;
553 else if (strcasecmp(varname, "T") == 0)
554 c_thresh_test = ctl->met_cms_eps_t;
555 else if (strcasecmp(varname, "U") == 0)
556 c_thresh_test = ctl->met_cms_eps_u;
557 else if (strcasecmp(varname, "V") == 0)
558 c_thresh_test = ctl->met_cms_eps_v;
559 else if (strcasecmp(varname, "W") == 0)
560 c_thresh_test = ctl->met_cms_eps_w;
561 else if (strcasecmp(varname, "PV") == 0)
562 c_thresh_test = ctl->met_cms_eps_pv;
563 else if (strcasecmp(varname, "H2O") == 0)
564 c_thresh_test = ctl->met_cms_eps_h2o;
565 else if (strcasecmp(varname, "O3") == 0)
566 c_thresh_test = ctl->met_cms_eps_o3;
567 else if (strcasecmp(varname, "LWC") == 0)
568 c_thresh_test = ctl->met_cms_eps_lwc;
569 else if (strcasecmp(varname, "RWC") == 0)
570 c_thresh_test = ctl->met_cms_eps_rwc;
571 else if (strcasecmp(varname, "IWC") == 0)
572 c_thresh_test = ctl->met_cms_eps_iwc;
573 else if (strcasecmp(varname, "SWC") == 0)
574 c_thresh_test = ctl->met_cms_eps_swc;
575 else if (strcasecmp(varname, "CC") == 0)
576 c_thresh_test = ctl->met_cms_eps_cc;
577 else
578 ERRMSG("Variable name unknown!");
579
580 /* Initialize multiscale module... */
581 cms_ptr[ip] = cms_init(cms_param);
582
583 /* Coarsening... */
584 cms_sol[ip] =
585 cms_read_arr_new(cms_ptr[ip], tmp_arr, lon, lat,
586 nx, ny, c_thresh_test);
587
588 /* Free... */
589 free(tmp_arr);
590 }
591
592 /* Measure time... */
593 t_coars += (omp_get_wtime() - t0);
594
595 /* Loop over levels... */
596 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
597
598 /* Allocate... */
599 double *tmp_cms, *tmp_org, *tmp_diff;
600 ALLOC(tmp_cms, double,
601 nxy);
602 ALLOC(tmp_org, double,
603 nxy);
604 ALLOC(tmp_diff, double,
605 nxy);
606
607 /* Measure time... */
608 t0 = omp_get_wtime();
609
610 /* Evaluate... */
611#pragma omp parallel for default(shared)
612 for (size_t ix = 0; ix < nx; ix++)
613 for (size_t iy = 0; iy < ny; iy++) {
614 const size_t idx = ARRAY_2D(ix, iy, ny);
615 const double x[] = { lon[ix], lat[iy] };
616 cms_eval(cms_ptr[ip], cms_sol[ip], x, &tmp_cms[idx]);
617 tmp_org[idx] = array[ARRAY_3D(ix, iy, ny, ip, np)];
618 tmp_diff[idx] = tmp_cms[idx] - tmp_org[idx];
619 }
620
621 /* Measure time... */
622 t_eval += (omp_get_wtime() - t0);
623
624 /* Write info... */
625 LOG(2,
626 "cmultiscale: var= %s / lev= %lu / ratio= %g / rho= %g"
627 " / mean= %g / sd= %g / min= %g / max= %g", varname, ip,
628 cms_compression_rate(cms_ptr[ip], cms_sol[ip]),
629 gsl_stats_correlation(tmp_cms, 1, tmp_org, 1, nxy),
630 gsl_stats_mean(tmp_diff, 1, nxy), gsl_stats_sd(tmp_diff, 1, nxy),
631 gsl_stats_min(tmp_diff, 1, nxy), gsl_stats_max(tmp_diff, 1, nxy));
632
633 /* Calculate mean compression ratio... */
634 cr += cms_compression_rate(cms_ptr[ip], cms_sol[ip]) / (double) np;
635
636 /* Save binary data... */
637 if (ctl->met_cms_zstd == 1)
638 cms_save_zstd_sol(cms_sol[ip], inout, 3);
639 else
640 cms_save_sol(cms_sol[ip], inout);
641
642 /* Free... */
643 cms_delete_sol(cms_sol[ip]);
644 cms_delete_module(cms_ptr[ip]);
645 free(tmp_cms);
646 free(tmp_org);
647 free(tmp_diff);
648 }
649 }
650
651 /* Write info... */
652 LOG(2, "Write 3-D variable: %s"
653 " (cms, RATIO= %g, T_COARS= %g s, T_EVAL= %g s)",
654 varname, cr, t_coars, t_eval);
655 }
656
657 /* Free... */
658 cms_delete_param(cms_param);
659}
660#endif
661
662/*****************************************************************************/
663
665 const char *varname,
666 float *array,
667 const size_t nxy,
668 const size_t nz,
669 const int decompress,
670 FILE *inout) {
671
672 double min[EP], max[EP], off[EP], scl[EP];
673
674 unsigned short *sarray;
675
676 /* Allocate... */
677 ALLOC(sarray, unsigned short,
678 nxy * nz);
679
680 /* Read compressed stream and decompress array... */
681 if (decompress) {
682
683 /* Write info... */
684 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
685 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
686
687 /* Read data... */
688 FREAD(&scl, double,
689 nz,
690 inout);
691 FREAD(&off, double,
692 nz,
693 inout);
694 FREAD(sarray, unsigned short,
695 nxy * nz,
696 inout);
697
698 /* Convert to float... */
699#pragma omp parallel for default(shared)
700 for (size_t ixy = 0; ixy < nxy; ixy++)
701 for (size_t iz = 0; iz < nz; iz++)
702 array[ixy * nz + iz]
703 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
704 }
705
706 /* Compress array and output compressed stream... */
707 else {
708
709 /* Write info... */
710 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
711 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
712
713 /* Get range... */
714 for (size_t iz = 0; iz < nz; iz++) {
715 min[iz] = array[iz];
716 max[iz] = array[iz];
717 }
718 for (size_t ixy = 1; ixy < nxy; ixy++)
719 for (size_t iz = 0; iz < nz; iz++) {
720 if (array[ixy * nz + iz] < min[iz])
721 min[iz] = array[ixy * nz + iz];
722 if (array[ixy * nz + iz] > max[iz])
723 max[iz] = array[ixy * nz + iz];
724 }
725
726 /* Get offset and scaling factor... */
727 for (size_t iz = 0; iz < nz; iz++) {
728 scl[iz] = (max[iz] - min[iz]) / 65533.;
729 off[iz] = min[iz];
730 }
731
732 /* Convert to short... */
733#pragma omp parallel for default(shared)
734 for (size_t ixy = 0; ixy < nxy; ixy++)
735 for (size_t iz = 0; iz < nz; iz++)
736 if (scl[iz] != 0)
737 sarray[ixy * nz + iz] = (unsigned short)
738 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
739 else
740 sarray[ixy * nz + iz] = 0;
741
742 /* Write data... */
743 FWRITE(&scl, double,
744 nz,
745 inout);
746 FWRITE(&off, double,
747 nz,
748 inout);
749 FWRITE(sarray, unsigned short,
750 nxy * nz,
751 inout);
752 }
753
754 /* Free... */
755 free(sarray);
756}
757
758/*****************************************************************************/
759
760#ifdef ZFP
761void compress_zfp(
762 const char *varname,
763 float *array,
764 const int nx,
765 const int ny,
766 const int nz,
767 const int precision,
768 const double tolerance,
769 const int decompress,
770 FILE *inout) {
771
772 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
773 const zfp_type type = zfp_type_float;
774 zfp_field *field =
775 zfp_field_3d(array, type, (uint) nx, (uint) ny, (uint) nz);
776
777 /* Allocate meta data for a compressed stream... */
778 zfp_stream *zfp = zfp_stream_open(NULL);
779 if (!field || !zfp)
780 ERRMSG("Failed to allocate zfp structures!");
781
782 /* Set compression mode... */
783 int actual_prec = 0;
784 double actual_tol = 0;
785 if ((precision > 0 && tolerance > 0) || (precision <= 0 && tolerance <= 0)) {
786 ERRMSG("Exactly one of precision or tolerance must be set for zfp!");
787 } else if (precision > 0)
788 actual_prec = (int) zfp_stream_set_precision(zfp, (uint) precision);
789 else if (tolerance > 0)
790 actual_tol = zfp_stream_set_accuracy(zfp, tolerance);
791
792 /* Allocate buffer for compressed data... */
793 const size_t bufsize = zfp_stream_maximum_size(zfp, field);
794 void *buffer = malloc(bufsize);
795 if (!buffer)
796 ERRMSG("Failed to allocate compression buffer!");
797
798 /* Associate bit stream with allocated buffer... */
799 bitstream *stream = stream_open(buffer, bufsize);
800 zfp_stream_set_bit_stream(zfp, stream);
801 zfp_stream_rewind(zfp);
802
803 /* Read compressed stream and decompress array... */
804 size_t zfpsize;
805 if (decompress) {
806 FREAD(&zfpsize, size_t,
807 1,
808 inout);
809 if (zfpsize > bufsize)
810 ERRMSG("Compressed data size exceeds allocated buffer!");
811 if (fread(buffer, 1, zfpsize, inout) != zfpsize)
812 ERRMSG("Error while reading zfp data!");
813 if (!zfp_decompress(zfp, field)) {
814 ERRMSG("Decompression failed!");
815 }
816 LOG(2, "Read 3-D variable: %s "
817 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
818 varname, actual_prec, actual_tol,
819 ((double) (nx * ny * nz)) / (double) zfpsize);
820 }
821
822 /* Compress array and output compressed stream... */
823 else {
824 zfpsize = zfp_compress(zfp, field);
825 if (!zfpsize) {
826 ERRMSG("Compression failed!");
827 } else {
828 FWRITE(&zfpsize, size_t,
829 1,
830 inout);
831 if (fwrite(buffer, 1, zfpsize, inout) != zfpsize)
832 ERRMSG("Error while writing zfp data!");
833 }
834 LOG(2, "Write 3-D variable: %s "
835 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
836 varname, actual_prec, actual_tol,
837 ((double) (nx * ny * nz)) / (double) zfpsize);
838 }
839
840 /* Free... */
841 zfp_field_free(field);
842 zfp_stream_close(zfp);
843 stream_close(stream);
844 free(buffer);
845}
846#endif
847
848/*****************************************************************************/
849
850#ifdef ZSTD
851void compress_zstd(
852 const char *varname,
853 float *array,
854 const size_t n,
855 const int decompress,
856 const int level,
857 FILE *inout) {
858
859 /* Get buffer sizes... */
860 const size_t uncomprLen = n * sizeof(float);
861 size_t comprLen = ZSTD_compressBound(uncomprLen);
862 size_t compsize;
863
864 /* Allocate... */
865 char *compr = (char *) calloc((uint) comprLen, 1);
866 char *uncompr = (char *) array;
867
868 /* Read compressed stream and decompress array... */
869 if (decompress) {
870 FREAD(&comprLen, size_t,
871 1,
872 inout);
873 if (fread(compr, 1, comprLen, inout) != comprLen)
874 ERRMSG("Error while reading zstd data!");
875 compsize = ZSTD_decompress(uncompr, uncomprLen, compr, comprLen);
876 if (ZSTD_isError(compsize)) {
877 ERRMSG("Decompression failed!");
878 }
879 LOG(2, "Read 3-D variable: %s (zstd, RATIO= %g)",
880 varname, ((double) uncomprLen) / (double) comprLen)
881 }
882
883 /* Compress array and output compressed stream... */
884 else {
885 compsize = ZSTD_compress(compr, comprLen, uncompr, uncomprLen, level);
886 if (ZSTD_isError(compsize)) {
887 ERRMSG("Compression failed!");
888 } else {
889 FWRITE(&compsize, size_t,
890 1,
891 inout);
892 if (fwrite(compr, 1, compsize, inout) != compsize)
893 ERRMSG("Error while writing zstd data!");
894 }
895 LOG(2, "Write 3-D variable: %s (zstd, RATIO= %g)",
896 varname, ((double) uncomprLen) / (double) compsize);
897 }
898
899 /* Free... */
900 free(compr);
901}
902#endif
903
904/*****************************************************************************/
905
907 const int year,
908 const int mon,
909 const int day,
910 int *doy) {
911
912 const int
913 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
914 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
915
916 /* Get day of year... */
917 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
918 *doy = d0l[mon - 1] + day - 1;
919 else
920 *doy = d0[mon - 1] + day - 1;
921}
922
923/*****************************************************************************/
924
926 const int year,
927 const int doy,
928 int *mon,
929 int *day) {
930
931 const int
932 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
933 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
934
935 int i;
936
937 /* Get month and day... */
938 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
939 for (i = 11; i > 0; i--)
940 if (d0l[i] <= doy)
941 break;
942 *mon = i + 1;
943 *day = doy - d0l[i] + 1;
944 } else {
945 for (i = 11; i > 0; i--)
946 if (d0[i] <= doy)
947 break;
948 *mon = i + 1;
949 *day = doy - d0[i] + 1;
950 }
951}
952
953/*****************************************************************************/
954
956 double *fcReal,
957 double *fcImag,
958 const int n) {
959
960 double data[2 * EX];
961
962 /* Check size... */
963 if (n > EX)
964 ERRMSG("Too many data points!");
965
966 /* Allocate... */
967 gsl_fft_complex_wavetable *wavetable =
968 gsl_fft_complex_wavetable_alloc((size_t) n);
969 gsl_fft_complex_workspace *workspace =
970 gsl_fft_complex_workspace_alloc((size_t) n);
971
972 /* Set data (real, complex)... */
973 for (int i = 0; i < n; i++) {
974 data[2 * i] = fcReal[i];
975 data[2 * i + 1] = fcImag[i];
976 }
977
978 /* Calculate FFT... */
979 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
980
981 /* Copy data... */
982 for (int i = 0; i < n; i++) {
983 fcReal[i] = data[2 * i];
984 fcImag[i] = data[2 * i + 1];
985 }
986
987 /* Free... */
988 gsl_fft_complex_wavetable_free(wavetable);
989 gsl_fft_complex_workspace_free(workspace);
990}
991
992/*****************************************************************************/
993
995 const double z,
996 const double lon,
997 const double lat,
998 double *x) {
999
1000 const double radius = z + RE;
1001 const double latrad = DEG2RAD(lat);
1002 const double lonrad = DEG2RAD(lon);
1003 const double coslat = cos(latrad);
1004
1005 x[0] = radius * coslat * cos(lonrad);
1006 x[1] = radius * coslat * sin(lonrad);
1007 x[2] = radius * sin(latrad);
1008}
1009
1010/*****************************************************************************/
1011
1013 const ctl_t *ctl,
1014 const double t,
1015 const int direct,
1016 const char *metbase,
1017 const double dt_met,
1018 char *filename) {
1019
1020 char repl[LEN];
1021
1022 double t6, r;
1023
1024 int year, mon, day, hour, min, sec;
1025
1026 /* Round time to fixed intervals... */
1027 if (direct == -1)
1028 t6 = floor(t / dt_met) * dt_met;
1029 else
1030 t6 = ceil(t / dt_met) * dt_met;
1031
1032 /* Decode time... */
1033 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1034
1035 /* Set filename of MPTRAC meteo files... */
1036 if (ctl->met_clams == 0) {
1037 if (ctl->met_type == 0)
1038 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1039 else if (ctl->met_type == 1)
1040 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1041 else if (ctl->met_type == 2)
1042 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1043 else if (ctl->met_type == 3)
1044 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1045 else if (ctl->met_type == 4)
1046 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1047 else if (ctl->met_type == 5)
1048 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1049 sprintf(repl, "%d", year);
1050 get_met_replace(filename, "YYYY", repl);
1051 sprintf(repl, "%02d", mon);
1052 get_met_replace(filename, "MM", repl);
1053 sprintf(repl, "%02d", day);
1054 get_met_replace(filename, "DD", repl);
1055 sprintf(repl, "%02d", hour);
1056 get_met_replace(filename, "HH", repl);
1057 }
1058
1059 /* Set filename of CLaMS meteo files... */
1060 else {
1061 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1062 sprintf(repl, "%d", year);
1063 get_met_replace(filename, "YYYY", repl);
1064 sprintf(repl, "%02d", year % 100);
1065 get_met_replace(filename, "YY", repl);
1066 sprintf(repl, "%02d", mon);
1067 get_met_replace(filename, "MM", repl);
1068 sprintf(repl, "%02d", day);
1069 get_met_replace(filename, "DD", repl);
1070 sprintf(repl, "%02d", hour);
1071 get_met_replace(filename, "HH", repl);
1072 }
1073}
1074
1075/*****************************************************************************/
1076
1078 char *orig,
1079 char *search,
1080 char *repl) {
1081
1082 char buffer[LEN];
1083
1084 /* Iterate... */
1085 for (int i = 0; i < 3; i++) {
1086
1087 /* Replace sub-string... */
1088 char *ch;
1089 if (!(ch = strstr(orig, search)))
1090 return;
1091 strncpy(buffer, orig, (size_t) (ch - orig));
1092 buffer[ch - orig] = 0;
1093 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1094 orig[0] = 0;
1095 strcpy(orig, buffer);
1096 }
1097}
1098
1099/*****************************************************************************/
1100
1102 const int met_tropo,
1103 ctl_t *ctl,
1104 clim_t *clim,
1105 met_t *met,
1106 const double *lons,
1107 const int nx,
1108 const double *lats,
1109 const int ny,
1110 double *pt,
1111 double *zt,
1112 double *tt,
1113 double *qt,
1114 double *o3t,
1115 double *ps,
1116 double *zs) {
1117
1119
1120 ctl->met_tropo = met_tropo;
1121 read_met_tropo(ctl, clim, met);
1122#pragma omp parallel for default(shared) private(ci,cw)
1123 for (int ix = 0; ix < nx; ix++)
1124 for (int iy = 0; iy < ny; iy++) {
1125 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1126 &pt[iy * nx + ix], ci, cw, 1);
1127 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1128 &ps[iy * nx + ix], ci, cw, 0);
1129 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1130 &zs[iy * nx + ix], ci, cw, 0);
1131 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1132 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1133 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1134 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1135 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1136 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1137 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1138 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1139 }
1140}
1141
1142/*****************************************************************************/
1143
1145 const double *lons,
1146 const int nlon,
1147 const double *lats,
1148 const int nlat,
1149 const double lon,
1150 const double lat,
1151 double *lon2,
1152 double *lat2) {
1153
1154 /* Check longitude... */
1155 *lon2 = FMOD(lon, 360.);
1156 if (*lon2 < lons[0])
1157 *lon2 += 360;
1158 else if (*lon2 > lons[nlon - 1])
1159 *lon2 -= 360;
1160
1161 /* Check latitude... */
1162 *lat2 = lat;
1163 if (lats[0] < lats[nlat - 1])
1164 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
1165 else
1166 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
1167}
1168
1169/*****************************************************************************/
1170
1172 const met_t *met0,
1173 float heights0[EX][EY][EP],
1174 float array0[EX][EY][EP],
1175 const met_t *met1,
1176 float heights1[EX][EY][EP],
1177 float array1[EX][EY][EP],
1178 const double ts,
1179 const double height,
1180 const double lon,
1181 const double lat,
1182 double *var,
1183 int *ci,
1184 double *cw,
1185 const int init) {
1186
1187 if (init) {
1188
1189 /* Check longitude and latitude... */
1190 double lon2, lat2;
1191 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
1192 &lon2, &lat2);
1193
1194 /* Get horizontal indizes... */
1195 ci[0] = locate_irr(met0->lon, met0->nx, lon2);
1196 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
1197
1198 /* Locate the vertical indizes for each edge of the column... */
1199 int ind[2][4];
1200 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1201 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1202
1203 /* Find minimum and maximum indizes... */
1204 ci[2] = ind[0][0];
1205 int k_max = ind[0][0];
1206 for (int i = 0; i < 2; i++)
1207 for (int j = 0; j < 4; j++) {
1208 if (ci[2] > ind[i][j])
1209 ci[2] = ind[i][j];
1210 if (k_max < ind[i][j])
1211 k_max = ind[i][j];
1212 }
1213
1214 /* Get weighting factors for time, longitude and latitude... */
1215 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1216 cw[0] = (lon2 - met0->lon[ci[0]]) /
1217 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1218 cw[1] = (lat2 - met0->lat[ci[1]]) /
1219 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1220
1221 /* Interpolate in time at the lowest level... */
1222 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1223 - heights0[ci[0]][ci[1]][ci[2]])
1224 + heights0[ci[0]][ci[1]][ci[2]];
1225 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1226 - heights0[ci[0]][ci[1] + 1][ci[2]])
1227 + heights0[ci[0]][ci[1] + 1][ci[2]];
1228 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1229 - heights0[ci[0] + 1][ci[1]][ci[2]])
1230 + heights0[ci[0] + 1][ci[1]][ci[2]];
1231 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1232 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1233 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1234
1235 /* Interpolate in latitude direction... */
1236 double height0 = cw[1] * (height01 - height00) + height00;
1237 double height1 = cw[1] * (height11 - height10) + height10;
1238
1239 /* Interpolate in longitude direction... */
1240 double height_bot = cw[0] * (height1 - height0) + height0;
1241
1242 /* Interpolate in time at the upper level... */
1243 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1244 - heights0[ci[0]][ci[1]][ci[2] + 1])
1245 + heights0[ci[0]][ci[1]][ci[2] + 1];
1246 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1247 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1248 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1249 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1250 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1251 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1252 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1253 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1254 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1255
1256 /* Interpolate in latitude direction... */
1257 height0 = cw[1] * (height01 - height00) + height00;
1258 height1 = cw[1] * (height11 - height10) + height10;
1259
1260 /* Interpolate in longitude direction... */
1261 double height_top = cw[0] * (height1 - height0) + height0;
1262
1263 /* Search at higher levels if height is not in box... */
1264 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1265 ((height_bot <= height) || (height_top > height))
1266 && (height_bot >= height) && (ci[2] < k_max))
1267 ||
1268 ((heights0[0][0][0] < heights0[0][0][1]) &&
1269 ((height_bot >= height) || (height_top < height))
1270 && (height_bot <= height) && (ci[2] < k_max))
1271 ) {
1272
1273 ci[2]++;
1274 height_bot = height_top;
1275
1276 /* Interpolate in time at the next level... */
1277 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1278 - heights0[ci[0]][ci[1]][ci[2] + 1])
1279 + heights0[ci[0]][ci[1]][ci[2] + 1];
1280 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1281 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1282 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1283 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1284 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1285 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1286 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1287 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1288 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1289
1290 /* Interpolate in latitude direction... */
1291 height0 = cw[1] * (height01 - height00) + height00;
1292 height1 = cw[1] * (height11 - height10) + height10;
1293
1294 /* Interpolate in longitude direction... */
1295 height_top = cw[0] * (height1 - height0) + height0;
1296 }
1297
1298 /* Get vertical weighting factors... */
1299 cw[2] = (height - height_bot)
1300 / (height_top - height_bot);
1301 }
1302
1303 /* Calculate the needed array values... */
1304 double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1305 - array0[ci[0]][ci[1]][ci[2]])
1306 + array0[ci[0]][ci[1]][ci[2]];
1307 double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1308 - array0[ci[0] + 1][ci[1]][ci[2]])
1309 + array0[ci[0] + 1][ci[1]][ci[2]];
1310 double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1311 - array0[ci[0]][ci[1] + 1][ci[2]])
1312 + array0[ci[0]][ci[1] + 1][ci[2]];
1313 double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1314 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1315 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1316 double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1317 - array0[ci[0]][ci[1]][ci[2] + 1])
1318 + array0[ci[0]][ci[1]][ci[2] + 1];
1319 double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
1320 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
1321 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
1322 double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
1323 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
1324 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
1325 double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1326 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1327 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1328
1329 double array00 = cw[0] * (array100 - array000) + array000;
1330 double array10 = cw[0] * (array110 - array010) + array010;
1331 double array01 = cw[0] * (array101 - array001) + array001;
1332 double array11 = cw[0] * (array111 - array011) + array011;
1333
1334 double aux0 = cw[1] * (array10 - array00) + array00;
1335 double aux1 = cw[1] * (array11 - array01) + array01;
1336
1337 /* Interpolate vertically... */
1338 *var = cw[2] * (aux1 - aux0) + aux0;
1339}
1340
1341/*****************************************************************************/
1342
1344 const met_t *met,
1345 float array[EX][EY][EP],
1346 const double p,
1347 const double lon,
1348 const double lat,
1349 double *var,
1350 int *ci,
1351 double *cw,
1352 const int init) {
1353
1354 /* Initialize interpolation... */
1355 if (init) {
1356
1357 /* Check longitude and latitude... */
1358 double lon2, lat2;
1359 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1360 &lon2, &lat2);
1361
1362 /* Get interpolation indices... */
1363 ci[0] = locate_irr(met->p, met->np, p);
1364 ci[1] = locate_reg(met->lon, met->nx, lon2);
1365 ci[2] = locate_irr(met->lat, met->ny, lat2);
1366
1367 /* Get interpolation weights... */
1368 cw[0] = (met->p[ci[0] + 1] - p)
1369 / (met->p[ci[0] + 1] - met->p[ci[0]]);
1370 cw[1] = (met->lon[ci[1] + 1] - lon2)
1371 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1372 cw[2] = (met->lat[ci[2] + 1] - lat2)
1373 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1374 }
1375
1376 /* Interpolate vertically... */
1377 double aux00 =
1378 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
1379 + array[ci[1]][ci[2]][ci[0] + 1];
1380 double aux01 =
1381 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
1382 array[ci[1]][ci[2] + 1][ci[0] + 1])
1383 + array[ci[1]][ci[2] + 1][ci[0] + 1];
1384 double aux10 =
1385 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
1386 array[ci[1] + 1][ci[2]][ci[0] + 1])
1387 + array[ci[1] + 1][ci[2]][ci[0] + 1];
1388 double aux11 =
1389 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
1390 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
1391 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
1392
1393 /* Interpolate horizontally... */
1394 aux00 = cw[2] * (aux00 - aux01) + aux01;
1395 aux11 = cw[2] * (aux10 - aux11) + aux11;
1396 *var = cw[1] * (aux00 - aux11) + aux11;
1397}
1398
1399/*****************************************************************************/
1400
1402 const met_t *met,
1403 float zs[EX][EY][EP],
1404 float array[EX][EY][EP],
1405 const double z,
1406 const double lon,
1407 const double lat,
1408 double *var) {
1409
1410 /* Check longitude and latitude... */
1411 double lon2, lat2;
1412 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat, &lon2,
1413 &lat2);
1414
1415 /* Get horizontal indices... */
1416 const int ix = locate_reg(met->lon, met->nx, lon2);
1417 const int iy = locate_irr(met->lat, met->ny, lat2);
1418
1419 /* Interpolate vertically... */
1420 int iz = locate_irr_float(zs[ix][iy], met->npl, z, 0);
1421 double aux00;
1422 if (z >= zs[ix][iy][iz + 1])
1423 aux00 = array[ix][iy][iz + 1];
1424 else if (z <= zs[ix][iy][iz])
1425 aux00 = array[ix][iy][iz];
1426 else
1427 aux00 = LIN(zs[ix][iy][iz], array[ix][iy][iz],
1428 zs[ix][iy][iz + 1], array[ix][iy][iz + 1], z);
1429
1430 iz = locate_irr_float(zs[ix][iy + 1], met->npl, z, iz);
1431 double aux01;
1432 if (z >= zs[ix][iy + 1][iz + 1])
1433 aux01 = array[ix][iy + 1][iz + 1];
1434 else if (z <= zs[ix][iy + 1][iz])
1435 aux01 = array[ix][iy + 1][iz];
1436 else
1437 aux01 = LIN(zs[ix][iy + 1][iz], array[ix][iy + 1][iz],
1438 zs[ix][iy + 1][iz + 1], array[ix][iy + 1][iz + 1], z);
1439
1440 iz = locate_irr_float(zs[ix + 1][iy], met->npl, z, iz);
1441 double aux10;
1442 if (z >= zs[ix + 1][iy][iz + 1])
1443 aux10 = array[ix + 1][iy][iz + 1];
1444 else if (z <= zs[ix + 1][iy][iz])
1445 aux10 = array[ix + 1][iy][iz];
1446 else
1447 aux10 = LIN(zs[ix + 1][iy][iz], array[ix + 1][iy][iz],
1448 zs[ix + 1][iy][iz + 1], array[ix + 1][iy][iz + 1], z);
1449
1450 iz = locate_irr_float(zs[ix + 1][iy + 1], met->npl, z, iz);
1451 double aux11;
1452 if (z >= zs[ix + 1][iy + 1][iz + 1])
1453 aux11 = array[ix + 1][iy + 1][iz + 1];
1454 else if (z <= zs[ix + 1][iy + 1][iz])
1455 aux11 = array[ix + 1][iy + 1][iz];
1456 else
1457 aux11 = LIN(zs[ix + 1][iy + 1][iz], array[ix + 1][iy + 1][iz],
1458 zs[ix + 1][iy + 1][iz + 1], array[ix + 1][iy + 1][iz + 1], z);
1459
1460 /* Interpolate horizontally... */
1461 double aux0 = LIN(met->lat[iy], aux00, met->lat[iy + 1], aux01, lat2);
1462 double aux1 = LIN(met->lat[iy], aux10, met->lat[iy + 1], aux11, lat2);
1463 *var = LIN(met->lon[ix], aux0, met->lon[ix + 1], aux1, lon2);
1464}
1465
1466/*****************************************************************************/
1467
1469 const met_t *met,
1470 float array[EX][EY],
1471 const double lon,
1472 const double lat,
1473 double *var,
1474 int *ci,
1475 double *cw,
1476 const int init) {
1477
1478 /* Initialize interpolation... */
1479 if (init) {
1480
1481 /* Check longitude and latitude... */
1482 double lon2, lat2;
1483 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1484 &lon2, &lat2);
1485
1486 /* Get interpolation indices... */
1487 ci[1] = locate_reg(met->lon, met->nx, lon2);
1488 ci[2] = locate_irr(met->lat, met->ny, lat2);
1489
1490 /* Get interpolation weights... */
1491 cw[1] = (met->lon[ci[1] + 1] - lon2)
1492 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1493 cw[2] = (met->lat[ci[2] + 1] - lat2)
1494 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1495 }
1496
1497 /* Set variables... */
1498 double aux00 = array[ci[1]][ci[2]];
1499 double aux01 = array[ci[1]][ci[2] + 1];
1500 double aux10 = array[ci[1] + 1][ci[2]];
1501 double aux11 = array[ci[1] + 1][ci[2] + 1];
1502
1503 /* Interpolate horizontally... */
1504 if (isfinite(aux00) && isfinite(aux01)
1505 && isfinite(aux10) && isfinite(aux11)) {
1506 aux00 = cw[2] * (aux00 - aux01) + aux01;
1507 aux11 = cw[2] * (aux10 - aux11) + aux11;
1508 *var = cw[1] * (aux00 - aux11) + aux11;
1509 } else {
1510 if (cw[2] < 0.5) {
1511 if (cw[1] < 0.5)
1512 *var = aux11;
1513 else
1514 *var = aux01;
1515 } else {
1516 if (cw[1] < 0.5)
1517 *var = aux10;
1518 else
1519 *var = aux00;
1520 }
1521 }
1522}
1523
1524/*****************************************************************************/
1525
1527 const met_t *met0,
1528 float array0[EX][EY][EP],
1529 const met_t *met1,
1530 float array1[EX][EY][EP],
1531 const double ts,
1532 const double p,
1533 const double lon,
1534 const double lat,
1535 double *var,
1536 int *ci,
1537 double *cw,
1538 const int init) {
1539
1540 double var0, var1;
1541
1542 /* Spatial interpolation... */
1543 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
1544 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
1545
1546 /* Get weighting factor... */
1547 const double wt = (met1->time - ts) / (met1->time - met0->time);
1548
1549 /* Interpolate... */
1550 *var = wt * (var0 - var1) + var1;
1551}
1552
1553/*****************************************************************************/
1554
1556 const met_t *met0,
1557 float zs0[EX][EY][EP],
1558 float array0[EX][EY][EP],
1559 const met_t *met1,
1560 float zs1[EX][EY][EP],
1561 float array1[EX][EY][EP],
1562 const double ts,
1563 const double p,
1564 const double lon,
1565 const double lat,
1566 double *var) {
1567
1568 double var0, var1;
1569
1570 /* Spatial interpolation... */
1571 intpol_met_space_3d_ml(met0, zs0, array0, p, lon, lat, &var0);
1572 intpol_met_space_3d_ml(met1, zs1, array1, p, lon, lat, &var1);
1573
1574 /* Interpolate... */
1575 *var = LIN(met0->time, var0, met1->time, var1, ts);
1576}
1577
1578/*****************************************************************************/
1579
1581 const met_t *met0,
1582 float array0[EX][EY],
1583 const met_t *met1,
1584 float array1[EX][EY],
1585 const double ts,
1586 const double lon,
1587 const double lat,
1588 double *var,
1589 int *ci,
1590 double *cw,
1591 const int init) {
1592
1593 double var0, var1;
1594
1595 /* Spatial interpolation... */
1596 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
1597 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
1598
1599 /* Get weighting factor... */
1600 const double wt = (met1->time - ts) / (met1->time - met0->time);
1601
1602 /* Interpolate... */
1603 if (isfinite(var0) && isfinite(var1))
1604 *var = wt * (var0 - var1) + var1;
1605 else if (wt < 0.5)
1606 *var = var1;
1607 else
1608 *var = var0;
1609}
1610
1611/*****************************************************************************/
1612
1614 const double time0,
1615 float array0[EX][EY],
1616 const double time1,
1617 float array1[EX][EY],
1618 const double lons[EX],
1619 const double lats[EY],
1620 const int nlon,
1621 const int nlat,
1622 const double time,
1623 const double lon,
1624 const double lat,
1625 const int method,
1626 double *var,
1627 double *sigma) {
1628
1629 double aux0, aux1, aux00, aux01, aux10, aux11, mean = 0;
1630
1631 int n = 0;
1632
1633 /* Check longitude and latitude... */
1634 double lon2, lat2;
1635 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
1636
1637 /* Get indices... */
1638 const int ix = locate_reg(lons, (int) nlon, lon2);
1639 const int iy = locate_irr(lats, (int) nlat, lat2);
1640
1641 /* Calculate standard deviation... */
1642 *sigma = 0;
1643 for (int dx = 0; dx < 2; dx++)
1644 for (int dy = 0; dy < 2; dy++) {
1645 if (isfinite(array0[ix + dx][iy + dy])) {
1646 mean += array0[ix + dx][iy + dy];
1647 *sigma += SQR(array0[ix + dx][iy + dy]);
1648 n++;
1649 }
1650 if (isfinite(array1[ix + dx][iy + dy])) {
1651 mean += array1[ix + dx][iy + dy];
1652 *sigma += SQR(array1[ix + dx][iy + dy]);
1653 n++;
1654 }
1655 }
1656 if (n > 0)
1657 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
1658
1659 /* Linear interpolation... */
1660 if (method == 1 && isfinite(array0[ix][iy])
1661 && isfinite(array0[ix][iy + 1])
1662 && isfinite(array0[ix + 1][iy])
1663 && isfinite(array0[ix + 1][iy + 1])
1664 && isfinite(array1[ix][iy])
1665 && isfinite(array1[ix][iy + 1])
1666 && isfinite(array1[ix + 1][iy])
1667 && isfinite(array1[ix + 1][iy + 1])) {
1668
1669 aux00 = LIN(lons[ix], array0[ix][iy],
1670 lons[ix + 1], array0[ix + 1][iy], lon2);
1671 aux01 = LIN(lons[ix], array0[ix][iy + 1],
1672 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1673 aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1674
1675 aux10 = LIN(lons[ix], array1[ix][iy],
1676 lons[ix + 1], array1[ix + 1][iy], lon2);
1677 aux11 = LIN(lons[ix], array1[ix][iy + 1],
1678 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1679 aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1680
1681 *var = LIN(time0, aux0, time1, aux1, time);
1682 }
1683
1684 /* Nearest neighbor interpolation... */
1685 else {
1686 aux00 = NN(lons[ix], array0[ix][iy],
1687 lons[ix + 1], array0[ix + 1][iy], lon2);
1688 aux01 = NN(lons[ix], array0[ix][iy + 1],
1689 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1690 aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1691
1692 aux10 = NN(lons[ix], array1[ix][iy],
1693 lons[ix + 1], array1[ix + 1][iy], lon2);
1694 aux11 = NN(lons[ix], array1[ix][iy + 1],
1695 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1696 aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1697
1698 *var = NN(time0, aux0, time1, aux1, time);
1699 }
1700}
1701
1702/*****************************************************************************/
1703
1705 const double jsec,
1706 int *year,
1707 int *mon,
1708 int *day,
1709 int *hour,
1710 int *min,
1711 int *sec,
1712 double *remain) {
1713
1714 struct tm t0, *t1;
1715
1716 t0.tm_year = 100;
1717 t0.tm_mon = 0;
1718 t0.tm_mday = 1;
1719 t0.tm_hour = 0;
1720 t0.tm_min = 0;
1721 t0.tm_sec = 0;
1722
1723 const time_t jsec0 = (time_t) jsec + timegm(&t0);
1724 t1 = gmtime(&jsec0);
1725
1726 *year = t1->tm_year + 1900;
1727 *mon = t1->tm_mon + 1;
1728 *day = t1->tm_mday;
1729 *hour = t1->tm_hour;
1730 *min = t1->tm_min;
1731 *sec = t1->tm_sec;
1732 *remain = jsec - floor(jsec);
1733}
1734
1735/*****************************************************************************/
1736
1738 const double kz[EP],
1739 const double kw[EP],
1740 const int nk,
1741 const double p) {
1742
1743 /* Check number of data points... */
1744 if (nk < 2)
1745 return 1.0;
1746
1747 /* Get altitude... */
1748 const double z = Z(p);
1749
1750 /* Get weighting factor... */
1751 if (z < kz[0])
1752 return kw[0];
1753 else if (z > kz[nk - 1])
1754 return kw[nk - 1];
1755 else {
1756 int idx = locate_irr(kz, nk, z);
1757 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
1758 }
1759}
1760
1761/*****************************************************************************/
1762
1764 const double t,
1765 const double h2o) {
1766
1767 /*
1768 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
1769 and water vapor volume mixing ratio [1].
1770
1771 Reference: https://en.wikipedia.org/wiki/Lapse_rate
1772 */
1773
1774 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
1775
1776 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
1777}
1778
1779/*****************************************************************************/
1780
1782 ctl_t *ctl) {
1783
1784 if (0 == ctl->met_press_level_def) {
1785
1786 ctl->met_np = 138;
1787
1788 const double press[138] = {
1789 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1790 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1791 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1792 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1793 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1794 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1795 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1796 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1797 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1798 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1799 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1800 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1801 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1802 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1803 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1804 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1805 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1806 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1807 1010.8487, 1013.2500, 1044.45
1808 };
1809
1810 for (int ip = 0; ip < ctl->met_np; ip++)
1811 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1812
1813 } else if (1 == ctl->met_press_level_def) {
1814
1815 ctl->met_np = 92;
1816
1817 const double press[92] = {
1818 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1819 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1820 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1821 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1822 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1823 113.6382,
1824 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1825 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1826 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1827 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1828 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1829 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1830 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1831 1007.4431, 1010.8487, 1013.2500, 1044.45
1832 };
1833
1834 for (int ip = 0; ip < ctl->met_np; ip++)
1835 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1836
1837 } else if (2 == ctl->met_press_level_def) {
1838
1839 ctl->met_np = 60;
1840
1841 const double press[60] = {
1842 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1843 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1844 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1845 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1846 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1847 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1848 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1849 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1044.45
1850 };
1851
1852 for (int ip = 0; ip < ctl->met_np; ip++)
1853 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1854
1855 } else if (3 == ctl->met_press_level_def) {
1856
1857 ctl->met_np = 147;
1858
1859 const double press[147] = {
1860 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1861 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1862 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1863 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1864 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1865 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1866 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1867 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1868 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1869 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1870 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1871 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1872 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1873 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1874 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1875 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1876 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1877 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1878 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
1879 1031.97,
1880 1035.09, 1038.21, 1041.33, 1044.45
1881 };
1882
1883 for (int ip = 0; ip < ctl->met_np; ip++)
1884 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1885
1886 } else if (4 == ctl->met_press_level_def) {
1887
1888 ctl->met_np = 101;
1889
1890 const double press[101] = {
1891 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1892 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1893 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1894 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1895 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1896 113.6382,
1897 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1898 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1899 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1900 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1901 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1902 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1903 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1904 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
1905 1028.85, 1031.97,
1906 1035.09, 1038.21, 1041.33, 1044.45
1907 };
1908
1909 for (int ip = 0; ip < ctl->met_np; ip++)
1910 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1911
1912 } else if (5 == ctl->met_press_level_def) {
1913
1914 ctl->met_np = 62;
1915
1916 const double press[62] = {
1917 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1918 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1919 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1920 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1921 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1922 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1923 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1924 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
1925 1044.45
1926 };
1927
1928 for (int ip = 0; ip < ctl->met_np; ip++)
1929 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1930
1931 } else if (6 == ctl->met_press_level_def) {
1932
1933 ctl->met_np = 137;
1934
1935 const double press[137] = {
1936 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
1937 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
1938 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
1939 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
1940 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
1941 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1942 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
1943 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
1944 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
1945 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
1946 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
1947 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
1948 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
1949 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
1950 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
1951 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
1952 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
1953 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
1954 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
1955 1030.06, 1037.25, 1044.45
1956 };
1957
1958 for (int ip = 0; ip < ctl->met_np; ip++)
1959 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1960
1961 } else if (7 == ctl->met_press_level_def) {
1962
1963 ctl->met_np = 59;
1964
1965 const double press[59] = {
1966 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
1967 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
1968 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
1969 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
1970 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
1971 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
1972 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
1973 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
1974 1028.53, 1046.13
1975 };
1976
1977 for (int ip = 0; ip < ctl->met_np; ip++)
1978 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1979
1980 } else {
1981 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.");
1982 }
1983
1984 if (ctl->met_np > EP) {
1985 ERRMSG("Recompile with larger EP to use this pressure level definition.");
1986 }
1987}
1988
1989/*****************************************************************************/
1990
1992 const double *xx,
1993 const int n,
1994 const double x) {
1995
1996 int ilo = 0;
1997 int ihi = n - 1;
1998 int i = (ihi + ilo) >> 1;
1999
2000 if (xx[i] < xx[i + 1])
2001 while (ihi > ilo + 1) {
2002 i = (ihi + ilo) >> 1;
2003 if (xx[i] > x)
2004 ihi = i;
2005 else
2006 ilo = i;
2007 } else
2008 while (ihi > ilo + 1) {
2009 i = (ihi + ilo) >> 1;
2010 if (xx[i] <= x)
2011 ihi = i;
2012 else
2013 ilo = i;
2014 }
2015
2016 return ilo;
2017}
2018
2019/*****************************************************************************/
2020
2022 const float *xx,
2023 const int n,
2024 const double x,
2025 const int ig) {
2026
2027 int ilo = 0;
2028 int ihi = n - 1;
2029 int i = (ihi + ilo) >> 1;
2030
2031 if (x >= xx[ig] && x < xx[ig + 1])
2032 return ig;
2033
2034 if (xx[i] < xx[i + 1])
2035 while (ihi > ilo + 1) {
2036 i = (ihi + ilo) >> 1;
2037 if (xx[i] > x)
2038 ihi = i;
2039 else
2040 ilo = i;
2041 } else
2042 while (ihi > ilo + 1) {
2043 i = (ihi + ilo) >> 1;
2044 if (xx[i] <= x)
2045 ihi = i;
2046 else
2047 ilo = i;
2048 }
2049
2050 return ilo;
2051}
2052
2053/*****************************************************************************/
2054
2056 const double *xx,
2057 const int n,
2058 const double x) {
2059
2060 /* Calculate index... */
2061 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2062
2063 /* Check range... */
2064 if (i < 0)
2065 return 0;
2066 else if (i > n - 2)
2067 return n - 2;
2068 else
2069 return i;
2070}
2071
2072/*****************************************************************************/
2073
2075 float profiles[EX][EY][EP],
2076 const int np,
2077 const int lon_ap_ind,
2078 const int lat_ap_ind,
2079 const double height_ap,
2080 int *ind) {
2081
2082 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2083 np, height_ap, 0);
2084 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2085 np, height_ap, ind[0]);
2086 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2087 np, height_ap, ind[1]);
2088 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2089 np, height_ap, ind[2]);
2090}
2091
2092/*****************************************************************************/
2093
2095 const ctl_t *ctl,
2096 const cache_t *cache,
2097 met_t *met0,
2098 met_t *met1,
2099 atm_t *atm) {
2100
2101 /* Set timer... */
2102 SELECT_TIMER("MODULE_ADVECT", "PHYSICS", NVTX_GPU);
2103
2104 /* Use omega vertical velocity... */
2105 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2106
2107 /* Loop over particles... */
2108 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2109
2110 /* Init... */
2112 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2113 x[3] = { 0, 0, 0 };
2114
2115 /* Loop over integration nodes... */
2116 for (int i = 0; i < ctl->advect; i++) {
2117
2118 /* Set position... */
2119 if (i == 0) {
2120 dts = 0.0;
2121 x[0] = atm->lon[ip];
2122 x[1] = atm->lat[ip];
2123 x[2] = atm->p[ip];
2124 } else {
2125 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2126 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2127 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2128 x[2] = atm->p[ip] + dts * w[i - 1];
2129 }
2130 const double tm = atm->time[ip] + dts;
2131
2132 /* Interpolate meteo data on pressure levels... */
2133 if (ctl->advect_vert_coord == 0) {
2134 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2135 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2136 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2137 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2138 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2139 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2140 }
2141
2142 /* Interpolate meteo data on model levels... */
2143 else {
2144 intpol_met_time_3d_ml(met0, met0->pl, met0->ul,
2145 met1, met1->pl, met1->ul,
2146 tm, x[2], x[0], x[1], &u[i]);
2147 intpol_met_time_3d_ml(met0, met0->pl, met0->vl,
2148 met1, met1->pl, met1->vl,
2149 tm, x[2], x[0], x[1], &v[i]);
2150 intpol_met_time_3d_ml(met0, met0->pl, met0->wl,
2151 met1, met1->pl, met1->wl,
2152 tm, x[2], x[0], x[1], &w[i]);
2153 }
2154
2155 /* Get mean wind... */
2156 double k = 1.0;
2157 if (ctl->advect == 2)
2158 k = (i == 0 ? 0.0 : 1.0);
2159 else if (ctl->advect == 4)
2160 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2161 um += k * u[i];
2162 vm += k * v[i];
2163 wm += k * w[i];
2164 }
2165
2166 /* Set new position... */
2167 atm->time[ip] += cache->dt[ip];
2168 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2169 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2170 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2171 atm->p[ip] += cache->dt[ip] * wm;
2172 }
2173 }
2174
2175 /* Use zetadot vertical velocity... */
2176 else if (ctl->advect_vert_coord == 1) {
2177
2178 /* Loop over particles... */
2179 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2180
2181 /* Convert pressure to zeta... */
2183 intpol_met_4d_coord(met0, met0->pl, met0->zetal, met1,
2184 met1->pl, met1->zetal, atm->time[ip], atm->p[ip],
2185 atm->lon[ip], atm->lat[ip],
2186 &atm->q[ctl->qnt_zeta][ip], ci, cw, 1);
2187
2188 /* Init... */
2189 double dts, u[4], um = 0, v[4], vm = 0, zeta_dot[4],
2190 zeta_dotm = 0, x[3] = { 0, 0, 0 };
2191
2192 /* Loop over integration nodes... */
2193 for (int i = 0; i < ctl->advect; i++) {
2194
2195 /* Set position... */
2196 if (i == 0) {
2197 dts = 0.0;
2198 x[0] = atm->lon[ip];
2199 x[1] = atm->lat[ip];
2200 x[2] = atm->q[ctl->qnt_zeta][ip];
2201 } else {
2202 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2203 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2204 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2205 x[2] = atm->q[ctl->qnt_zeta][ip] + dts * zeta_dot[i - 1];
2206 }
2207 const double tm = atm->time[ip] + dts;
2208
2209 /* Interpolate meteo data... */
2210 intpol_met_4d_coord(met0, met0->zetal, met0->ul, met1, met1->zetal,
2211 met1->ul, tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2212 intpol_met_4d_coord(met0, met0->zetal, met0->vl, met1, met1->zetal,
2213 met1->vl, tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2214 intpol_met_4d_coord(met0, met0->zetal, met0->zeta_dotl, met1,
2215 met1->zetal, met1->zeta_dotl, tm, x[2], x[0],
2216 x[1], &zeta_dot[i], ci, cw, 0);
2217
2218 /* Get mean wind... */
2219 double k = 1.0;
2220 if (ctl->advect == 2)
2221 k = (i == 0 ? 0.0 : 1.0);
2222 else if (ctl->advect == 4)
2223 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2224 um += k * u[i];
2225 vm += k * v[i];
2226 zeta_dotm += k * zeta_dot[i];
2227 }
2228
2229 /* Set new position... */
2230 atm->time[ip] += cache->dt[ip];
2231 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2232 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2233 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2234 atm->q[ctl->qnt_zeta][ip] += cache->dt[ip] * zeta_dotm;
2235
2236 /* Convert zeta to pressure... */
2237 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2238 met1->pl, atm->time[ip],
2239 atm->q[ctl->qnt_zeta][ip], atm->lon[ip],
2240 atm->lat[ip], &atm->p[ip], ci, cw, 1);
2241 }
2242 }
2243}
2244
2245/*****************************************************************************/
2246
2248 const ctl_t *ctl,
2249 const cache_t *cache,
2250 met_t *met0,
2251 met_t *met1,
2252 atm_t *atm) {
2253
2254 /* Check parameters... */
2255 if (ctl->advect_vert_coord != 1)
2256 return;
2257
2258 /* Set timer... */
2259 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS", NVTX_GPU);
2260
2261 /* Loop over particles... */
2262 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
2263
2264 /* Initialize pressure consistent with zeta... */
2266 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2267 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2268 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2269 }
2270}
2271
2272/*****************************************************************************/
2273
2275 const ctl_t *ctl,
2276 const cache_t *cache,
2277 const clim_t *clim,
2278 met_t *met0,
2279 met_t *met1,
2280 atm_t *atm) {
2281
2282 /* Set timer... */
2283 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS", NVTX_GPU);
2284
2285 /* Check quantity flags... */
2286 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2287 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2288 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2289 return;
2290
2291 /* Loop over particles... */
2292 PARTICLE_LOOP(0, atm->np, 1,
2293 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2294
2295 /* Check latitude and pressure range... */
2296 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2297 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2298 continue;
2299
2300 /* Check surface layer... */
2301 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2302 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2303
2304 /* Get surface pressure... */
2305 double ps;
2307 INTPOL_2D(ps, 1);
2308
2309 /* Check pressure... */
2310 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2311 continue;
2312
2313 /* Check height... */
2314 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2315 continue;
2316
2317 /* Check zeta range... */
2318 if (ctl->bound_zetas > 0) {
2319 double t;
2320 INTPOL_3D(t, 1);
2321 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2322 continue;
2323 }
2324
2325 /* Check planetary boundary layer... */
2326 if (ctl->bound_pbl) {
2327 double pbl;
2328 INTPOL_2D(pbl, 0);
2329 if (atm->p[ip] < pbl)
2330 continue;
2331 }
2332 }
2333
2334 /* Set mass and volume mixing ratio... */
2335 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2336 atm->q[ctl->qnt_m][ip] =
2337 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2338 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2339 atm->q[ctl->qnt_vmr][ip] =
2340 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2341
2342 /* Set CFC-10 volume mixing ratio... */
2343 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2344 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2345
2346 /* Set CFC-11 volume mixing ratio... */
2347 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2348 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2349
2350 /* Set CFC-12 volume mixing ratio... */
2351 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2352 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2353
2354 /* Set N2O volume mixing ratio... */
2355 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2356 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2357
2358 /* Set SF6 volume mixing ratio... */
2359 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2360 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2361
2362 /* Set age of air... */
2363 if (ctl->qnt_aoa >= 0)
2364 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2365 }
2366}
2367
2368/*****************************************************************************/
2369
2371 const ctl_t *ctl,
2372 met_t *met0,
2373 met_t *met1,
2374 atm_t *atm,
2375 const double tt) {
2376
2377 /* Check quantities... */
2378 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
2379 return;
2380 if (ctl->molmass <= 0)
2381 ERRMSG("Molar mass is not defined!");
2382
2383 /* Set timer... */
2384 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS", NVTX_GPU);
2385
2386 /* Allocate... */
2387 const int ensemble_mode = (ctl->nens > 0);
2388 const int np = atm->np;
2389 const int nz = ctl->chemgrid_nz;
2390 const int nx = ctl->chemgrid_nx;
2391 const int ny = ctl->chemgrid_ny;
2392 const int ngrid = nx * ny * nz;
2393 const int nens = ensemble_mode ? ctl->nens : 1;
2394
2395 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2396 double *restrict const press =
2397 (double *) malloc((size_t) nz * sizeof(double));
2398 double *restrict const mass =
2399 (double *) calloc((size_t) ngrid * (size_t) nens, sizeof(double));
2400 double *restrict const area =
2401 (double *) malloc((size_t) ny * sizeof(double));
2402 double *restrict const lon =
2403 (double *) malloc((size_t) nx * sizeof(double));
2404 double *restrict const lat =
2405 (double *) malloc((size_t) ny * sizeof(double));
2406
2407 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2408 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2409 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2410
2411 /* Set grid box size... */
2412 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2413 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2414 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2415
2416 /* Set vertical coordinates... */
2417#ifdef _OPENACC
2418#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])
2419#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2420#pragma acc parallel loop independent gang vector
2421#else
2422#pragma omp parallel for default(shared)
2423#endif
2424 for (int iz = 0; iz < nz; iz++) {
2425 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2426 press[iz] = P(z[iz]);
2427 }
2428
2429 /* Set time interval for output... */
2430 const double t0 = tt - 0.5 * ctl->dt_mod;
2431 const double t1 = tt + 0.5 * ctl->dt_mod;
2432
2433 /* Get indices... */
2434#ifdef _OPENACC
2435#pragma acc parallel loop independent gang vector
2436#else
2437#pragma omp parallel for default(shared)
2438#endif
2439 for (int ip = 0; ip < np; ip++) {
2440 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2441 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2442 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2443 if (atm->time[ip] < t0 || atm->time[ip] > t1
2444 || ixs[ip] < 0 || ixs[ip] >= nx
2445 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2446 izs[ip] = -1;
2447 }
2448
2449 /* Set horizontal coordinates... */
2450#ifdef _OPENACC
2451#pragma acc parallel loop independent gang vector
2452#else
2453#pragma omp parallel for default(shared)
2454#endif
2455 for (int ix = 0; ix < nx; ix++)
2456 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
2457
2458#ifdef _OPENACC
2459#pragma acc parallel loop independent gang vector
2460#else
2461#pragma omp parallel for default(shared)
2462#endif
2463 for (int iy = 0; iy < ny; iy++) {
2464 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
2465 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
2466 }
2467
2468 /* Get mass per grid box... */
2469#ifdef _OPENACC
2470#pragma acc parallel loop independent gang vector
2471#endif
2472 for (int ip = 0; ip < np; ip++) {
2473 if (izs[ip] >= 0) {
2474 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
2475 if (ensemble_mode) {
2476 const int ens = (int) atm->q[ctl->qnt_ens][ip];
2477 mass_idx += ens * ngrid;
2478 }
2479#ifdef _OPENACC
2480#pragma acc atomic update
2481#endif
2482 mass[mass_idx] += atm->q[ctl->qnt_m][ip];
2483 }
2484 }
2485
2486 /* Assign grid data to air parcels ... */
2487#ifdef _OPENACC
2488#pragma acc parallel loop independent gang vector
2489#else
2490#pragma omp parallel for default(shared)
2491#endif
2492 for (int ip = 0; ip < np; ip++)
2493 if (izs[ip] >= 0) {
2494
2495 /* Interpolate temperature... */
2496 double temp;
2498 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt,
2499 press[izs[ip]],
2500 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
2501
2502 /* Set mass... */
2503 int mass_idx = ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz);
2504 if (ensemble_mode) {
2505 int ens = (int) atm->q[ctl->qnt_ens][ip];
2506 mass_idx += ens * ngrid;
2507 }
2508
2509 /* Calculate volume mixing ratio... */
2510 const double m = mass[mass_idx];
2511 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
2512 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
2513 }
2514
2515 /* Free... */
2516#ifdef _OPENACC
2517#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
2518#endif
2519 free(mass);
2520 free(lon);
2521 free(lat);
2522 free(area);
2523 free(z);
2524 free(press);
2525 free(ixs);
2526 free(iys);
2527 free(izs);
2528}
2529
2530/*****************************************************************************/
2531
2533 const ctl_t *ctl,
2534 const cache_t *cache,
2535 const clim_t *clim,
2536 met_t *met0,
2537 met_t *met1,
2538 atm_t *atm) {
2539
2540 /* Set timer... */
2541 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS", NVTX_GPU);
2542
2543 /* Loop over particles... */
2544 PARTICLE_LOOP(0, atm->np, 0,
2545 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2546
2547 /* Set H2O and O3 using meteo data... */
2549 if (ctl->qnt_Ch2o >= 0) {
2550 double h2o;
2551 INTPOL_3D(h2o, 1);
2552 SET_ATM(qnt_Ch2o, h2o);
2553 }
2554 if (ctl->qnt_Co3 >= 0) {
2555 double o3;
2556 INTPOL_3D(o3, 1);
2557 SET_ATM(qnt_Co3, o3);
2558 }
2559
2560 /* Set radical species... */
2561 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
2562 atm->lon[ip], atm->lat[ip], atm->p[ip]));
2563 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
2564 atm->lat[ip], atm->p[ip]));
2565 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
2566 atm->lat[ip], atm->p[ip]));
2567 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
2568 atm->lat[ip], atm->p[ip]));
2569 }
2570}
2571
2572/*****************************************************************************/
2573
2575 const ctl_t *ctl,
2576 cache_t *cache,
2577 met_t *met0,
2578 met_t *met1,
2579 atm_t *atm) {
2580
2581 /* Set timer... */
2582 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
2583
2584 /* Create random numbers... */
2585 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
2586
2587 /* Loop over particles... */
2588 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2589
2590 /* Interpolate CAPE... */
2591 double ps;
2593 INTPOL_2D(ps, 1);
2594
2595 /* Initialize pressure range for vertical mixing... */
2596 double pbot = ps, ptop = ps;
2597
2598 /* Mixing in the PBL... */
2599 if (ctl->conv_mix_pbl) {
2600
2601 /* Interpolate PBL... */
2602 double pbl;
2603 INTPOL_2D(pbl, 0);
2604
2605 /* Set pressure range... */
2606 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
2607 }
2608
2609 /* Convective mixing... */
2610 if (ctl->conv_cape >= 0) {
2611
2612 /* Interpolate CAPE, CIN, and equilibrium level... */
2613 double cape, cin, pel;
2614 INTPOL_2D(cape, 0);
2615 INTPOL_2D(cin, 0);
2616 INTPOL_2D(pel, 0);
2617
2618 /* Set pressure range... */
2619 if (isfinite(cape) && cape >= ctl->conv_cape
2620 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
2621 ptop = GSL_MIN(ptop, pel);
2622 }
2623
2624 /* Apply vertical mixing... */
2625 if (ptop != pbot && atm->p[ip] >= ptop) {
2626
2627 /* Get density range... */
2628 double tbot, ttop;
2629 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2630 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
2631 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip], ptop,
2632 atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
2633 const double rhobot = pbot / tbot;
2634 const double rhotop = ptop / ttop;
2635
2636 /* Get new density... */
2637 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
2638
2639 /* Get pressure... */
2640 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
2641 }
2642 }
2643}
2644
2645/*****************************************************************************/
2646
2648 const ctl_t *ctl,
2649 const cache_t *cache,
2650 const clim_t *clim,
2651 atm_t *atm) {
2652
2653 /* Set timer... */
2654 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
2655
2656 /* Check quantity flags... */
2657 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2658 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2659
2660 /* Loop over particles... */
2661 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
2662
2663 /* Get weighting factor... */
2664 const double w = tropo_weight(clim, atm, ip);
2665
2666 /* Set lifetime... */
2667 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
2668
2669 /* Calculate exponential decay... */
2670 const double aux = exp(-cache->dt[ip] / tdec);
2671 if (ctl->qnt_m >= 0) {
2672 if (ctl->qnt_mloss_decay >= 0)
2673 atm->q[ctl->qnt_mloss_decay][ip]
2674 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2675 atm->q[ctl->qnt_m][ip] *= aux;
2676 if (ctl->qnt_loss_rate >= 0)
2677 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
2678 }
2679 if (ctl->qnt_vmr >= 0)
2680 atm->q[ctl->qnt_vmr][ip] *= aux;
2681 }
2682}
2683
2684/*****************************************************************************/
2685
2687 const ctl_t *ctl,
2688 cache_t *cache,
2689 met_t *met0,
2690 met_t *met1,
2691 atm_t *atm) {
2692
2693 /* Set timer... */
2694 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS", NVTX_GPU);
2695
2696 /* Create random numbers... */
2697 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2698
2699 /* Loop over particles... */
2700 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2701
2702 /* Get indices... */
2703 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
2704 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
2705 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
2706
2707 /* Get standard deviations of local wind data... */
2708 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
2709 for (int i = 0; i < 2; i++)
2710 for (int j = 0; j < 2; j++)
2711 for (int k = 0; k < 2; k++) {
2712 umean += met0->u[ix + i][iy + j][iz + k];
2713 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
2714 vmean += met0->v[ix + i][iy + j][iz + k];
2715 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
2716 wmean += met0->w[ix + i][iy + j][iz + k];
2717 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
2718
2719 umean += met1->u[ix + i][iy + j][iz + k];
2720 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
2721 vmean += met1->v[ix + i][iy + j][iz + k];
2722 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
2723 wmean += met1->w[ix + i][iy + j][iz + k];
2724 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
2725 }
2726 usig = usig / 16.f - SQR(umean / 16.f);
2727 usig = (usig > 0 ? sqrtf(usig) : 0);
2728 vsig = vsig / 16.f - SQR(vmean / 16.f);
2729 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
2730 wsig = wsig / 16.f - SQR(wmean / 16.f);
2731 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
2732
2733 /* Set temporal correlations for mesoscale fluctuations... */
2734 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
2735 const double r2 = sqrt(1 - r * r);
2736
2737 /* Calculate horizontal mesoscale wind fluctuations... */
2738 if (ctl->turb_mesox > 0) {
2739 cache->uvwp[ip][0] =
2740 (float) (r * cache->uvwp[ip][0] +
2741 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
2742 atm->lon[ip] +=
2743 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2744
2745 cache->uvwp[ip][1] =
2746 (float) (r * cache->uvwp[ip][1] +
2747 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
2748 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2749 }
2750
2751 /* Calculate vertical mesoscale wind fluctuations... */
2752 if (ctl->turb_mesoz > 0) {
2753 cache->uvwp[ip][2] =
2754 (float) (r * cache->uvwp[ip][2] +
2755 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
2756 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
2757 }
2758 }
2759}
2760
2761/*****************************************************************************/
2762
2764 const ctl_t *ctl,
2765 cache_t *cache,
2766 met_t *met0,
2767 met_t *met1,
2768 atm_t *atm) {
2769
2770 /* Set timer... */
2771 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS", NVTX_GPU);
2772
2773 /* Create random numbers... */
2774 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2775
2776 /* Loop over particles... */
2777 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2778
2779 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
2780 tau_u = 300., tau_w = 100.;
2781
2782 /* Get surface and PBL pressure... */
2783 double pbl, ps;
2785 INTPOL_2D(ps, 1);
2786 INTPOL_2D(pbl, 0);
2787
2788 /* Boundary layer... */
2789 if (atm->p[ip] >= pbl) {
2790
2791 /* Calculate heights... */
2792 const double p = MIN(atm->p[ip], ps);
2793 const double zs = Z(ps);
2794 const double z = 1e3 * (Z(p) - zs);
2795 const double zi = 1e3 * (Z(pbl) - zs);
2796 const double zratio = z / zi;
2797
2798 /* Calculate friction velocity... */
2799 double ess, nss, h2o, t;
2800 INTPOL_2D(ess, 0);
2801 INTPOL_2D(nss, 0);
2802 INTPOL_3D(t, 1);
2803 INTPOL_3D(h2o, 0);
2804 const double rho = RHO(p, TVIRT(t, h2o));
2805 const double tau = sqrt(SQR(ess) + SQR(nss));
2806 const double ustar = sqrt(tau / rho);
2807
2808 /* Get surface sensible heat flux... */
2809 double shf;
2810 INTPOL_2D(shf, 1);
2811
2812 /* Stable or neutral conditions... */
2813 if (shf <= 0) {
2814
2815 /* Calcalute turbulent velocity variances... */
2816 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
2817 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
2818
2819 /* Calculate derivative dsig_w/dz... */
2820 dsigw_dz = -1.3 * ustar / zi;
2821
2822 /* Calcalute Lagrangian timescales... */
2823 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
2824 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
2825 }
2826
2827 /* Unstable conditions... */
2828 else {
2829
2830 /* Convective velocity... */
2831 const double wstar =
2832 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
2833
2834 /* Calcalute turbulent velocity variances... */
2835 sig_u = 1e-2
2836 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
2837 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
2838 * pow(zratio, 2.0 / 3.0)
2839 + (1.8 - 1.4 * zratio) * SQR(ustar));
2840
2841 /* Calculate derivative dsig_w/dz... */
2842 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
2843 * (0.8 *
2844 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
2845 - 1.8 * pow(zratio, 2.0 / 3.0)));
2846
2847 /* Calcalute Lagrangian timescales... */
2848 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
2849 const double eps =
2850 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
2851 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
2852 tau_u = 2 * SQR(sig_u) / (C0 * eps);
2853 tau_w = 2 * SQR(sig_w) / (C0 * eps);
2854 }
2855 }
2856
2857 /* Set minimum values... */
2858 sig_u = MAX(sig_u, 0.25);
2859 sig_w = MAX(sig_w, 0.1);
2860 tau_u = MAX(tau_u, 300.);
2861 tau_w = MAX(tau_w, 100.);
2862
2863 /* Update perturbations... */
2864 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
2865 const double ru2 = sqrt(1.0 - SQR(ru));
2866 cache->uvwp[ip][0]
2867 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
2868 cache->uvwp[ip][1]
2869 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
2870
2871 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
2872 const double rw2 = sqrt(1.0 - SQR(rw));
2873 cache->uvwp[ip][2]
2874 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
2875 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
2876
2877 /* Calculate new air parcel position... */
2878 atm->lon[ip] +=
2879 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2880 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2881 atm->p[ip] +=
2882 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
2883 }
2884}
2885
2886/*****************************************************************************/
2887
2889 const ctl_t *ctl,
2890 cache_t *cache,
2891 const clim_t *clim,
2892 met_t *met0,
2893 met_t *met1,
2894 atm_t *atm) {
2895
2896 /* Set timer... */
2897 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS", NVTX_GPU);
2898
2899 /* Create random numbers... */
2900 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2901
2902 /* Loop over particles... */
2903 PARTICLE_LOOP(0, atm->np, 1,
2904 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2905
2906 /* Get PBL and surface pressure... */
2907 double pbl, ps;
2909 INTPOL_2D(pbl, 1);
2910 INTPOL_2D(ps, 0);
2911
2912 /* Get weighting factors... */
2913 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
2914 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
2915 const double wstrat = 1.0 - wpbl - wtrop;
2916
2917 /* Set diffusivity... */
2918 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
2919 + wstrat * ctl->turb_dx_strat;
2920 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
2921 + wstrat * ctl->turb_dz_strat;
2922
2923 /* Horizontal turbulent diffusion... */
2924 if (dx > 0) {
2925 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
2926 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
2927 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
2928 }
2929
2930 /* Vertical turbulent diffusion... */
2931 if (dz > 0) {
2932 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
2933 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
2934 }
2935 }
2936}
2937
2938/*****************************************************************************/
2939
2941 const ctl_t *ctl,
2942 const cache_t *cache,
2943 met_t *met0,
2944 met_t *met1,
2945 atm_t *atm) {
2946
2947 /* Set timer... */
2948 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS", NVTX_GPU);
2949
2950 /* Check quantity flags... */
2951 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2952 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2953
2954 /* Loop over particles... */
2955 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2956
2957 /* Get surface pressure... */
2958 double ps;
2960 INTPOL_2D(ps, 1);
2961
2962 /* Check whether particle is above the surface layer... */
2963 if (atm->p[ip] < ps - ctl->dry_depo_dp)
2964 continue;
2965
2966 /* Set depth of surface layer... */
2967 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
2968
2969 /* Calculate sedimentation velocity for particles... */
2970 double v_dep;
2971 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
2972
2973 /* Get temperature... */
2974 double t;
2975 INTPOL_3D(t, 1);
2976
2977 /* Set deposition velocity... */
2978 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
2979 atm->q[ctl->qnt_rhop][ip]);
2980 }
2981
2982 /* Use explicit sedimentation velocity for gases... */
2983 else
2984 v_dep = ctl->dry_depo_vdep;
2985
2986 /* Calculate loss of mass based on deposition velocity... */
2987 const double aux = exp(-cache->dt[ip] * v_dep / dz);
2988 if (ctl->qnt_m >= 0) {
2989 if (ctl->qnt_mloss_dry >= 0)
2990 atm->q[ctl->qnt_mloss_dry][ip]
2991 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2992 atm->q[ctl->qnt_m][ip] *= aux;
2993 if (ctl->qnt_loss_rate >= 0)
2994 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
2995 }
2996 if (ctl->qnt_vmr >= 0)
2997 atm->q[ctl->qnt_vmr][ip] *= aux;
2998 }
2999}
3000
3001/*****************************************************************************/
3002
3004 const ctl_t *ctl,
3005 const cache_t *cache,
3006 const clim_t *clim,
3007 met_t *met0,
3008 met_t *met1,
3009 atm_t *atm) {
3010
3011 /* Set timer... */
3012 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS", NVTX_GPU);
3013
3014 /* Check quantity flags... */
3015 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3016 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3017
3018 /* Parameter of SO2 correction... */
3019 const double a = 3.12541941e-06;
3020 const double b = -5.72532259e-01;
3021 const double low = pow(1. / a, 1. / b);
3022
3023 /* Loop over particles... */
3024 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3025
3026 /* Check whether particle is inside cloud... */
3027 double lwc, rwc;
3029 INTPOL_3D(lwc, 1);
3030 INTPOL_3D(rwc, 0);
3031 if (!(lwc > 0 || rwc > 0))
3032 continue;
3033
3034 /* Get temperature... */
3035 double t;
3036 INTPOL_3D(t, 0);
3037
3038 /* Get molecular density... */
3039 const double M = MOLEC_DENS(atm->p[ip], t);
3040
3041 /* Reaction rate (Berglen et al., 2004)... */
3042 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3043
3044 /* Henry constant of SO2... */
3045 const double H_SO2 =
3046 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3047 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3048
3049 /* Henry constant of H2O2... */
3050 const double H_h2o2 =
3051 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3052
3053 /* Correction factor for high SO2 concentration
3054 (if qnt_Cx is defined, the correction is switched on)... */
3055 double cor = 1.0;
3056 if (ctl->qnt_Cx >= 0)
3057 cor = atm->q[ctl->qnt_Cx][ip] >
3058 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3059
3060 const double h2o2 = H_h2o2
3061 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3062 * M * cor * 1000. / AVO; /* unit: mol/L */
3063
3064 /* Volume water content in cloud [m^3 m^(-3)]... */
3065 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3066 const double CWC = (lwc + rwc) * rho_air / 1e3;
3067
3068 /* Calculate exponential decay (Rolph et al., 1992)... */
3069 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3070 const double aux = exp(-cache->dt[ip] * rate_coef);
3071 if (ctl->qnt_m >= 0) {
3072 if (ctl->qnt_mloss_h2o2 >= 0)
3073 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3074 atm->q[ctl->qnt_m][ip] *= aux;
3075 if (ctl->qnt_loss_rate >= 0)
3076 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3077 }
3078 if (ctl->qnt_vmr >= 0)
3079 atm->q[ctl->qnt_vmr][ip] *= aux;
3080 }
3081}
3082
3083/*****************************************************************************/
3084
3086 const ctl_t *ctl,
3087 cache_t *cache,
3088 met_t *met0,
3089 met_t *met1,
3090 atm_t *atm) {
3091
3092 double t;
3093
3094 /* Set timer... */
3095 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS", NVTX_GPU);
3096
3097 /* Save pressure... */
3098 if (ctl->isosurf == 1) {
3099 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
3100 cache->iso_var[ip] = atm->p[ip];
3101 }
3102 }
3103
3104 /* Save density... */
3105 else if (ctl->isosurf == 2) {
3106 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3108 INTPOL_3D(t, 1);
3109 cache->iso_var[ip] = atm->p[ip] / t;
3110 }
3111 }
3112
3113 /* Save potential temperature... */
3114 else if (ctl->isosurf == 3) {
3115 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3117 INTPOL_3D(t, 1);
3118 cache->iso_var[ip] = THETA(atm->p[ip], t);
3119 }
3120 }
3121
3122 /* Read balloon pressure data... */
3123 else if (ctl->isosurf == 4) {
3124
3125 /* Write info... */
3126 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3127
3128 /* Open file... */
3129 FILE *in;
3130 if (!(in = fopen(ctl->balloon, "r")))
3131 ERRMSG("Cannot open file!");
3132
3133 /* Read pressure time series... */
3134 char line[LEN];
3135 while (fgets(line, LEN, in))
3136 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3137 &(cache->iso_ps[cache->iso_n])) == 2)
3138 if ((++cache->iso_n) > NP)
3139 ERRMSG("Too many data points!");
3140
3141 /* Check number of points... */
3142 if (cache->iso_n < 1)
3143 ERRMSG("Could not read any data!");
3144
3145 /* Close file... */
3146 fclose(in);
3147
3148 /* Update of cache data on device... */
3149 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
3150 }
3151}
3152
3153/*****************************************************************************/
3154
3156 const ctl_t *ctl,
3157 const cache_t *cache,
3158 met_t *met0,
3159 met_t *met1,
3160 atm_t *atm) {
3161
3162 /* Set timer... */
3163 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3164
3165 /* Loop over particles... */
3166 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
3167
3168 /* Init... */
3169 double t;
3171
3172 /* Restore pressure... */
3173 if (ctl->isosurf == 1)
3174 atm->p[ip] = cache->iso_var[ip];
3175
3176 /* Restore density... */
3177 else if (ctl->isosurf == 2) {
3178 INTPOL_3D(t, 1);
3179 atm->p[ip] = cache->iso_var[ip] * t;
3180 }
3181
3182 /* Restore potential temperature... */
3183 else if (ctl->isosurf == 3) {
3184 INTPOL_3D(t, 1);
3185 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3186 }
3187
3188 /* Interpolate pressure... */
3189 else if (ctl->isosurf == 4) {
3190 if (atm->time[ip] <= cache->iso_ts[0])
3191 atm->p[ip] = cache->iso_ps[0];
3192 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3193 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3194 else {
3195 int idx = locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3196 atm->p[ip] = LIN(cache->iso_ts[idx], cache->iso_ps[idx],
3197 cache->iso_ts[idx + 1], cache->iso_ps[idx + 1],
3198 atm->time[ip]);
3199 }
3200 }
3201 }
3202}
3203
3204/*****************************************************************************/
3205
3206#ifdef KPP
3207void module_kpp_chem(
3208 ctl_t *ctl,
3209 cache_t *cache,
3210 clim_t *clim,
3211 met_t *met0,
3212 met_t *met1,
3213 atm_t *atm) {
3214
3215 /* Set timer... */
3216 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS", NVTX_GPU);
3217
3218 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
3219 double rtol[1] = { 1.0e-3 };
3220 double atol[1] = { 1.0 };
3221
3222 /* Loop over particles... */
3223#ifdef _OPENACC
3224#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
3225#endif
3226 PARTICLE_LOOP(0, atm->np, 1,
3227 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
3228
3229 /* Initialize... */
3230 double var[nvar], fix[nfix], rconst[nreact];
3231 for (int i = 0; i < nvar; i++)
3232 var[i] = 0.0;
3233 for (int i = 0; i < nfix; i++)
3234 fix[i] = 0.0;
3235 for (int i = 0; i < nreact; i++)
3236 rconst[i] = 0.0;
3237 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
3238
3239 /* Integrate... */
3240 double rpar[20];
3241 int ipar[20];
3242 for (int i = 0; i < 20; i++) {
3243 ipar[i] = 0;
3244 rpar[i] = 0.0;
3245 }
3246 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) */
3247 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
3248 ipar[3] = 4; /* choice of the method:Rodas3 */
3249 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
3250 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
3251
3252 /* Save results.. */
3253 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
3254 }
3255}
3256#endif
3257
3258/*****************************************************************************/
3259
3261 const ctl_t *ctl,
3262 const cache_t *cache,
3263 const clim_t *clim,
3264 met_t *met0,
3265 met_t *met1,
3266 atm_t *atm) {
3267
3268 /* Set timer... */
3269 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
3270
3271 /* Check quantity flags... */
3272 if (ctl->qnt_tsts >= 0)
3273 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3274 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3275
3276 /* Loop over particles... */
3277 PARTICLE_LOOP(0, atm->np, 0,
3278 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3279
3280 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb,
3281 cl, plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot,
3282 o3, lwc, rwc, iwc, swc, cc, z, zt;
3283
3284 /* Interpolate meteo data... */
3286 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3287
3288 /* Set quantities... */
3289 SET_ATM(qnt_ps, ps);
3290 SET_ATM(qnt_ts, ts);
3291 SET_ATM(qnt_zs, zs);
3292 SET_ATM(qnt_us, us);
3293 SET_ATM(qnt_vs, vs);
3294 SET_ATM(qnt_ess, ess);
3295 SET_ATM(qnt_nss, nss);
3296 SET_ATM(qnt_shf, shf);
3297 SET_ATM(qnt_lsm, lsm);
3298 SET_ATM(qnt_sst, sst);
3299 SET_ATM(qnt_pbl, pbl);
3300 SET_ATM(qnt_pt, pt);
3301 SET_ATM(qnt_tt, tt);
3302 SET_ATM(qnt_zt, zt);
3303 SET_ATM(qnt_h2ot, h2ot);
3304 SET_ATM(qnt_zg, z);
3305 SET_ATM(qnt_p, atm->p[ip]);
3306 SET_ATM(qnt_t, t);
3307 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3308 SET_ATM(qnt_u, u);
3309 SET_ATM(qnt_v, v);
3310 SET_ATM(qnt_w, w);
3311 SET_ATM(qnt_h2o, h2o);
3312 SET_ATM(qnt_o3, o3);
3313 SET_ATM(qnt_lwc, lwc);
3314 SET_ATM(qnt_rwc, rwc);
3315 SET_ATM(qnt_iwc, iwc);
3316 SET_ATM(qnt_swc, swc);
3317 SET_ATM(qnt_cc, cc);
3318 SET_ATM(qnt_pct, pct);
3319 SET_ATM(qnt_pcb, pcb);
3320 SET_ATM(qnt_cl, cl);
3321 SET_ATM(qnt_plcl, plcl);
3322 SET_ATM(qnt_plfc, plfc);
3323 SET_ATM(qnt_pel, pel);
3324 SET_ATM(qnt_cape, cape);
3325 SET_ATM(qnt_cin, cin);
3326 SET_ATM(qnt_o3c, o3c);
3327 SET_ATM(qnt_hno3,
3328 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3329 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3330 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3331 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3332 atm->lat[ip], atm->p[ip]));
3333 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3334 atm->lat[ip], atm->p[ip]));
3335 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3336 atm->lat[ip], atm->p[ip]));
3337 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3338 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3339 SET_ATM(qnt_psat, PSAT(t));
3340 SET_ATM(qnt_psice, PSICE(t));
3341 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3342 SET_ATM(qnt_sh, SH(h2o));
3343 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3344 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3345 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3346 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3347 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3348 SET_ATM(qnt_zeta_dot, atm->q[ctl->qnt_zeta_dot][ip]);
3349 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3350 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3351 SET_ATM(qnt_pv, pv);
3352 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3353 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3354 SET_ATM(qnt_tnat,
3355 nat_temperature(atm->p[ip], h2o,
3356 clim_zm(&clim->hno3, atm->time[ip],
3357 atm->lat[ip], atm->p[ip])));
3358 SET_ATM(qnt_tsts,
3359 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3360 }
3361}
3362
3363/*****************************************************************************/
3364
3366 const ctl_t *ctl,
3367 const clim_t *clim,
3368 atm_t *atm,
3369 const double t) {
3370
3371 /* Set timer... */
3372 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
3373
3374 /* Allocate... */
3375 const int np = atm->np;
3376 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3377 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3378 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3379
3380 /* Set grid box size... */
3381 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3382 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3383 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3384
3385 /* Set time interval... */
3386 const double t0 = t - 0.5 * ctl->dt_mod;
3387 const double t1 = t + 0.5 * ctl->dt_mod;
3388
3389 /* Get indices... */
3390#ifdef _OPENACC
3391#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3392#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3393#pragma acc parallel loop independent gang vector
3394#else
3395#pragma omp parallel for default(shared)
3396#endif
3397 for (int ip = 0; ip < np; ip++) {
3398 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3399 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3400 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3401 if (atm->time[ip] < t0 || atm->time[ip] > t1
3402 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3403 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3404 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3405 izs[ip] = -1;
3406 }
3407
3408 /* Calculate interparcel mixing... */
3409 const int use_ensemble = (ctl->nens > 0);
3410
3411 const int quantities[] = {
3412 ctl->qnt_m, ctl->qnt_vmr, ctl->qnt_Ch2o, ctl->qnt_Co3,
3413 ctl->qnt_Cco, ctl->qnt_Coh, ctl->qnt_Ch, ctl->qnt_Cho2,
3414 ctl->qnt_Ch2o2, ctl->qnt_Co1d, ctl->qnt_Co3p, ctl->qnt_Cccl4,
3415 ctl->qnt_Cccl3f, ctl->qnt_Cccl2f2, ctl->qnt_Cn2o,
3416 ctl->qnt_Csf6, ctl->qnt_aoa
3417 };
3418 const int n_qnt = sizeof(quantities) / sizeof(quantities[0]);
3419
3420 for (int i = 0; i < n_qnt; i++)
3421 if (quantities[i] >= 0)
3422 module_mixing_help(ctl, clim, atm, ixs, iys, izs, quantities[i],
3423 use_ensemble);
3424
3425 /* Free... */
3426#ifdef _OPENACC
3427#pragma acc exit data delete(ixs,iys,izs)
3428#endif
3429 free(ixs);
3430 free(iys);
3431 free(izs);
3432}
3433
3434/*****************************************************************************/
3435
3437 const ctl_t *ctl,
3438 const clim_t *clim,
3439 atm_t *atm,
3440 const int *ixs,
3441 const int *iys,
3442 const int *izs,
3443 const int qnt_idx,
3444 const int use_ensemble) {
3445
3446 const int np = atm->np;
3447 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
3448 const int nens = use_ensemble ? ctl->nens : 1;
3449 const int total_grid = ngrid * nens;
3450
3451 double *restrict const cmean =
3452 (double *) malloc((size_t) total_grid * sizeof(double));
3453 int *restrict const count =
3454 (int *) malloc((size_t) total_grid * sizeof(int));
3455
3456 /* Init... */
3457#ifdef _OPENACC
3458#pragma acc enter data create(cmean[0:total_grid],count[0:total_grid])
3459#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
3460#pragma acc parallel loop independent gang vector
3461#else
3462#ifdef __NVCOMPILER
3463#pragma novector
3464#endif
3465#pragma omp parallel for
3466#endif
3467 for (int i = 0; i < total_grid; i++) {
3468 count[i] = 0;
3469 cmean[i] = 0.0;
3470 }
3471
3472 /* Loop over particles... */
3473#ifdef _OPENACC
3474#pragma acc parallel loop independent gang vector
3475#endif
3476 for (int ip = 0; ip < np; ip++)
3477 if (izs[ip] >= 0) {
3478 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
3479 const int idx =
3480 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
3481 ctl->mixing_nz);
3482#ifdef _OPENACC
3483#pragma acc atomic update
3484#endif
3485 cmean[idx] += atm->q[qnt_idx][ip];
3486#ifdef _OPENACC
3487#pragma acc atomic update
3488#endif
3489 count[idx]++;
3490 }
3491
3492 /* Compute means... */
3493#ifdef _OPENACC
3494#pragma acc parallel loop independent gang vector
3495#else
3496#ifdef __NVCOMPILER
3497#pragma novector
3498#endif
3499#pragma omp parallel for
3500#endif
3501 for (int i = 0; i < total_grid; i++)
3502 if (count[i] > 0)
3503 cmean[i] /= count[i];
3504
3505 /* Interparcel mixing... */
3506#ifdef _OPENACC
3507#pragma acc parallel loop independent gang vector
3508#else
3509#pragma omp parallel for
3510#endif
3511 for (int ip = 0; ip < np; ip++) {
3512 if (izs[ip] >= 0) {
3513 const int ens = use_ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
3514
3515 double mixparam = 1.0;
3516 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
3517 const double w = tropo_weight(clim, atm, ip);
3518 mixparam = w * ctl->mixing_trop + (1.0 - w) * ctl->mixing_strat;
3519 }
3520
3521 const int idx =
3522 ens * ngrid + ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip],
3523 ctl->mixing_nz);
3524 atm->q[qnt_idx][ip] += (cmean[idx] - atm->q[qnt_idx][ip]) * mixparam;
3525 }
3526 }
3527
3528 /* Free... */
3529#ifdef _OPENACC
3530#pragma acc exit data delete(cmean,count)
3531#endif
3532 free(cmean);
3533 free(count);
3534}
3535
3536/*****************************************************************************/
3537
3539 const ctl_t *ctl,
3540 const cache_t *cache,
3541 const clim_t *clim,
3542 met_t *met0,
3543 met_t *met1,
3544 atm_t *atm) {
3545
3546 /* Set timer... */
3547 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS", NVTX_GPU);
3548
3549 /* Check quantity flags... */
3550 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3551 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3552
3553 /* Parameter of SO2 correction... */
3554 const double a = 4.71572206e-08;
3555 const double b = -8.28782867e-01;
3556 const double low = pow(1. / a, 1. / b);
3557
3558 /* Loop over particles... */
3559 PARTICLE_LOOP(0, atm->np, 1,
3560 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3561
3562 /* Get temperature... */
3563 double t;
3565 INTPOL_3D(t, 1);
3566
3567 /* Calculate molecular density... */
3568 const double M = MOLEC_DENS(atm->p[ip], t);
3569
3570 /* Use constant reaction rate... */
3571 double k = NAN;
3572 if (ctl->oh_chem_reaction == 1)
3573 k = ctl->oh_chem[0];
3574
3575 /* Calculate bimolecular reaction rate... */
3576 else if (ctl->oh_chem_reaction == 2)
3577 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
3578
3579 /* Calculate termolecular reaction rate... */
3580 if (ctl->oh_chem_reaction == 3) {
3581
3582 /* Calculate rate coefficient for X + OH + M -> XOH + M
3583 (JPL Publication 19-05) ... */
3584 const double k0 =
3585 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
3586 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
3587 const double ki =
3588 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
3589 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
3590 const double c = log10(k0 * M / ki);
3591 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
3592 }
3593
3594 /* Correction factor for high SO2 concentration
3595 (if qnt_Cx is defined, the correction is switched on)... */
3596 double cor = 1;
3597 if (ctl->qnt_Cx >= 0)
3598 cor =
3599 atm->q[ctl->qnt_Cx][ip] >
3600 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3601
3602 /* Calculate exponential decay... */
3603 const double rate_coef =
3604 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
3605 atm->lat[ip], atm->p[ip]) * M * cor;
3606 const double aux = exp(-cache->dt[ip] * rate_coef);
3607 if (ctl->qnt_m >= 0) {
3608 if (ctl->qnt_mloss_oh >= 0)
3609 atm->q[ctl->qnt_mloss_oh][ip]
3610 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3611 atm->q[ctl->qnt_m][ip] *= aux;
3612 if (ctl->qnt_loss_rate >= 0)
3613 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3614 }
3615 if (ctl->qnt_vmr >= 0)
3616 atm->q[ctl->qnt_vmr][ip] *= aux;
3617 }
3618}
3619
3620/*****************************************************************************/
3621
3623 const cache_t *cache,
3624 met_t *met0,
3625 met_t *met1,
3626 atm_t *atm) {
3627
3628 /* Set timer... */
3629 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
3630
3631 /* Loop over particles... */
3632 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
3633
3634 /* Init... */
3635 double ps;
3637
3638 /* Calculate modulo... */
3639 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
3640 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
3641
3642 /* Check latitude... */
3643 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
3644 if (atm->lat[ip] > 90) {
3645 atm->lat[ip] = 180 - atm->lat[ip];
3646 atm->lon[ip] += 180;
3647 }
3648 if (atm->lat[ip] < -90) {
3649 atm->lat[ip] = -180 - atm->lat[ip];
3650 atm->lon[ip] += 180;
3651 }
3652 }
3653
3654 /* Check longitude... */
3655 while (atm->lon[ip] < -180)
3656 atm->lon[ip] += 360;
3657 while (atm->lon[ip] >= 180)
3658 atm->lon[ip] -= 360;
3659
3660 /* Check pressure... */
3661 if (atm->p[ip] < met0->p[met0->np - 1]) {
3662 atm->p[ip] = met0->p[met0->np - 1];
3663 } else if (atm->p[ip] > 300.) {
3664 INTPOL_2D(ps, 1);
3665 if (atm->p[ip] > ps)
3666 atm->p[ip] = ps;
3667 }
3668 }
3669}
3670
3671/*****************************************************************************/
3672
3674 const int ntask) {
3675
3676 /* Initialize GSL random number generators... */
3677 gsl_rng_env_setup();
3678 if (omp_get_max_threads() > NTHREADS)
3679 ERRMSG("Too many threads!");
3680 for (int i = 0; i < NTHREADS; i++) {
3681 rng[i] = gsl_rng_alloc(gsl_rng_default);
3682 gsl_rng_set(rng[i], gsl_rng_default_seed
3683 + (long unsigned) (ntask * NTHREADS + i));
3684 }
3685
3686 /* Initialize cuRAND random number generators... */
3687#ifdef CURAND
3688 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
3689 CURAND_STATUS_SUCCESS)
3690 ERRMSG("Cannot create random number generator!");
3691 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
3692 CURAND_STATUS_SUCCESS)
3693 ERRMSG("Cannot set seed for random number generator!");
3694 if (curandSetStream
3695 (rng_curand,
3696 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
3697 CURAND_STATUS_SUCCESS)
3698 ERRMSG("Cannot set stream for random number generator!");
3699#endif
3700}
3701
3702/*****************************************************************************/
3703
3705 const ctl_t *ctl,
3706 double *rs,
3707 const size_t n,
3708 const int method) {
3709
3710 /* Use GSL random number generators... */
3711 if (ctl->rng_type == 0) {
3712
3713 /* Uniform distribution... */
3714 if (method == 0) {
3715#pragma omp parallel for default(shared)
3716 for (size_t i = 0; i < n; ++i)
3717 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
3718 }
3719
3720 /* Normal distribution... */
3721 else if (method == 1) {
3722#pragma omp parallel for default(shared)
3723 for (size_t i = 0; i < n; ++i)
3724 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
3725 }
3726
3727 /* Update of random numbers on device... */
3728#ifdef _OPENACC
3729 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
3730#pragma acc update device(rs[:n])
3731#endif
3732 }
3733
3734 /* Use Squares random number generator (Widynski, 2022)... */
3735 else if (ctl->rng_type == 1) {
3736
3737 /* Set key (don't change this!)... */
3738 const uint64_t key = 0xc8e4fd154ce32f6d;
3739
3740 /* Uniform distribution... */
3741#ifdef _OPENACC
3742#pragma acc data present(rs)
3743#pragma acc parallel loop independent gang vector
3744#else
3745#pragma omp parallel for default(shared)
3746#endif
3747 for (size_t i = 0; i < n + 1; ++i) {
3748 uint64_t r, t, x, y, z;
3749 y = x = (rng_ctr + i) * key;
3750 z = y + key;
3751 x = x * x + y;
3752 x = (x >> 32) | (x << 32);
3753 x = x * x + z;
3754 x = (x >> 32) | (x << 32);
3755 x = x * x + y;
3756 x = (x >> 32) | (x << 32);
3757 t = x = x * x + z;
3758 x = (x >> 32) | (x << 32);
3759 r = t ^ ((x * x + y) >> 32);
3760 rs[i] = (double) r / (double) UINT64_MAX;
3761 }
3762 rng_ctr += n + 1;
3763
3764 /* Normal distribution... */
3765 if (method == 1) {
3766#ifdef _OPENACC
3767#pragma acc parallel loop independent gang vector
3768#else
3769#pragma omp parallel for default(shared)
3770#endif
3771 for (size_t i = 0; i < n; i += 2) {
3772 const double r = sqrt(-2.0 * log(rs[i]));
3773 const double phi = 2.0 * M_PI * rs[i + 1];
3774 rs[i] = r * cosf((float) phi);
3775 rs[i + 1] = r * sinf((float) phi);
3776 }
3777 }
3778 }
3779
3780 /* Use cuRAND random number generators... */
3781 else if (ctl->rng_type == 2) {
3782#ifdef CURAND
3783#pragma acc host_data use_device(rs)
3784 {
3785
3786 /* Uniform distribution... */
3787 if (method == 0) {
3788 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
3789 CURAND_STATUS_SUCCESS)
3790 ERRMSG("Cannot create random numbers!");
3791 }
3792
3793 /* Normal distribution... */
3794 else if (method == 1) {
3795 if (curandGenerateNormalDouble
3796 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
3797 1.0) != CURAND_STATUS_SUCCESS)
3798 ERRMSG("Cannot create random numbers!");
3799 }
3800 }
3801#else
3802 ERRMSG("MPTRAC was compiled without cuRAND!");
3803#endif
3804 }
3805}
3806
3807/*****************************************************************************/
3808
3810 const ctl_t *ctl,
3811 const cache_t *cache,
3812 met_t *met0,
3813 met_t *met1,
3814 atm_t *atm) {
3815
3816 /* Set timer... */
3817 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
3818
3819 /* Loop over particles... */
3820 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3821
3822 /* Get temperature... */
3823 double t;
3825 INTPOL_3D(t, 1);
3826
3827 /* Sedimentation velocity... */
3828 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3829 atm->q[ctl->qnt_rhop][ip]);
3830
3831 /* Calculate pressure change... */
3832 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
3833 }
3834}
3835
3836/*****************************************************************************/
3837
3839 const ctl_t *ctl,
3840 met_t *met0,
3841 atm_t *atm) {
3842
3843 /* Set timer... */
3844 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
3845
3846 /* Allocate... */
3847 const int np = atm->np;
3848 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
3849 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
3850
3851#ifdef _OPENACC
3852#pragma acc enter data create(a[0:np],p[0:np])
3853#pragma acc data present(ctl,met0,atm,a,p)
3854#endif
3855
3856 /* Get box index... */
3857#ifdef _OPENACC
3858#pragma acc parallel loop independent gang vector
3859#else
3860#pragma omp parallel for default(shared)
3861#endif
3862 for (int ip = 0; ip < np; ip++) {
3863 a[ip] =
3864 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
3865 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
3866 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
3867 p[ip] = ip;
3868 }
3869
3870 /* Sorting... */
3871#ifdef _OPENACC
3872#pragma acc host_data use_device(a,p)
3873#endif
3874#ifdef THRUST
3875 thrustSortWrapper(a, np, p);
3876#else
3877 ERRMSG("MPTRAC was compiled without Thrust library!");
3878#endif
3879
3880 /* Sort data... */
3881 module_sort_help(atm->time, p, np);
3882 module_sort_help(atm->p, p, np);
3883 module_sort_help(atm->lon, p, np);
3884 module_sort_help(atm->lat, p, np);
3885 for (int iq = 0; iq < ctl->nq; iq++)
3886 module_sort_help(atm->q[iq], p, np);
3887
3888 /* Free... */
3889#ifdef _OPENACC
3890#pragma acc exit data delete(a,p)
3891#endif
3892 free(a);
3893 free(p);
3894}
3895
3896/*****************************************************************************/
3897
3899 double *a,
3900 const int *p,
3901 const int np) {
3902
3903 /* Allocate... */
3904 double *restrict const help =
3905 (double *) malloc((size_t) np * sizeof(double));
3906
3907 /* Reordering of array... */
3908#ifdef _OPENACC
3909#pragma acc enter data create(help[0:np])
3910#pragma acc data present(a,p,help)
3911#pragma acc parallel loop independent gang vector
3912#else
3913#pragma omp parallel for default(shared)
3914#endif
3915 for (int ip = 0; ip < np; ip++)
3916 help[ip] = a[p[ip]];
3917#ifdef _OPENACC
3918#pragma acc parallel loop independent gang vector
3919#else
3920#pragma omp parallel for default(shared)
3921#endif
3922 for (int ip = 0; ip < np; ip++)
3923 a[ip] = help[ip];
3924
3925 /* Free... */
3926#ifdef _OPENACC
3927#pragma acc exit data delete(help)
3928#endif
3929 free(help);
3930}
3931
3932/*****************************************************************************/
3933
3935 const ctl_t *ctl,
3936 cache_t *cache,
3937 met_t *met0,
3938 atm_t *atm,
3939 const double t) {
3940
3941 /* Set timer... */
3942 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
3943
3944 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
3945 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
3946
3947 const int local =
3948 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
3949
3950 /* Loop over particles... */
3951 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
3952
3953 /* Set time step for each air parcel... */
3954 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
3955 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
3956 && ctl->direction * (atm->time[ip] - t) < 0))
3957 cache->dt[ip] = t - atm->time[ip];
3958 else
3959 cache->dt[ip] = 0.0;
3960
3961 /* Check horizontal boundaries of local meteo data... */
3962#ifndef DD
3963 if (local && (atm->lon[ip] <= met0->lon[0]
3964 || atm->lon[ip] >= met0->lon[met0->nx - 1]
3965 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
3966 cache->dt[ip] = 0.0;
3967#else
3968 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
3969 cache->dt[ip] = 0;
3970#endif
3971 }
3972}
3973
3974/*****************************************************************************/
3975
3977 ctl_t *ctl,
3978 const atm_t *atm) {
3979
3980 /* Set timer... */
3981 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS", NVTX_GPU);
3982
3983 /* Set start time... */
3984 if (ctl->direction == 1) {
3985 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3986 if (ctl->t_stop > 1e99)
3987 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3988 } else {
3989 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3990 if (ctl->t_stop > 1e99)
3991 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3992 }
3993
3994 /* Check time interval... */
3995 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
3996 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
3997
3998 /* Round start time... */
3999 if (ctl->direction == 1)
4000 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4001 else
4002 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4003}
4004
4005/*****************************************************************************/
4006
4008 const ctl_t *ctl,
4009 const cache_t *cache,
4010 const clim_t *clim,
4011 met_t *met0,
4012 met_t *met1,
4013 atm_t *atm) {
4014
4015 /* Set timer... */
4016 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS", NVTX_GPU);
4017
4018 /* Loop over particles... */
4019 PARTICLE_LOOP(0, atm->np, 1,
4020 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4021
4022 /* Get temperature... */
4023 double t;
4025 INTPOL_3D(t, 1);
4026
4027 /* Get molecular density... */
4028 const double M = MOLEC_DENS(atm->p[ip], t);
4029
4030 /* Get total column ozone... */
4031 double o3c;
4032 INTPOL_2D(o3c, 1);
4033
4034 /* Get solar zenith angle... */
4035 const double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
4036
4037 /* Get O(1D) volume mixing ratio... */
4038 const double o1d =
4039 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4040
4041 /* Reactions for CFC-10... */
4042 if (ctl->qnt_Cccl4 >= 0) {
4043 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4044 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4045 atm->p[ip], sza, o3c);
4046 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4047 }
4048
4049 /* Reactions for CFC-11... */
4050 if (ctl->qnt_Cccl3f >= 0) {
4051 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4052 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4053 atm->p[ip], sza, o3c);
4054 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4055 }
4056
4057 /* Reactions for CFC-12... */
4058 if (ctl->qnt_Cccl2f2 >= 0) {
4059 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4060 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4061 atm->p[ip], sza, o3c);
4062 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4063 }
4064
4065 /* Reactions for N2O... */
4066 if (ctl->qnt_Cn2o >= 0) {
4067 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4068 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4069 atm->p[ip], sza, o3c);
4070 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4071 }
4072 }
4073}
4074
4075/*****************************************************************************/
4076
4078 const ctl_t *ctl,
4079 const cache_t *cache,
4080 met_t *met0,
4081 met_t *met1,
4082 atm_t *atm) {
4083
4084 /* Set timer... */
4085 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS", NVTX_GPU);
4086
4087 /* Check quantity flags... */
4088 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4089 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4090
4091 /* Loop over particles... */
4092 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4093
4094 /* Check whether particle is below cloud top... */
4095 double pct;
4097 INTPOL_2D(pct, 1);
4098 if (!isfinite(pct) || atm->p[ip] <= pct)
4099 continue;
4100
4101 /* Get cloud bottom pressure... */
4102 double pcb;
4103 INTPOL_2D(pcb, 0);
4104
4105 /* Estimate precipitation rate (Pisso et al., 2019)... */
4106 double cl;
4107 INTPOL_2D(cl, 0);
4108 const double Is =
4109 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4110 if (Is < 0.01)
4111 continue;
4112
4113 /* Check whether particle is inside or below cloud... */
4114 double lwc, rwc, iwc, swc;
4115 INTPOL_3D(lwc, 1);
4116 INTPOL_3D(rwc, 0);
4117 INTPOL_3D(iwc, 0);
4118 INTPOL_3D(swc, 0);
4119 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4120
4121 /* Get temperature... */
4122 double t;
4123 INTPOL_3D(t, 0);
4124
4125 /* Calculate in-cloud scavenging coefficient... */
4126 double lambda = 0;
4127 if (inside) {
4128
4129 /* Calculate retention factor... */
4130 double eta;
4131 if (t > 273.15)
4132 eta = 1;
4133 else if (t <= 238.15)
4134 eta = ctl->wet_depo_ic_ret_ratio;
4135 else
4136 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4137
4138 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4139 if (ctl->wet_depo_ic_a > 0)
4140 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4141
4142 /* Use Henry's law for gases... */
4143 else if (ctl->wet_depo_ic_h[0] > 0) {
4144
4145 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4146 double h = ctl->wet_depo_ic_h[0]
4147 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4148
4149 /* Use effective Henry's constant for SO2
4150 (Berglen, 2004; Simpson, 2012)... */
4151 if (ctl->wet_depo_so2_ph > 0) {
4152 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
4153 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4154 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4155 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
4156 }
4157
4158 /* Estimate depth of cloud layer... */
4159 const double dz = 1e3 * (Z(pct) - Z(pcb));
4160
4161 /* Calculate scavenging coefficient... */
4162 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4163 }
4164 }
4165
4166 /* Calculate below-cloud scavenging coefficient... */
4167 else {
4168
4169 /* Calculate retention factor... */
4170 double eta;
4171 if (t > 270)
4172 eta = 1;
4173 else
4174 eta = ctl->wet_depo_bc_ret_ratio;
4175
4176 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4177 if (ctl->wet_depo_bc_a > 0)
4178 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4179
4180 /* Use Henry's law for gases... */
4181 else if (ctl->wet_depo_bc_h[0] > 0) {
4182
4183 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4184 const double h = ctl->wet_depo_bc_h[0]
4185 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4186
4187 /* Estimate depth of cloud layer... */
4188 const double dz = 1e3 * (Z(pct) - Z(pcb));
4189
4190 /* Calculate scavenging coefficient... */
4191 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4192 }
4193 }
4194
4195 /* Calculate exponential decay of mass... */
4196 const double aux = exp(-cache->dt[ip] * lambda);
4197 if (ctl->qnt_m >= 0) {
4198 if (ctl->qnt_mloss_wet >= 0)
4199 atm->q[ctl->qnt_mloss_wet][ip]
4200 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4201 atm->q[ctl->qnt_m][ip] *= aux;
4202 if (ctl->qnt_loss_rate >= 0)
4203 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4204 }
4205 if (ctl->qnt_vmr >= 0)
4206 atm->q[ctl->qnt_vmr][ip] *= aux;
4207 }
4208}
4209
4210/*****************************************************************************/
4211
4213 ctl_t **ctl,
4214 cache_t **cache,
4215 clim_t **clim,
4216 met_t **met0,
4217 met_t **met1,
4218 atm_t **atm) {
4219
4220 /* Initialize GPU... */
4221#ifdef _OPENACC
4222 SELECT_TIMER("ACC_INIT", "INIT", NVTX_GPU);
4223 int rank = 0;
4224#ifdef MPI
4225 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
4226#endif
4227 if (acc_get_num_devices(acc_device_nvidia) <= 0)
4228 ERRMSG("Not running on a GPU device!");
4229 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
4230 acc_device_nvidia);
4231 acc_device_t device_type = acc_get_device_type();
4232 acc_init(device_type);
4233#endif
4234
4235 /* Allocate... */
4236 SELECT_TIMER("ALLOC", "MEMORY", NVTX_CPU);
4237 ALLOC(*ctl, ctl_t, 1);
4238 ALLOC(*cache, cache_t, 1);
4239 ALLOC(*clim, clim_t, 1);
4240 ALLOC(*met0, met_t, 1);
4241 ALLOC(*met1, met_t, 1);
4242 ALLOC(*atm, atm_t, 1);
4243
4244 /* Create data region on GPU... */
4245#ifdef _OPENACC
4246 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY", NVTX_GPU);
4247 ctl_t *ctlup = *ctl;
4248 cache_t *cacheup = *cache;
4249 clim_t *climup = *clim;
4250 met_t *met0up = *met0;
4251 met_t *met1up = *met1;
4252 atm_t *atmup = *atm;
4253#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
4254#endif
4255}
4256
4257/*****************************************************************************/
4258
4259#ifdef DD
4260void mptrac_free(
4261 ctl_t *ctl,
4262 cache_t *cache,
4263 clim_t *clim,
4264 met_t *met0,
4265 met_t *met1,
4266 atm_t *atm,
4267 mpi_info_t *mpi_info) {
4268#else
4270 ctl_t *ctl,
4271 cache_t *cache,
4272 clim_t *clim,
4273 met_t *met0,
4274 met_t *met1,
4275 atm_t *atm) {
4276#endif
4277
4278 /* Delete data region on GPU... */
4279#ifdef _OPENACC
4280 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY", NVTX_GPU);
4281#pragma acc exit data delete (ctl,cache,clim,met0,met1,atm)
4282#endif
4283
4284 /* Free... */
4285 SELECT_TIMER("FREE", "MEMORY", NVTX_CPU);
4286 free(atm);
4287 free(ctl);
4288 free(cache);
4289 free(clim);
4290 free(met0);
4291 free(met1);
4292
4293 /* Free MPI datatype... */
4294#ifdef DD
4295 MPI_Type_free(&mpi_info->MPI_Particle);
4296#endif
4297}
4298
4299/*****************************************************************************/
4300
4302 ctl_t *ctl,
4303 clim_t *clim,
4304 const double t,
4305 met_t **met0,
4306 met_t **met1) {
4307
4308 static int init;
4309
4310 met_t *mets;
4311
4312 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
4313
4314 /* Set timer... */
4315 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4316
4317 /* Init... */
4318 if (t == ctl->t_start || !init) {
4319 init = 1;
4320
4321 /* Read meteo data... */
4322 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
4323 ctl->metbase, ctl->dt_met, filename);
4324 if (!mptrac_read_met(filename, ctl, clim, *met0))
4325 ERRMSG("Cannot open file!");
4326
4327 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
4328 ctl->metbase, ctl->dt_met, filename);
4329 if (!mptrac_read_met(filename, ctl, clim, *met1))
4330 ERRMSG("Cannot open file!");
4331
4332 /* Update GPU... */
4333 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
4334 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4335
4336 /* Caching... */
4337 if (ctl->met_cache && t != ctl->t_stop) {
4338 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
4339 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
4340 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4341 LOG(1, "Caching: %s", cachefile);
4342 if (system(cmd) != 0)
4343 WARN("Caching command failed!");
4344 }
4345 }
4346
4347 /* Read new data for forward trajectories... */
4348 if (t > (*met1)->time) {
4349
4350 /* Pointer swap... */
4351 mets = *met1;
4352 *met1 = *met0;
4353 *met0 = mets;
4354
4355 /* Read new meteo data... */
4356 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
4357 if (!mptrac_read_met(filename, ctl, clim, *met1))
4358 ERRMSG("Cannot open file!");
4359
4360 /* Update GPU... */
4361 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
4362 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4363
4364 /* Caching... */
4365 if (ctl->met_cache && t != ctl->t_stop) {
4366 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
4367 cachefile);
4368 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4369 LOG(1, "Caching: %s", cachefile);
4370 if (system(cmd) != 0)
4371 WARN("Caching command failed!");
4372 }
4373 }
4374
4375 /* Read new data for backward trajectories... */
4376 if (t < (*met0)->time) {
4377
4378 /* Pointer swap... */
4379 mets = *met1;
4380 *met1 = *met0;
4381 *met0 = mets;
4382
4383 /* Read new meteo data... */
4384 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
4385 if (!mptrac_read_met(filename, ctl, clim, *met0))
4386 ERRMSG("Cannot open file!");
4387
4388 /* Update GPU... */
4389 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
4390 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4391
4392 /* Caching... */
4393 if (ctl->met_cache && t != ctl->t_stop) {
4394 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
4395 cachefile);
4396 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4397 LOG(1, "Caching: %s", cachefile);
4398 if (system(cmd) != 0)
4399 WARN("Caching command failed!");
4400 }
4401 }
4402
4403 /* Check that grids are consistent... */
4404 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
4405 if ((*met0)->nx != (*met1)->nx
4406 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
4407 ERRMSG("Meteo grid dimensions do not match!");
4408 for (int ix = 0; ix < (*met0)->nx; ix++)
4409 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
4410 ERRMSG("Meteo grid longitudes do not match!");
4411 for (int iy = 0; iy < (*met0)->ny; iy++)
4412 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
4413 ERRMSG("Meteo grid latitudes do not match!");
4414 for (int ip = 0; ip < (*met0)->np; ip++)
4415 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
4416 ERRMSG("Meteo grid pressure levels do not match!");
4417 }
4418}
4419
4420/*****************************************************************************/
4421
4423 ctl_t *ctl,
4424 cache_t *cache,
4425 clim_t *clim,
4426 atm_t *atm,
4427 const int ntask) {
4428
4429 /* Initialize timesteps... */
4430 module_timesteps_init(ctl, atm);
4431
4432 /* Initialize random number generator... */
4433 module_rng_init(ntask);
4434
4435 /* Update GPU memory... */
4436 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
4437}
4438
4439/*****************************************************************************/
4440
4442 const char *filename,
4443 const ctl_t *ctl,
4444 atm_t *atm) {
4445
4446 int result;
4447
4448 /* Set timer... */
4449 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
4450
4451 /* Init... */
4452 atm->np = 0;
4453
4454 /* Write info... */
4455 LOG(1, "Read atmospheric data: %s", filename);
4456
4457 /* Read ASCII data... */
4458 if (ctl->atm_type == 0)
4459 result = read_atm_asc(filename, ctl, atm);
4460
4461 /* Read binary data... */
4462 else if (ctl->atm_type == 1)
4463 result = read_atm_bin(filename, ctl, atm);
4464
4465 /* Read netCDF data... */
4466 else if (ctl->atm_type == 2)
4467 result = read_atm_nc(filename, ctl, atm);
4468
4469 /* Read CLaMS data... */
4470 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
4471 result = read_atm_clams(filename, ctl, atm);
4472
4473 /* Error... */
4474 else
4475 ERRMSG("Atmospheric data type not supported!");
4476
4477 /* Check result... */
4478 if (result != 1)
4479 return 0;
4480
4481 /* Check number of air parcels... */
4482 if (atm->np < 1)
4483 ERRMSG("Can not read any data!");
4484
4485 /* Write info... */
4486 double mini, maxi;
4487 LOG(2, "Number of particles: %d", atm->np);
4488 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
4489 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
4490 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
4491 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
4492 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
4493 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
4494 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
4495 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
4496 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
4497 for (int iq = 0; iq < ctl->nq; iq++) {
4498 char msg[5 * LEN];
4499 sprintf(msg, "Quantity %s range: %s ... %s %s",
4500 ctl->qnt_name[iq], ctl->qnt_format[iq],
4501 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
4502 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
4503 LOG(2, msg, mini, maxi);
4504 }
4505
4506 /* Return success... */
4507 return 1;
4508}
4509
4510/*****************************************************************************/
4511
4513 const ctl_t *ctl,
4514 clim_t *clim) {
4515
4516 /* Set timer... */
4517 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
4518
4519 /* Init tropopause climatology... */
4520 clim_tropo_init(clim);
4521
4522 /* Read photolysis rates... */
4523 if (ctl->clim_photo[0] != '-')
4524 read_clim_photo(ctl->clim_photo, &clim->photo);
4525
4526 /* Read HNO3 climatology... */
4527 if (ctl->clim_hno3_filename[0] != '-')
4528 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
4529
4530 /* Read OH climatology... */
4531 if (ctl->clim_oh_filename[0] != '-') {
4532 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
4533 if (ctl->oh_chem_beta > 0)
4534 clim_oh_diurnal_correction(ctl, clim);
4535 }
4536
4537 /* Read H2O2 climatology... */
4538 if (ctl->clim_h2o2_filename[0] != '-')
4539 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
4540
4541 /* Read HO2 climatology... */
4542 if (ctl->clim_ho2_filename[0] != '-')
4543 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
4544
4545 /* Read O(1D) climatology... */
4546 if (ctl->clim_o1d_filename[0] != '-')
4547 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
4548
4549 /* Read CFC-10 time series... */
4550 if (ctl->clim_ccl4_timeseries[0] != '-')
4552
4553 /* Read CFC-11 time series... */
4554 if (ctl->clim_ccl3f_timeseries[0] != '-')
4556
4557 /* Read CFC-12 time series... */
4558 if (ctl->clim_ccl2f2_timeseries[0] != '-')
4560
4561 /* Read N2O time series... */
4562 if (ctl->clim_n2o_timeseries[0] != '-')
4563 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
4564
4565 /* Read SF6 time series... */
4566 if (ctl->clim_sf6_timeseries[0] != '-')
4567 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
4568}
4569
4570/*****************************************************************************/
4571
4573 const char *filename,
4574 int argc,
4575 char *argv[],
4576 ctl_t *ctl) {
4577
4578 /* Set timer... */
4579 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
4580
4581 /* Write info... */
4582 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
4583 "(executable: %s | version: %s | compiled: %s, %s)\n",
4584 argv[0], VERSION, __DATE__, __TIME__);
4585
4586 /* Initialize quantity indices... */
4587 ctl->qnt_idx = -1;
4588 ctl->qnt_ens = -1;
4589 ctl->qnt_stat = -1;
4590 ctl->qnt_m = -1;
4591 ctl->qnt_vmr = -1;
4592 ctl->qnt_rp = -1;
4593 ctl->qnt_rhop = -1;
4594 ctl->qnt_ps = -1;
4595 ctl->qnt_ts = -1;
4596 ctl->qnt_zs = -1;
4597 ctl->qnt_us = -1;
4598 ctl->qnt_vs = -1;
4599 ctl->qnt_ess = -1;
4600 ctl->qnt_nss = -1;
4601 ctl->qnt_shf = -1;
4602 ctl->qnt_lsm = -1;
4603 ctl->qnt_sst = -1;
4604 ctl->qnt_pbl = -1;
4605 ctl->qnt_pt = -1;
4606 ctl->qnt_tt = -1;
4607 ctl->qnt_zt = -1;
4608 ctl->qnt_h2ot = -1;
4609 ctl->qnt_zg = -1;
4610 ctl->qnt_p = -1;
4611 ctl->qnt_t = -1;
4612 ctl->qnt_rho = -1;
4613 ctl->qnt_u = -1;
4614 ctl->qnt_v = -1;
4615 ctl->qnt_w = -1;
4616 ctl->qnt_h2o = -1;
4617 ctl->qnt_o3 = -1;
4618 ctl->qnt_lwc = -1;
4619 ctl->qnt_rwc = -1;
4620 ctl->qnt_iwc = -1;
4621 ctl->qnt_swc = -1;
4622 ctl->qnt_cc = -1;
4623 ctl->qnt_pct = -1;
4624 ctl->qnt_pcb = -1;
4625 ctl->qnt_cl = -1;
4626 ctl->qnt_plcl = -1;
4627 ctl->qnt_plfc = -1;
4628 ctl->qnt_pel = -1;
4629 ctl->qnt_cape = -1;
4630 ctl->qnt_cin = -1;
4631 ctl->qnt_o3c = -1;
4632 ctl->qnt_hno3 = -1;
4633 ctl->qnt_oh = -1;
4634 ctl->qnt_h2o2 = -1;
4635 ctl->qnt_ho2 = -1;
4636 ctl->qnt_o1d = -1;
4637 ctl->qnt_mloss_oh = -1;
4638 ctl->qnt_mloss_h2o2 = -1;
4639 ctl->qnt_mloss_kpp = -1;
4640 ctl->qnt_mloss_wet = -1;
4641 ctl->qnt_mloss_dry = -1;
4642 ctl->qnt_mloss_decay = -1;
4643 ctl->qnt_loss_rate = -1;
4644 ctl->qnt_psat = -1;
4645 ctl->qnt_psice = -1;
4646 ctl->qnt_pw = -1;
4647 ctl->qnt_sh = -1;
4648 ctl->qnt_rh = -1;
4649 ctl->qnt_rhice = -1;
4650 ctl->qnt_theta = -1;
4651 ctl->qnt_zeta = -1;
4652 ctl->qnt_zeta_d = -1;
4653 ctl->qnt_zeta_dot = -1;
4654 ctl->qnt_tvirt = -1;
4655 ctl->qnt_lapse = -1;
4656 ctl->qnt_vh = -1;
4657 ctl->qnt_vz = -1;
4658 ctl->qnt_pv = -1;
4659 ctl->qnt_tdew = -1;
4660 ctl->qnt_tice = -1;
4661 ctl->qnt_tsts = -1;
4662 ctl->qnt_tnat = -1;
4663 ctl->qnt_Cx = -1;
4664 ctl->qnt_Ch2o = -1;
4665 ctl->qnt_Co3 = -1;
4666 ctl->qnt_Cco = -1;
4667 ctl->qnt_Coh = -1;
4668 ctl->qnt_Ch = -1;
4669 ctl->qnt_Cho2 = -1;
4670 ctl->qnt_Ch2o2 = -1;
4671 ctl->qnt_Co1d = -1;
4672 ctl->qnt_Co3p = -1;
4673 ctl->qnt_Cccl4 = -1;
4674 ctl->qnt_Cccl3f = -1;
4675 ctl->qnt_Cccl2f2 = -1;
4676 ctl->qnt_Cn2o = -1;
4677 ctl->qnt_Csf6 = -1;
4678 ctl->qnt_aoa = -1;
4679
4680#ifdef DD
4681 ctl->qnt_destination = -1;
4682 ctl->qnt_subdomain = -1;
4683#endif
4684
4685 /* Read quantities... */
4686 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
4687 if (ctl->nq > NQ)
4688 ERRMSG("Too many quantities!");
4689 for (int iq = 0; iq < ctl->nq; iq++) {
4690
4691 /* Read quantity name and format... */
4692 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
4693 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
4694 ctl->qnt_longname[iq]);
4695 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
4696 ctl->qnt_format[iq]);
4697 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
4698 sprintf(ctl->qnt_format[iq], "%%.2f");
4699
4700 /* Try to identify quantity... */
4701 SET_QNT(qnt_idx, "idx", "particle index", "-")
4702 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
4703 SET_QNT(qnt_stat, "stat", "station flag", "-")
4704 SET_QNT(qnt_m, "m", "mass", "kg")
4705 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
4706 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
4707 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
4708 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
4709 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
4710 SET_QNT(qnt_zs, "zs", "surface height", "km")
4711 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
4712 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
4713 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
4714 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
4715 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
4716 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
4717 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
4718 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
4719 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
4720 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
4721 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
4722 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
4723 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
4724 SET_QNT(qnt_p, "p", "pressure", "hPa")
4725 SET_QNT(qnt_t, "t", "temperature", "K")
4726 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
4727 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
4728 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
4729 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
4730 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
4731 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
4732 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
4733 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
4734 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
4735 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
4736 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
4737 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
4738 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
4739 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
4740 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
4741 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
4742 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
4743 SET_QNT(qnt_cape, "cape", "convective available potential energy",
4744 "J/kg")
4745 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
4746 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
4747 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
4748 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
4749 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
4750 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
4751 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
4752 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
4753 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2",
4754 "mass loss due to H2O2 chemistry", "kg")
4755 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
4756 "kg")
4757 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
4758 "kg")
4759 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
4760 "kg")
4761 SET_QNT(qnt_mloss_decay, "mloss_decay",
4762 "mass loss due to exponential decay", "kg")
4763 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
4764 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
4765 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
4766 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
4767 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
4768 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
4769 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
4770 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
4771 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
4772 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
4773 SET_QNT(qnt_zeta_dot, "zeta_dot", "velocity of zeta coordinate",
4774 "K/day")
4775 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
4776 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
4777 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
4778 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
4779 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
4780 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
4781 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
4782 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
4783 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
4784 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
4785 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
4786 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
4787 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
4788 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
4789 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
4790 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
4791 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
4792 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
4793 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
4794 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
4795 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
4796 "ppv")
4797 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
4798 "ppv")
4799 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
4800 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
4801 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
4802#ifdef DD
4803 SET_QNT(qnt_destination, "destination",
4804 "subdomain index of destination", "-")
4805 SET_QNT(qnt_subdomain, "subdomain", "current subdomain index", "-")
4806#endif
4807 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
4808 }
4809
4810 /* Vertical coordinates and velocities... */
4811 ctl->advect_vert_coord =
4812 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
4813 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 2)
4814 ERRMSG("Set ADVECT_VERT_COORD to 0, 1, or 2!");
4815 ctl->met_vert_coord =
4816 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
4817 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
4818 ERRMSG("Set MET_VERT_COORD to 0, 1, 2, 3, or 4!");
4819 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
4820 ERRMSG("Please add zeta to your quantities for diabatic calculations!");
4821 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
4822 ERRMSG
4823 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
4824
4825 /* Time steps of simulation... */
4826 ctl->direction =
4827 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
4828 if (ctl->direction != -1 && ctl->direction != 1)
4829 ERRMSG("Set DIRECTION to -1 or 1!");
4830 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
4831 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
4832
4833 /* Meteo data... */
4834 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
4835 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
4836 ctl->met_convention =
4837 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
4838 ctl->met_type =
4839 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
4840 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
4841 ERRMSG
4842 ("Please use meteo files in netcdf format for diabatic calculations.");
4843 ctl->met_clams =
4844 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
4845 ctl->met_nc_scale =
4846 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
4847 ctl->met_nc_level =
4848 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
4849 ctl->met_nc_quant =
4850 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
4851 ctl->met_zstd_level =
4852 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
4853 for (int i = 0; i < METVAR; i++) {
4854 char defprec[LEN] = "0", deftol[LEN] = "0.0";
4855 if (i == 0) /* geopotential height */
4856 sprintf(deftol, "0.5");
4857 else if (i == 1) /* temperature */
4858 sprintf(deftol, "5.0");
4859 else /* other variables */
4860 sprintf(defprec, "8");
4861 ctl->met_zfp_prec[i] =
4862 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", i, defprec, NULL);
4863 ctl->met_zfp_tol[i] =
4864 scan_ctl(filename, argc, argv, "MET_ZFP_TOL", i, deftol, NULL);
4865 }
4866 ctl->met_cms_batch =
4867 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
4868 ctl->met_cms_zstd =
4869 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
4870 ctl->met_cms_heur =
4871 (int) scan_ctl(filename, argc, argv, "MET_CMS_HEUR", -1, "1", NULL);
4872 ctl->met_cms_eps_z =
4873 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
4874 ctl->met_cms_eps_t =
4875 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
4876 ctl->met_cms_eps_u =
4877 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
4878 ctl->met_cms_eps_v =
4879 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
4880 ctl->met_cms_eps_w =
4881 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
4882 ctl->met_cms_eps_pv =
4883 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
4884 ctl->met_cms_eps_h2o =
4885 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
4886 ctl->met_cms_eps_o3 =
4887 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
4888 ctl->met_cms_eps_lwc =
4889 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
4890 ctl->met_cms_eps_rwc =
4891 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
4892 ctl->met_cms_eps_iwc =
4893 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
4894 ctl->met_cms_eps_swc =
4895 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
4896 ctl->met_cms_eps_cc =
4897 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
4898 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
4899 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
4900 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
4901 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
4902 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
4903 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
4904 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
4905 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
4906 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
4907 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
4908 ctl->met_detrend =
4909 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
4910 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
4911 if (ctl->met_np > EP)
4912 ERRMSG("Too many pressure levels!");
4913 ctl->met_press_level_def =
4914 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
4915 NULL);
4916 if (ctl->met_press_level_def >= 0) {
4917 level_definitions(ctl);
4918 } else {
4919 if (ctl->met_np > 0) {
4920 for (int ip = 0; ip < ctl->met_np; ip++)
4921 ctl->met_p[ip] =
4922 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
4923 }
4924 }
4925 ctl->met_nlev =
4926 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
4927 if (ctl->met_nlev > EP)
4928 ERRMSG("Too many model levels!");
4929 for (int ip = 0; ip < ctl->met_nlev; ip++) {
4930 ctl->met_lev_hyam[ip] =
4931 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
4932 ctl->met_lev_hybm[ip] =
4933 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
4934 }
4935 ctl->met_geopot_sx =
4936 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
4937 ctl->met_geopot_sy =
4938 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
4939 ctl->met_relhum =
4940 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
4941 ctl->met_cape =
4942 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
4943 if (ctl->met_cape < 0 || ctl->met_cape > 1)
4944 ERRMSG("Set MET_CAPE to 0 or 1!");
4945 ctl->met_pbl =
4946 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
4947 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
4948 ERRMSG("Set MET_PBL to 0 ... 3!");
4949 ctl->met_pbl_min =
4950 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
4951 ctl->met_pbl_max =
4952 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
4953 ctl->met_tropo =
4954 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
4955 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
4956 ERRMSG("Set MET_TROPO to 0 ... 5!");
4957 ctl->met_tropo_pv =
4958 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
4959 ctl->met_tropo_theta =
4960 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
4961 ctl->met_tropo_spline =
4962 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
4963 ctl->met_dt_out =
4964 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
4965 ctl->met_cache =
4966 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
4967 ctl->met_mpi_share =
4968 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
4969
4970 /* Sorting... */
4971 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
4972
4973 /* Isosurface parameters... */
4974 ctl->isosurf =
4975 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
4976 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
4977
4978 /* Random number generator... */
4979 ctl->rng_type =
4980 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
4981 if (ctl->rng_type < 0 || ctl->rng_type > 2)
4982 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
4983
4984 /* Advection parameters... */
4985 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
4986 if (!
4987 (ctl->advect == 0 || ctl->advect == 1 || ctl->advect == 2
4988 || ctl->advect == 4))
4989 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
4990
4991 /* Diffusion parameters... */
4992 ctl->diffusion
4993 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
4994 if (ctl->diffusion < 0 || ctl->diffusion > 2)
4995 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
4996 ctl->turb_dx_pbl =
4997 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
4998 ctl->turb_dx_trop =
4999 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
5000 ctl->turb_dx_strat =
5001 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
5002 ctl->turb_dz_pbl =
5003 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
5004 ctl->turb_dz_trop =
5005 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
5006 ctl->turb_dz_strat =
5007 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
5008 ctl->turb_mesox =
5009 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
5010 ctl->turb_mesoz =
5011 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5012
5013 /* Convection... */
5014 ctl->conv_mix_pbl
5015 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
5016 ctl->conv_pbl_trans
5017 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
5018 ctl->conv_cape
5019 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5020 ctl->conv_cin
5021 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5022 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5023
5024 /* Boundary conditions... */
5025 ctl->bound_mass =
5026 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5027 ctl->bound_mass_trend =
5028 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5029 ctl->bound_vmr =
5030 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5031 ctl->bound_vmr_trend =
5032 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5033 ctl->bound_lat0 =
5034 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5035 ctl->bound_lat1 =
5036 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5037 ctl->bound_p0 =
5038 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5039 ctl->bound_p1 =
5040 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5041 ctl->bound_dps =
5042 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5043 ctl->bound_dzs =
5044 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
5045 ctl->bound_zetas =
5046 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
5047 ctl->bound_pbl =
5048 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
5049
5050 /* Species parameters... */
5051 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
5052 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
5053 ctl->molmass = 120.907;
5054 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
5055 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5056 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5057 ctl->molmass = 137.359;
5058 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5059 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5060 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5061 ctl->molmass = 16.043;
5062 ctl->oh_chem_reaction = 2;
5063 ctl->oh_chem[0] = 2.45e-12;
5064 ctl->oh_chem[1] = 1775;
5065 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5066 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5067 } else if (strcasecmp(ctl->species, "CO") == 0) {
5068 ctl->molmass = 28.01;
5069 ctl->oh_chem_reaction = 3;
5070 ctl->oh_chem[0] = 6.9e-33;
5071 ctl->oh_chem[1] = 2.1;
5072 ctl->oh_chem[2] = 1.1e-12;
5073 ctl->oh_chem[3] = -1.3;
5074 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5075 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5076 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5077 ctl->molmass = 44.009;
5078 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5079 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5080 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5081 ctl->molmass = 18.01528;
5082 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5083 ctl->molmass = 44.013;
5084 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5085 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5086 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5087 ctl->molmass = 17.031;
5088 ctl->oh_chem_reaction = 2;
5089 ctl->oh_chem[0] = 1.7e-12;
5090 ctl->oh_chem[1] = 710;
5091 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
5092 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
5093 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
5094 ctl->molmass = 63.012;
5095 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
5096 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
5097 } else if (strcasecmp(ctl->species, "NO") == 0) {
5098 ctl->molmass = 30.006;
5099 ctl->oh_chem_reaction = 3;
5100 ctl->oh_chem[0] = 7.1e-31;
5101 ctl->oh_chem[1] = 2.6;
5102 ctl->oh_chem[2] = 3.6e-11;
5103 ctl->oh_chem[3] = 0.1;
5104 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
5105 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5106 } else if (strcasecmp(ctl->species, "NO2") == 0) {
5107 ctl->molmass = 46.005;
5108 ctl->oh_chem_reaction = 3;
5109 ctl->oh_chem[0] = 1.8e-30;
5110 ctl->oh_chem[1] = 3.0;
5111 ctl->oh_chem[2] = 2.8e-11;
5112 ctl->oh_chem[3] = 0.0;
5113 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
5114 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5115 } else if (strcasecmp(ctl->species, "O3") == 0) {
5116 ctl->molmass = 47.997;
5117 ctl->oh_chem_reaction = 2;
5118 ctl->oh_chem[0] = 1.7e-12;
5119 ctl->oh_chem[1] = 940;
5120 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
5121 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
5122 } else if (strcasecmp(ctl->species, "SF6") == 0) {
5123 ctl->molmass = 146.048;
5124 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
5125 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
5126 } else if (strcasecmp(ctl->species, "SO2") == 0) {
5127 ctl->molmass = 64.066;
5128 ctl->oh_chem_reaction = 3;
5129 ctl->oh_chem[0] = 2.9e-31;
5130 ctl->oh_chem[1] = 4.1;
5131 ctl->oh_chem[2] = 1.7e-12;
5132 ctl->oh_chem[3] = -0.2;
5133 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
5134 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
5135 }
5136
5137 /* Molar mass... */
5138 char defstr[LEN];
5139 sprintf(defstr, "%g", ctl->molmass);
5140 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
5141
5142 /* OH chemistry... */
5143 sprintf(defstr, "%d", ctl->oh_chem_reaction);
5144 ctl->oh_chem_reaction =
5145 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
5146 NULL);
5147 for (int ip = 0; ip < 4; ip++) {
5148 sprintf(defstr, "%g", ctl->oh_chem[ip]);
5149 ctl->oh_chem[ip] =
5150 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
5151 }
5152 ctl->oh_chem_beta =
5153 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
5154
5155 /* H2O2 chemistry... */
5156 ctl->h2o2_chem_reaction =
5157 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
5158
5159 /* KPP chemistry... */
5160 ctl->kpp_chem =
5161 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
5162 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
5163
5164 /* First order tracer chemistry... */
5165 ctl->tracer_chem =
5166 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
5167
5168 /* Wet deposition... */
5169 for (int ip = 0; ip < 2; ip++) {
5170 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
5171 ctl->wet_depo_ic_h[ip] =
5172 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
5173 }
5174 for (int ip = 0; ip < 1; ip++) {
5175 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
5176 ctl->wet_depo_bc_h[ip] =
5177 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
5178 }
5179 ctl->wet_depo_so2_ph =
5180 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
5181 ctl->wet_depo_ic_a =
5182 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
5183 ctl->wet_depo_ic_b =
5184 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
5185 ctl->wet_depo_bc_a =
5186 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
5187 ctl->wet_depo_bc_b =
5188 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
5189 ctl->wet_depo_pre[0] =
5190 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
5191 ctl->wet_depo_pre[1] =
5192 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
5194 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
5196 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
5197
5198 /* Dry deposition... */
5199 ctl->dry_depo_vdep =
5200 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
5201 ctl->dry_depo_dp =
5202 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
5203
5204 /* Climatological data... */
5205 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
5206 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
5207 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
5208 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
5209 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
5210 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
5211 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
5212 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
5213 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
5214 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
5215 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
5216 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
5217 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
5218 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
5219 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
5220 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
5221 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
5222 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
5223 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
5224 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
5225 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
5226 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
5227
5228 /* Mixing... */
5229 ctl->mixing_dt =
5230 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
5231 ctl->mixing_trop =
5232 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
5233 ctl->mixing_strat =
5234 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
5235 ctl->mixing_z0 =
5236 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
5237 ctl->mixing_z1 =
5238 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
5239 ctl->mixing_nz =
5240 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
5241 ctl->mixing_lon0 =
5242 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
5243 ctl->mixing_lon1 =
5244 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
5245 ctl->mixing_nx =
5246 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
5247 ctl->mixing_lat0 =
5248 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
5249 ctl->mixing_lat1 =
5250 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
5251 ctl->mixing_ny =
5252 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
5253
5254 /* Chemistry grid... */
5255 ctl->chemgrid_z0 =
5256 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
5257 ctl->chemgrid_z1 =
5258 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
5259 ctl->chemgrid_nz =
5260 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
5261 ctl->chemgrid_lon0 =
5262 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
5263 ctl->chemgrid_lon1 =
5264 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
5265 ctl->chemgrid_nx =
5266 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
5267 ctl->chemgrid_lat0 =
5268 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
5269 ctl->chemgrid_lat1 =
5270 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
5271 ctl->chemgrid_ny =
5272 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
5273
5274 /* Exponential decay... */
5275 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
5276 ctl->tdec_strat =
5277 scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
5278
5279 /* PSC analysis... */
5280 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
5281 ctl->psc_hno3 =
5282 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
5283
5284 /* Output of atmospheric data... */
5285 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
5286 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
5287 ctl->atm_dt_out =
5288 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
5289 ctl->atm_filter =
5290 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
5291 ctl->atm_stride =
5292 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
5293 ctl->atm_type =
5294 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
5295 ctl->atm_type_out =
5296 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
5297 if (ctl->atm_type_out == -1)
5298 ctl->atm_type_out = ctl->atm_type;
5299 ctl->atm_nc_level =
5300 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
5301 for (int iq = 0; iq < ctl->nq; iq++)
5302 ctl->atm_nc_quant[iq] =
5303 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
5304 ctl->obs_type =
5305 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
5306
5307 /* Output of CSI data... */
5308 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
5309 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
5310 ctl->csi_dt_out =
5311 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
5312 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
5313 ctl->csi_obsmin =
5314 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
5315 ctl->csi_modmin =
5316 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
5317 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
5318 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
5319 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
5320 ctl->csi_lon0 =
5321 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
5322 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
5323 ctl->csi_nx =
5324 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
5325 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
5326 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
5327 ctl->csi_ny =
5328 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
5329
5330 /* Output of ensemble data... */
5331 ctl->nens = (int) scan_ctl(filename, argc, argv, "NENS", -1, "0", NULL);
5332 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
5333 ctl->ens_dt_out =
5334 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
5335
5336 /* Output of grid data... */
5337 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
5338 ctl->grid_basename);
5339 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
5340 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
5341 ctl->grid_dt_out =
5342 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
5343 ctl->grid_sparse =
5344 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
5345 ctl->grid_nc_level =
5346 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
5347 for (int iq = 0; iq < ctl->nq; iq++)
5348 ctl->grid_nc_quant[iq] =
5349 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
5350 ctl->grid_stddev =
5351 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
5352 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
5353 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
5354 ctl->grid_nz =
5355 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
5356 ctl->grid_lon0 =
5357 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
5358 ctl->grid_lon1 =
5359 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
5360 ctl->grid_nx =
5361 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
5362 ctl->grid_lat0 =
5363 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
5364 ctl->grid_lat1 =
5365 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
5366 ctl->grid_ny =
5367 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
5368 ctl->grid_type =
5369 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
5370
5371 /* Output of profile data... */
5372 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
5373 ctl->prof_basename);
5374 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
5375 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
5376 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
5377 ctl->prof_nz =
5378 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
5379 ctl->prof_lon0 =
5380 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
5381 ctl->prof_lon1 =
5382 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
5383 ctl->prof_nx =
5384 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
5385 ctl->prof_lat0 =
5386 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
5387 ctl->prof_lat1 =
5388 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
5389 ctl->prof_ny =
5390 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
5391
5392 /* Output of sample data... */
5393 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
5394 ctl->sample_basename);
5395 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
5396 ctl->sample_kernel);
5397 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
5398 ctl->sample_obsfile);
5399 ctl->sample_dx =
5400 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
5401 ctl->sample_dz =
5402 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
5403
5404 /* Output of station data... */
5405 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
5406 ctl->stat_basename);
5407 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
5408 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
5409 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
5410 ctl->stat_t0 =
5411 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
5412 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
5413
5414 /* Output of VTK data... */
5415 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
5416 ctl->vtk_dt_out =
5417 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
5418 ctl->vtk_stride =
5419 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
5420 ctl->vtk_scale =
5421 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
5422 ctl->vtk_offset =
5423 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
5424 ctl->vtk_sphere =
5425 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
5426
5427#ifdef DD
5428 /* Controle of domain decomposition... */
5430 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_MERIDIONAL", -1, "1",
5431 NULL);
5432 ctl->dd_subdomains_zonal =
5433 (int) scan_ctl(filename, argc, argv, "DD_SUBDOMAINS_ZONAL", -1, "1",
5434 NULL);
5435 ctl->dd_nbr_neighbours =
5436 (int) scan_ctl(filename, argc, argv, "DD_NBR_NEIGHBOURS", -1, "8", NULL);
5437 ctl->dd_halos_size =
5438 (int) scan_ctl(filename, argc, argv, "DD_HALOS_SIZE", -1, "1", NULL);
5439#endif
5440
5441}
5442
5443/*****************************************************************************/
5444
5446 const char *filename,
5447 const ctl_t *ctl,
5448 const clim_t *clim,
5449 met_t *met) {
5450
5451 /* Write info... */
5452 LOG(1, "Read meteo data: %s", filename);
5453
5454 /* Set rank... */
5455 int rank = 0;
5456#ifdef MPI
5457 if (ctl->met_mpi_share)
5458 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5459#endif
5460
5461 /* Check rank... */
5462 if (!ctl->met_mpi_share || rank == 0) {
5463
5464#ifdef DD
5465 /* Read netCDF data... */
5466 if (ctl->met_type == 0) {
5467 if (read_met_nc_dd(filename, ctl, met) != 1)
5468 return 0;
5469 }
5470#else
5471 /* Read netCDF data... */
5472 if (ctl->met_type == 0) {
5473 if (read_met_nc(filename, ctl, met) != 1)
5474 return 0;
5475 }
5476#endif
5477
5478 /* Read binary data... */
5479 else if (ctl->met_type >= 1 && ctl->met_type <= 5) {
5480 if (read_met_bin(filename, ctl, met) != 1)
5481 return 0;
5482 }
5483#ifdef ECCODES
5484 /* Read grib data... */
5485 else if (ctl->met_type == 6) {
5486 if (read_met_grib(filename, ctl, met) != 1)
5487 return 0;
5488 }
5489#endif
5490
5491 /* Not implemented... */
5492 else
5493 ERRMSG("MET_TYPE not implemented!");
5494
5495 /* Preprocessing for netCDF and grib files... */
5496 if (ctl->met_type == 0 || ctl->met_type == 6) {
5497
5498 /* Extrapolate data for lower boundary... */
5500
5501 /* Fix polar winds... */
5503
5504 /* Create periodic boundary conditions... */
5505#ifndef DD
5506 read_met_periodic(met);
5507#endif
5508
5509 /* Downsampling... */
5510 read_met_sample(ctl, met);
5511
5512 /* Calculate geopotential heights... */
5513 read_met_geopot(ctl, met);
5514
5515 /* Calculate potential vorticity... */
5516 read_met_pv(met);
5517
5518 /* Calculate boundary layer data... */
5519 read_met_pbl(ctl, met);
5520
5521 /* Calculate tropopause data... */
5522 read_met_tropo(ctl, clim, met);
5523
5524 /* Calculate cloud properties... */
5525 read_met_cloud(met);
5526
5527 /* Calculate convective available potential energy... */
5528 read_met_cape(ctl, clim, met);
5529
5530 /* Calculate total column ozone... */
5531 read_met_ozone(met);
5532
5533 /* Detrending... */
5534 read_met_detrend(ctl, met);
5535
5536 /* Check meteo data and smooth zeta profiles ... */
5537 read_met_monotonize(ctl, met);
5538 }
5539 }
5540
5541 /* Broadcast data via MPI... */
5542#ifdef MPI
5543 if (ctl->met_mpi_share) {
5544
5545 /* Set timer... */
5546 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
5547 LOG(2, "Broadcast data on rank %d...", rank);
5548
5549 /* Broadcast... */
5550 broadcast_large_data(met, sizeof(met_t));
5551 }
5552#endif
5553
5554 /* Return success... */
5555 return 1;
5556}
5557
5558/*****************************************************************************/
5559
5560#ifdef DD
5562 ctl_t *ctl,
5563 cache_t *cache,
5564 clim_t *clim,
5565 met_t **met0,
5566 met_t **met1,
5567 atm_t *atm,
5568 double t,
5569 mpi_info_t *mpi_info) {
5570#else
5572 ctl_t *ctl,
5573 cache_t *cache,
5574 clim_t *clim,
5575 met_t **met0,
5576 met_t **met1,
5577 atm_t *atm,
5578 double t) {
5579#endif
5580 /* Initialize modules... */
5581 if (t == ctl->t_start) {
5582
5583 /* Initialize isosurface data... */
5584 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5585 module_isosurf_init(ctl, cache, *met0, *met1, atm);
5586
5587 /* Initialize advection... */
5588 module_advect_init(ctl, cache, *met0, *met1, atm);
5589
5590 /* Initialize chemistry... */
5591 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
5592 }
5593
5594 /* Set time steps of air parcels... */
5595 module_timesteps(ctl, cache, *met0, atm, t);
5596
5597#ifndef DD
5598 /* Sort particles... */
5599 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
5600 module_sort(ctl, *met0, atm);
5601#endif
5602
5603 /* Check positions (initial)... */
5604 module_position(cache, *met0, *met1, atm);
5605
5606 /* Advection... */
5607 if (ctl->advect > 0)
5608 module_advect(ctl, cache, *met0, *met1, atm);
5609
5610 /* Turbulent diffusion... */
5611 if (ctl->diffusion == 1
5612 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
5613 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
5614 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
5615 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
5616
5617 /* Mesoscale diffusion... */
5618 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
5619 module_diff_meso(ctl, cache, *met0, *met1, atm);
5620
5621 /* Diffusion... */
5622 if (ctl->diffusion == 2)
5623 module_diff_pbl(ctl, cache, *met0, *met1, atm);
5624
5625 /* Convection... */
5626 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
5627 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
5628 module_convection(ctl, cache, *met0, *met1, atm);
5629
5630 /* Sedimentation... */
5631 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
5632 module_sedi(ctl, cache, *met0, *met1, atm);
5633
5634 /* Isosurface... */
5635 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5636 module_isosurf(ctl, cache, *met0, *met1, atm);
5637
5638 /* Check positions (final)... */
5639 module_position(cache, *met0, *met1, atm);
5640
5641 /* Interpolate meteo data... */
5642 if (ctl->met_dt_out > 0
5643 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
5644 module_meteo(ctl, cache, clim, *met0, *met1, atm);
5645
5646 /* Check boundary conditions (initial)... */
5647 if ((ctl->bound_lat0 < ctl->bound_lat1)
5648 && (ctl->bound_p0 > ctl->bound_p1))
5649 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5650
5651 /* Initialize quantity of total loss rate... */
5652 if (ctl->qnt_loss_rate >= 0) {
5653 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
5654 atm->q[ctl->qnt_loss_rate][ip] = 0;
5655 }
5656 }
5657
5658 /* Decay of particle mass... */
5659 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
5660 module_decay(ctl, cache, clim, atm);
5661
5662 /* Interparcel mixing... */
5663 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
5664 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
5665 module_mixing(ctl, clim, atm, t);
5666
5667 /* Calculate the tracer vmr in the chemistry grid... */
5668 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
5669 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
5670 module_chem_grid(ctl, *met0, *met1, atm, t);
5671
5672 /* OH chemistry... */
5673 if (ctl->oh_chem_reaction != 0)
5674 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
5675
5676 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
5677 if (ctl->h2o2_chem_reaction != 0)
5678 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
5679
5680 /* First-order tracer chemistry... */
5681 if (ctl->tracer_chem)
5682 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
5683
5684 /* Domain decomposition... */
5685#ifdef DD
5687 module_dd(ctl, atm, cache, mpi_info, met0);
5688#endif
5689
5690 /* KPP chemistry... */
5691 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
5692#ifdef KPP
5693 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
5694#else
5695 ERRMSG("Code was compiled without KPP!");
5696#endif
5697 }
5698
5699 /* Wet deposition... */
5700 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
5701 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
5702 module_wet_depo(ctl, cache, *met0, *met1, atm);
5703
5704 /* Dry deposition... */
5705 if (ctl->dry_depo_vdep > 0)
5706 module_dry_depo(ctl, cache, *met0, *met1, atm);
5707
5708 /* Check boundary conditions (final)... */
5709 if ((ctl->bound_lat0 < ctl->bound_lat1)
5710 && (ctl->bound_p0 > ctl->bound_p1))
5711 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5712}
5713
5714/*****************************************************************************/
5715
5717 const ctl_t *ctl,
5718 const cache_t *cache,
5719 const clim_t *clim,
5720 met_t **met0,
5721 met_t **met1,
5722 const atm_t *atm) {
5723
5724 /* Update GPU... */
5725 if (ctl != NULL) {
5726#ifdef _OPENACC
5727 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5728#pragma acc update device(ctl[:1])
5729#endif
5730 }
5731
5732 if (cache != NULL) {
5733#ifdef _OPENACC
5734 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5735#pragma acc update device(cache[:1])
5736#endif
5737 }
5738
5739 if (clim != NULL) {
5740#ifdef _OPENACC
5741 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5742#pragma acc update device(clim[:1])
5743#endif
5744 }
5745
5746 if (met0 != NULL) {
5747#ifdef _OPENACC
5748 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5749 met_t *met0up = *met0;
5750#pragma acc update device(met0up[:1])
5751#endif
5752 }
5753
5754 if (met1 != NULL) {
5755#ifdef _OPENACC
5756 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5757 met_t *met1up = *met1;
5758#pragma acc update device(met1up[:1])
5759#endif
5760 }
5761
5762 if (atm != NULL) {
5763#ifdef _OPENACC
5764 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5765#pragma acc update device(atm[:1])
5766#endif
5767 }
5768}
5769
5770/*****************************************************************************/
5771
5773 const ctl_t *ctl,
5774 const cache_t *cache,
5775 const clim_t *clim,
5776 met_t **met0,
5777 met_t **met1,
5778 const atm_t *atm) {
5779
5780 /* Update GPU... */
5781 if (ctl != NULL) {
5782#ifdef _OPENACC
5783 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5784#pragma acc update host(ctl[:1])
5785#endif
5786 }
5787
5788 if (cache != NULL) {
5789#ifdef _OPENACC
5790 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5791#pragma acc update host(cache[:1])
5792#endif
5793 }
5794
5795 if (clim != NULL) {
5796#ifdef _OPENACC
5797 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5798#pragma acc update host(clim[:1])
5799#endif
5800 }
5801
5802 if (met0 != NULL) {
5803#ifdef _OPENACC
5804 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5805 met_t *met0up = *met0;
5806#pragma acc update host(met0up[:1])
5807#endif
5808 }
5809
5810 if (met1 != NULL) {
5811#ifdef _OPENACC
5812 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5813 met_t *met1up = *met1;
5814#pragma acc update host(met1up[:1])
5815#endif
5816 }
5817
5818 if (atm != NULL) {
5819#ifdef _OPENACC
5820 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5821#pragma acc update host(atm[:1])
5822#endif
5823 }
5824}
5825
5826/*****************************************************************************/
5827
5829 const char *filename,
5830 const ctl_t *ctl,
5831 const atm_t *atm,
5832 const double t) {
5833
5834 /* Set timer... */
5835 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
5836
5837 /* Write info... */
5838 LOG(1, "Write atmospheric data: %s", filename);
5839
5840 /* Write ASCII data... */
5841 if (ctl->atm_type_out == 0)
5842 write_atm_asc(filename, ctl, atm, t);
5843
5844 /* Write binary data... */
5845 else if (ctl->atm_type_out == 1)
5846 write_atm_bin(filename, ctl, atm);
5847
5848 /* Write netCDF data... */
5849 else if (ctl->atm_type_out == 2)
5850 write_atm_nc(filename, ctl, atm);
5851
5852 /* Write CLaMS trajectory data... */
5853 else if (ctl->atm_type_out == 3)
5854 write_atm_clams_traj(filename, ctl, atm, t);
5855
5856 /* Write CLaMS pos data... */
5857 else if (ctl->atm_type_out == 4)
5858 write_atm_clams(filename, ctl, atm);
5859
5860 /* Error... */
5861 else
5862 ERRMSG("Atmospheric data type not supported!");
5863
5864 /* Write info... */
5865 double mini, maxi;
5866 LOG(2, "Number of particles: %d", atm->np);
5867 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5868 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5869 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5870 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5871 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5872 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5873 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5874 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5875 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5876 for (int iq = 0; iq < ctl->nq; iq++) {
5877 char msg[5 * LEN];
5878 sprintf(msg, "Quantity %s range: %s ... %s %s",
5879 ctl->qnt_name[iq], ctl->qnt_format[iq],
5880 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5881 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5882 LOG(2, msg, mini, maxi);
5883 }
5884}
5885
5886/*****************************************************************************/
5887
5889 const char *filename,
5890 const ctl_t *ctl,
5891 met_t *met) {
5892
5893 /* Set timer... */
5894 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
5895
5896 /* Write info... */
5897 LOG(1, "Write meteo data: %s", filename);
5898
5899 /* Check compression flags... */
5900#ifndef ZFP
5901 if (ctl->met_type == 3)
5902 ERRMSG("MPTRAC was compiled without zfp compression!");
5903#endif
5904#ifndef ZSTD
5905 if (ctl->met_type == 4)
5906 ERRMSG("MPTRAC was compiled without zstd compression!");
5907#endif
5908#ifndef CMS
5909 if (ctl->met_type == 5)
5910 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
5911#endif
5912
5913 /* Write netCDF data... */
5914 if (ctl->met_type == 0)
5915 write_met_nc(filename, ctl, met);
5916
5917 /* Write binary data... */
5918 else if (ctl->met_type >= 1 && ctl->met_type <= 5)
5919 write_met_bin(filename, ctl, met);
5920
5921 /* Not implemented... */
5922 else
5923 ERRMSG("MET_TYPE not implemented!");
5924}
5925
5926/*****************************************************************************/
5927
5929 const char *dirname,
5930 const ctl_t *ctl,
5931 met_t *met0,
5932 met_t *met1,
5933 atm_t *atm,
5934 const double t) {
5935
5936 char ext[10], filename[2 * LEN];
5937
5938 double r;
5939
5940 int year, mon, day, hour, min, sec;
5941
5942 /* Get time... */
5943 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
5944
5945 /* Update host... */
5946 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
5947 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
5948 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
5949 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
5950 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
5951 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
5952 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
5953
5954 /* Write atmospheric data... */
5955 if (ctl->atm_basename[0] != '-' &&
5956 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
5957 if (ctl->atm_type_out == 0)
5958 sprintf(ext, "tab");
5959 else if (ctl->atm_type_out == 1)
5960 sprintf(ext, "bin");
5961 else if (ctl->atm_type_out == 2)
5962 sprintf(ext, "nc");
5963 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
5964 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
5965 mptrac_write_atm(filename, ctl, atm, t);
5966 }
5967
5968 /* Write gridded data... */
5969 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
5970 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
5971 dirname, ctl->grid_basename, year, mon, day, hour, min,
5972 ctl->grid_type == 0 ? "tab" : "nc");
5973 write_grid(filename, ctl, met0, met1, atm, t);
5974 }
5975
5976 /* Write CSI data... */
5977 if (ctl->csi_basename[0] != '-') {
5978 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
5979 write_csi(filename, ctl, atm, t);
5980 }
5981
5982 /* Write ensemble data... */
5983 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
5984 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
5985 dirname, ctl->ens_basename, year, mon, day, hour, min);
5986 write_ens(filename, ctl, atm, t);
5987 }
5988
5989 /* Write profile data... */
5990 if (ctl->prof_basename[0] != '-') {
5991 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
5992 write_prof(filename, ctl, met0, met1, atm, t);
5993 }
5994
5995 /* Write sample data... */
5996 if (ctl->sample_basename[0] != '-') {
5997 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
5998 write_sample(filename, ctl, met0, met1, atm, t);
5999 }
6000
6001 /* Write station data... */
6002 if (ctl->stat_basename[0] != '-') {
6003 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
6004 write_station(filename, ctl, atm, t);
6005 }
6006
6007 /* Write VTK data... */
6008 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
6009 static int nvtk;
6010 if (t == ctl->t_start)
6011 nvtk = 0;
6012 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
6013 write_vtk(filename, ctl, atm, t);
6014 }
6015}
6016
6017/*****************************************************************************/
6018
6020 const double p,
6021 const double h2o,
6022 const double hno3) {
6023
6024 /* Check water vapor volume mixing ratio... */
6025 const double h2o_help = MAX(h2o, 0.1e-6);
6026
6027 /* Calculate T_NAT... */
6028 const double p_hno3 = hno3 * p / 1.333224;
6029 const double p_h2o = h2o_help * p / 1.333224;
6030 const double a = 0.009179 - 0.00088 * log10(p_h2o);
6031 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
6032 const double c = -11397.0 / a;
6033 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
6034 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
6035 if (x2 > 0)
6036 tnat = x2;
6037
6038 return tnat;
6039}
6040
6041/*****************************************************************************/
6042
6044 const ctl_t *ctl,
6045 const atm_t *atm,
6046 const int ip,
6047 const double pbl,
6048 const double ps) {
6049
6050 /* Get pressure range... */
6051 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
6052 const double p0 = pbl;
6053
6054 /* Get weighting factor... */
6055 if (atm->p[ip] > p0)
6056 return 1;
6057 else if (atm->p[ip] < p1)
6058 return 0;
6059 else
6060 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
6061}
6062
6063/*****************************************************************************/
6064
6066 const char *filename,
6067 const ctl_t *ctl,
6068 atm_t *atm) {
6069
6070 /* Open file... */
6071 FILE *in;
6072 if (!(in = fopen(filename, "r"))) {
6073 WARN("Cannot open file!");
6074 return 0;
6075 }
6076
6077 /* Read line... */
6078 char line[LEN];
6079 while (fgets(line, LEN, in)) {
6080
6081 /* Read data... */
6082 char *tok;
6083 TOK(line, tok, "%lg", atm->time[atm->np]);
6084 TOK(NULL, tok, "%lg", atm->p[atm->np]);
6085 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
6086 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
6087 for (int iq = 0; iq < ctl->nq; iq++)
6088 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
6089
6090 /* Convert altitude to pressure... */
6091 atm->p[atm->np] = P(atm->p[atm->np]);
6092
6093 /* Increment data point counter... */
6094 if ((++atm->np) > NP)
6095 ERRMSG("Too many data points!");
6096 }
6097
6098 /* Close file... */
6099 fclose(in);
6100
6101 /* Return success... */
6102 return 1;
6103}
6104
6105/*****************************************************************************/
6106
6108 const char *filename,
6109 const ctl_t *ctl,
6110 atm_t *atm) {
6111
6112 /* Open file... */
6113 FILE *in;
6114 if (!(in = fopen(filename, "r")))
6115 return 0;
6116
6117 /* Check version of binary data... */
6118 int version;
6119 FREAD(&version, int,
6120 1,
6121 in);
6122 if (version != 100)
6123 ERRMSG("Wrong version of binary data!");
6124
6125 /* Read data... */
6126 FREAD(&atm->np, int,
6127 1,
6128 in);
6129 FREAD(atm->time, double,
6130 (size_t) atm->np,
6131 in);
6132 FREAD(atm->p, double,
6133 (size_t) atm->np,
6134 in);
6135 FREAD(atm->lon, double,
6136 (size_t) atm->np,
6137 in);
6138 FREAD(atm->lat, double,
6139 (size_t) atm->np,
6140 in);
6141 for (int iq = 0; iq < ctl->nq; iq++)
6142 FREAD(atm->q[iq], double,
6143 (size_t) atm->np,
6144 in);
6145
6146 /* Read final flag... */
6147 int final;
6148 FREAD(&final, int,
6149 1,
6150 in);
6151 if (final != 999)
6152 ERRMSG("Error while reading binary data!");
6153
6154 /* Close file... */
6155 fclose(in);
6156
6157 /* Return success... */
6158 return 1;
6159}
6160
6161/*****************************************************************************/
6162
6164 const char *filename,
6165 const ctl_t *ctl,
6166 atm_t *atm) {
6167
6168 int ncid, varid;
6169
6170 /* Open file... */
6171 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6172 return 0;
6173
6174 /* Get dimensions... */
6175 NC_INQ_DIM("NPARTS", &atm->np, 1, NP);
6176
6177 /* Get time... */
6178 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
6179 NC(nc_get_var_double(ncid, varid, atm->time));
6180 } else {
6181 WARN("TIME_INIT not found use time instead!");
6182 double time_init;
6183 NC_GET_DOUBLE("time", &time_init, 1);
6184 for (int ip = 0; ip < atm->np; ip++) {
6185 atm->time[ip] = time_init;
6186 }
6187 }
6188
6189 /* Read zeta coordinate, pressure is optional... */
6190 if (ctl->advect_vert_coord == 1) {
6191 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
6192 NC_GET_DOUBLE("PRESS", atm->p, 0);
6193 }
6194
6195 /* Read pressure, zeta coordinate is optional... */
6196 else {
6197 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
6198 NC(nc_get_var_double(ncid, varid, atm->p));
6199 } else {
6200 WARN("PRESS_INIT not found use PRESS instead!");
6201 nc_inq_varid(ncid, "PRESS", &varid);
6202 NC(nc_get_var_double(ncid, varid, atm->p));
6203 }
6204 }
6205
6206 /* Read further quantities if requested... */
6207 for (int iq = 0; iq < ctl->nq; iq++)
6208 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6209
6210 /* Read longitude and latitude... */
6211 NC_GET_DOUBLE("LON", atm->lon, 1);
6212 NC_GET_DOUBLE("LAT", atm->lat, 1);
6213
6214 /* Close file... */
6215 NC(nc_close(ncid));
6216
6217 /* Return success... */
6218 return 1;
6219}
6220
6221/*****************************************************************************/
6222
6224 const char *filename,
6225 const ctl_t *ctl,
6226 atm_t *atm) {
6227
6228 int ncid, varid;
6229
6230 /* Open file... */
6231 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6232 return 0;
6233
6234 /* Get dimensions... */
6235 NC_INQ_DIM("obs", &atm->np, 1, NP);
6236
6237 /* Read geolocations... */
6238 NC_GET_DOUBLE("time", atm->time, 1);
6239 NC_GET_DOUBLE("press", atm->p, 1);
6240 NC_GET_DOUBLE("lon", atm->lon, 1);
6241 NC_GET_DOUBLE("lat", atm->lat, 1);
6242
6243 /* Read variables... */
6244 for (int iq = 0; iq < ctl->nq; iq++)
6245 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6246
6247 /* Close file... */
6248 NC(nc_close(ncid));
6249
6250 /* Return success... */
6251 return 1;
6252}
6253
6254/*****************************************************************************/
6255
6257 const char *filename,
6258 clim_photo_t *photo) {
6259
6260 int ncid, varid;
6261
6262 /* Write info... */
6263 LOG(1, "Read photolysis rates: %s", filename);
6264
6265 /* Open netCDF file... */
6266 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6267 WARN("Photolysis rate data are missing!");
6268 return;
6269 }
6270
6271 /* Read pressure data... */
6272 NC_INQ_DIM("press", &photo->np, 2, CP);
6273 NC_GET_DOUBLE("press", photo->p, 1);
6274 if (photo->p[0] < photo->p[1])
6275 ERRMSG("Pressure data are not descending!");
6276
6277 /* Read total column ozone data... */
6278 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3);
6279 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
6280 if (photo->o3c[0] > photo->o3c[1])
6281 ERRMSG("Total column ozone data are not ascending!");
6282
6283 /* Read solar zenith angle data... */
6284 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA);
6285 NC_GET_DOUBLE("sza", photo->sza, 1);
6286 if (photo->sza[0] > photo->sza[1])
6287 ERRMSG("Solar zenith angle data are not ascending!");
6288
6289 /* Read data... */
6290 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
6291 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
6292 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
6293 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
6294 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
6295 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
6296 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
6297 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
6298 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
6299
6300 /* Close netCDF file... */
6301 NC(nc_close(ncid));
6302
6303 /* Write info... */
6304 LOG(2, "Number of pressure levels: %d", photo->np);
6305 LOG(2, "Altitude levels: %g, %g ... %g km",
6306 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
6307 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6308 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
6309 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
6310 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
6311 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
6312 RAD2DEG(photo->sza[photo->nsza - 1]));
6313 LOG(2, "Number of total column ozone values: %d", photo->no3c);
6314 LOG(2, "Total column ozone: %g, %g ... %g DU",
6315 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
6316 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
6317 photo->n2o[0][0][0], photo->n2o[1][0][0],
6318 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6319 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
6320 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
6321 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6322 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
6323 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
6324 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6325 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
6326 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
6327 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6328 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
6329 photo->o2[0][0][0], photo->o2[1][0][0],
6330 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6331 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
6332 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
6333 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6334 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
6335 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
6336 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6337 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
6338 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
6339 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6340 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
6341 photo->h2o[0][0][0], photo->h2o[1][0][0],
6342 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6343}
6344
6345/*****************************************************************************/
6346
6348 const int ncid,
6349 const char *varname,
6350 const clim_photo_t *photo,
6351 double var[CP][CSZA][CO3]) {
6352
6353 /* Allocate... */
6354 double *help;
6355 ALLOC(help, double,
6356 photo->np * photo->nsza * photo->no3c);
6357
6358 /* Read varible... */
6359 int varid;
6360 NC_GET_DOUBLE(varname, help, 1);
6361
6362 /* Copy data... */
6363 for (int ip = 0; ip < photo->np; ip++)
6364 for (int is = 0; is < photo->nsza; is++)
6365 for (int io = 0; io < photo->no3c; io++)
6366 var[ip][is][io] =
6367 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
6368
6369 /* Free... */
6370 free(help);
6371}
6372
6373/*****************************************************************************/
6374
6376 const char *filename,
6377 clim_ts_t *ts) {
6378
6379 /* Write info... */
6380 LOG(1, "Read climatological time series: %s", filename);
6381
6382 /* Open file... */
6383 FILE *in;
6384 if (!(in = fopen(filename, "r"))) {
6385 WARN("Cannot open file!");
6386 return 0;
6387 }
6388
6389 /* Read data... */
6390 char line[LEN];
6391 int nh = 0;
6392 while (fgets(line, LEN, in))
6393 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
6394
6395 /* Convert years to seconds... */
6396 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
6397
6398 /* Check data... */
6399 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
6400 ERRMSG("Time series must be ascending!");
6401
6402 /* Count time steps... */
6403 if ((++nh) >= CTS)
6404 ERRMSG("Too many data points!");
6405 }
6406
6407 /* Close file... */
6408 fclose(in);
6409
6410 /* Check number of data points... */
6411 ts->ntime = nh;
6412 if (nh < 2)
6413 ERRMSG("Not enough data points!");
6414
6415 /* Write info... */
6416 LOG(2, "Number of time steps: %d", ts->ntime);
6417 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
6418 ts->time[nh - 1]);
6419 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
6420 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
6421 (size_t) nh));
6422
6423 /* Exit success... */
6424 return 1;
6425}
6426
6427/*****************************************************************************/
6428
6430 const char *filename,
6431 const char *varname,
6432 clim_zm_t *zm) {
6433
6434 int ncid, varid, it, iy, iz, iz2, nt;
6435
6436 double *help, varmin = 1e99, varmax = -1e99;
6437
6438 /* Write info... */
6439 LOG(1, "Read %s data: %s", varname, filename);
6440
6441 /* Open netCDF file... */
6442 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6443 WARN("%s climatology data are missing!", varname);
6444 return;
6445 }
6446
6447 /* Read pressure data... */
6448 NC_INQ_DIM("press", &zm->np, 2, CP);
6449 NC_GET_DOUBLE("press", zm->p, 1);
6450 if (zm->p[0] < zm->p[1])
6451 ERRMSG("Pressure data are not descending!");
6452
6453 /* Read latitudes... */
6454 NC_INQ_DIM("lat", &zm->nlat, 2, CY);
6455 NC_GET_DOUBLE("lat", zm->lat, 1);
6456 if (zm->lat[0] > zm->lat[1])
6457 ERRMSG("Latitude data are not ascending!");
6458
6459 /* Set time data (for monthly means)... */
6460 zm->ntime = 12;
6461 zm->time[0] = 1209600.00;
6462 zm->time[1] = 3888000.00;
6463 zm->time[2] = 6393600.00;
6464 zm->time[3] = 9072000.00;
6465 zm->time[4] = 11664000.00;
6466 zm->time[5] = 14342400.00;
6467 zm->time[6] = 16934400.00;
6468 zm->time[7] = 19612800.00;
6469 zm->time[8] = 22291200.00;
6470 zm->time[9] = 24883200.00;
6471 zm->time[10] = 27561600.00;
6472 zm->time[11] = 30153600.00;
6473
6474 /* Check number of timesteps... */
6475 NC_INQ_DIM("time", &nt, 12, 12);
6476
6477 /* Read data... */
6478 ALLOC(help, double,
6479 zm->nlat * zm->np * zm->ntime);
6480 NC_GET_DOUBLE(varname, help, 1);
6481 for (it = 0; it < zm->ntime; it++)
6482 for (iz = 0; iz < zm->np; iz++)
6483 for (iy = 0; iy < zm->nlat; iy++)
6484 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
6485 free(help);
6486
6487 /* Fix data gaps... */
6488 for (it = 0; it < zm->ntime; it++)
6489 for (iy = 0; iy < zm->nlat; iy++)
6490 for (iz = 0; iz < zm->np; iz++) {
6491 if (zm->vmr[it][iz][iy] < 0) {
6492 for (iz2 = 0; iz2 < zm->np; iz2++)
6493 if (zm->vmr[it][iz2][iy] >= 0) {
6494 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6495 break;
6496 }
6497 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
6498 if (zm->vmr[it][iz2][iy] >= 0) {
6499 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6500 break;
6501 }
6502 }
6503 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
6504 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
6505 }
6506
6507 /* Close netCDF file... */
6508 NC(nc_close(ncid));
6509
6510 /* Write info... */
6511 LOG(2, "Number of time steps: %d", zm->ntime);
6512 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
6513 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
6514 LOG(2, "Number of pressure levels: %d", zm->np);
6515 LOG(2, "Altitude levels: %g, %g ... %g km",
6516 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
6517 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
6518 zm->p[1], zm->p[zm->np - 1]);
6519 LOG(2, "Number of latitudes: %d", zm->nlat);
6520 LOG(2, "Latitudes: %g, %g ... %g deg",
6521 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
6522 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
6523 varmax);
6524}
6525
6526/*****************************************************************************/
6527
6529 const char *filename,
6530 double kz[EP],
6531 double kw[EP],
6532 int *nk) {
6533
6534 /* Write info... */
6535 LOG(1, "Read kernel function: %s", filename);
6536
6537 /* Open file... */
6538 FILE *in;
6539 if (!(in = fopen(filename, "r")))
6540 ERRMSG("Cannot open file!");
6541
6542 /* Read data... */
6543 char line[LEN];
6544 int n = 0;
6545 while (fgets(line, LEN, in))
6546 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
6547 if (n > 0 && kz[n] < kz[n - 1])
6548 ERRMSG("Height levels must be ascending!");
6549 if ((++n) >= EP)
6550 ERRMSG("Too many height levels!");
6551 }
6552
6553 /* Close file... */
6554 fclose(in);
6555
6556 /* Check number of data points... */
6557 *nk = n;
6558 if (n < 2)
6559 ERRMSG("Not enough height levels!");
6560
6561 /* Normalize kernel function... */
6562 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
6563 for (int iz = 0; iz < n; iz++)
6564 kw[iz] /= kmax;
6565}
6566
6567/*****************************************************************************/
6568
6570 const char *filename,
6571 const ctl_t *ctl,
6572 met_t *met) {
6573
6574 FILE *in;
6575
6576 double r;
6577
6578 int year, mon, day, hour, min, sec;
6579
6580 /* Set timer... */
6581 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
6582
6583 /* Open file... */
6584 if (!(in = fopen(filename, "r"))) {
6585 WARN("Cannot open file!");
6586 return 0;
6587 }
6588
6589 /* Check type of binary data... */
6590 int met_type;
6591 FREAD(&met_type, int,
6592 1,
6593 in);
6594 if (met_type != ctl->met_type)
6595 ERRMSG("Wrong MET_TYPE of binary data!");
6596
6597 /* Check version of binary data... */
6598 int version;
6599 FREAD(&version, int,
6600 1,
6601 in);
6602 if (version != 103)
6603 ERRMSG("Wrong version of binary data!");
6604
6605 /* Read time... */
6606 FREAD(&met->time, double,
6607 1,
6608 in);
6609 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
6610 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
6611 met->time, year, mon, day, hour, min);
6612 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
6613 || day < 1 || day > 31 || hour < 0 || hour > 23)
6614 ERRMSG("Error while reading time!");
6615
6616 /* Read dimensions... */
6617 FREAD(&met->nx, int,
6618 1,
6619 in);
6620 LOG(2, "Number of longitudes: %d", met->nx);
6621 if (met->nx < 2 || met->nx > EX)
6622 ERRMSG("Number of longitudes out of range!");
6623
6624 FREAD(&met->ny, int,
6625 1,
6626 in);
6627 LOG(2, "Number of latitudes: %d", met->ny);
6628 if (met->ny < 2 || met->ny > EY)
6629 ERRMSG("Number of latitudes out of range!");
6630
6631 FREAD(&met->np, int,
6632 1,
6633 in);
6634 LOG(2, "Number of levels: %d", met->np);
6635 if (met->np < 2 || met->np > EP)
6636 ERRMSG("Number of levels out of range!");
6637
6638 /* Read grid... */
6639 FREAD(met->lon, double,
6640 (size_t) met->nx,
6641 in);
6642 LOG(2, "Longitudes: %g, %g ... %g deg",
6643 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
6644
6645 FREAD(met->lat, double,
6646 (size_t) met->ny,
6647 in);
6648 LOG(2, "Latitudes: %g, %g ... %g deg",
6649 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
6650
6651 FREAD(met->p, double,
6652 (size_t) met->np,
6653 in);
6654 LOG(2, "Altitude levels: %g, %g ... %g km",
6655 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
6656 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6657 met->p[0], met->p[1], met->p[met->np - 1]);
6658
6659 /* Read surface data... */
6660 read_met_bin_2d(in, met, met->ps, "PS");
6661 read_met_bin_2d(in, met, met->ts, "TS");
6662 read_met_bin_2d(in, met, met->zs, "ZS");
6663 read_met_bin_2d(in, met, met->us, "US");
6664 read_met_bin_2d(in, met, met->vs, "VS");
6665 read_met_bin_2d(in, met, met->ess, "ESS");
6666 read_met_bin_2d(in, met, met->nss, "NSS");
6667 read_met_bin_2d(in, met, met->shf, "SHF");
6668 read_met_bin_2d(in, met, met->lsm, "LSM");
6669 read_met_bin_2d(in, met, met->sst, "SST");
6670 read_met_bin_2d(in, met, met->pbl, "PBL");
6671 read_met_bin_2d(in, met, met->pt, "PT");
6672 read_met_bin_2d(in, met, met->tt, "TT");
6673 read_met_bin_2d(in, met, met->zt, "ZT");
6674 read_met_bin_2d(in, met, met->h2ot, "H2OT");
6675 read_met_bin_2d(in, met, met->pct, "PCT");
6676 read_met_bin_2d(in, met, met->pcb, "PCB");
6677 read_met_bin_2d(in, met, met->cl, "CL");
6678 read_met_bin_2d(in, met, met->plcl, "PLCL");
6679 read_met_bin_2d(in, met, met->plfc, "PLFC");
6680 read_met_bin_2d(in, met, met->pel, "PEL");
6681 read_met_bin_2d(in, met, met->cape, "CAPE");
6682 read_met_bin_2d(in, met, met->cin, "CIN");
6683 read_met_bin_2d(in, met, met->o3c, "O3C");
6684
6685 /* Read level data... */
6686 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
6687 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
6688 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
6689 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
6690 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
6691 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
6692 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
6693 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
6694 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
6695 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
6696 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
6697 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
6698 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
6699
6700 /* Read final flag... */
6701 int final;
6702 FREAD(&final, int,
6703 1,
6704 in);
6705 if (final != 999)
6706 ERRMSG("Error while reading binary data!");
6707
6708 /* Close file... */
6709 fclose(in);
6710
6711 /* Return success... */
6712 return 1;
6713}
6714
6715/*****************************************************************************/
6716
6718 FILE *in,
6719 const met_t *met,
6720 float var[EX][EY],
6721 const char *varname) {
6722
6723 float *help;
6724
6725 /* Allocate... */
6726 ALLOC(help, float,
6727 EX * EY);
6728
6729 /* Read uncompressed... */
6730 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
6731 FREAD(help, float,
6732 (size_t) (met->nx * met->ny),
6733 in);
6734
6735 /* Copy data... */
6736 for (int ix = 0; ix < met->nx; ix++)
6737 for (int iy = 0; iy < met->ny; iy++)
6738 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
6739
6740 /* Free... */
6741 free(help);
6742}
6743
6744/*****************************************************************************/
6745
6747 FILE *in,
6748 const ctl_t *ctl,
6749 const met_t *met,
6750 float var[EX][EY][EP],
6751 const char *varname,
6752 const float bound_min,
6753 const float bound_max) {
6754
6755 float *help;
6756
6757 /* Allocate... */
6758 ALLOC(help, float,
6759 EX * EY * EP);
6760
6761 /* Read uncompressed data... */
6762 if (ctl->met_type == 1) {
6763 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
6764 FREAD(help, float,
6765 (size_t) (met->nx * met->ny * met->np),
6766 in);
6767 }
6768
6769 /* Read packed data... */
6770 else if (ctl->met_type == 2)
6771 compress_pck(varname, help, (size_t) (met->ny * met->nx),
6772 (size_t) met->np, 1, in);
6773
6774 /* Read zfp data... */
6775 else if (ctl->met_type == 3) {
6776#ifdef ZFP
6777 int precision;
6778 FREAD(&precision, int,
6779 1,
6780 in);
6781
6782 double tolerance;
6783 FREAD(&tolerance, double,
6784 1,
6785 in);
6786
6787 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
6788 tolerance, 1, in);
6789#else
6790 ERRMSG("MPTRAC was compiled without zfp compression!");
6791#endif
6792 }
6793
6794 /* Read zstd data... */
6795 else if (ctl->met_type == 4) {
6796#ifdef ZSTD
6797 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
6798 ctl->met_zstd_level, in);
6799#else
6800 ERRMSG("MPTRAC was compiled without zstd compression!");
6801#endif
6802 }
6803
6804 /* Read cmultiscale data... */
6805 else if (ctl->met_type == 5) {
6806#ifdef CMS
6807 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
6808 (size_t) met->np, 1, in);
6809#else
6810 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6811#endif
6812 }
6813
6814 /* Copy data... */
6815#pragma omp parallel for default(shared) collapse(2)
6816 for (int ix = 0; ix < met->nx; ix++)
6817 for (int iy = 0; iy < met->ny; iy++)
6818 for (int ip = 0; ip < met->np; ip++) {
6819 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
6820 if (var[ix][iy][ip] < bound_min)
6821 var[ix][iy][ip] = bound_min;
6822 else if (var[ix][iy][ip] > bound_max)
6823 var[ix][iy][ip] = bound_max;
6824 }
6825
6826 /* Free... */
6827 free(help);
6828}
6829
6830/*****************************************************************************/
6831
6833 const ctl_t *ctl,
6834 const clim_t *clim,
6835 met_t *met) {
6836
6837 /* Check parameters... */
6838 if (ctl->met_cape != 1)
6839 return;
6840
6841 /* Set timer... */
6842 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
6843 LOG(2, "Calculate CAPE...");
6844
6845 /* Vertical spacing (about 100 m)... */
6846 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
6847
6848 /* Loop over columns... */
6849#pragma omp parallel for default(shared) collapse(2)
6850 for (int ix = 0; ix < met->nx; ix++)
6851 for (int iy = 0; iy < met->ny; iy++) {
6852
6853 /* Get potential temperature and water vapor at lowest 50 hPa... */
6854 int n = 0;
6855 double h2o = 0, t, theta = 0;
6856 double pbot = MIN(met->ps[ix][iy], met->p[0]);
6857 double ptop = pbot - 50.;
6858 for (int ip = 0; ip < met->np; ip++) {
6859 if (met->p[ip] <= pbot) {
6860 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
6861 h2o += met->h2o[ix][iy][ip];
6862 n++;
6863 }
6864 if (met->p[ip] < ptop && n > 0)
6865 break;
6866 }
6867 theta /= n;
6868 h2o /= n;
6869
6870 /* Cannot compute anything if water vapor is missing... */
6871 met->plcl[ix][iy] = NAN;
6872 met->plfc[ix][iy] = NAN;
6873 met->pel[ix][iy] = NAN;
6874 met->cape[ix][iy] = NAN;
6875 met->cin[ix][iy] = NAN;
6876 if (h2o <= 0)
6877 continue;
6878
6879 /* Find lifted condensation level (LCL)... */
6880 ptop = P(20.);
6881 pbot = met->ps[ix][iy];
6882 do {
6883 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
6884 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
6885 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
6886 ptop = met->plcl[ix][iy];
6887 else
6888 pbot = met->plcl[ix][iy];
6889 } while (pbot - ptop > 0.1);
6890
6891 /* Calculate CIN up to LCL... */
6893 double dcape, dz, h2o_env, t_env;
6894 double p = met->ps[ix][iy];
6895 met->cape[ix][iy] = met->cin[ix][iy] = 0;
6896 do {
6897 dz = dz0 * TVIRT(t, h2o);
6898 p /= pfac;
6899 t = theta / pow(1000. / p, 0.286);
6900 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6901 &t_env, ci, cw, 1);
6902 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6903 &h2o_env, ci, cw, 0);
6904 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6905 TVIRT(t_env, h2o_env) * dz;
6906 if (dcape < 0)
6907 met->cin[ix][iy] += fabsf((float) dcape);
6908 } while (p > met->plcl[ix][iy]);
6909
6910 /* Calculate level of free convection (LFC), equilibrium level (EL),
6911 and convective available potential energy (CAPE)... */
6912 dcape = 0;
6913 p = met->plcl[ix][iy];
6914 t = theta / pow(1000. / p, 0.286);
6915 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
6916 do {
6917 dz = dz0 * TVIRT(t, h2o);
6918 p /= pfac;
6919 t -= lapse_rate(t, h2o) * dz;
6920 double psat = PSAT(t);
6921 h2o = psat / (p - (1. - EPS) * psat);
6922 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6923 &t_env, ci, cw, 1);
6924 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6925 &h2o_env, ci, cw, 0);
6926 double dcape_old = dcape;
6927 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6928 TVIRT(t_env, h2o_env) * dz;
6929 if (dcape > 0) {
6930 met->cape[ix][iy] += (float) dcape;
6931 if (!isfinite(met->plfc[ix][iy]))
6932 met->plfc[ix][iy] = (float) p;
6933 } else if (dcape_old > 0)
6934 met->pel[ix][iy] = (float) p;
6935 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
6936 met->cin[ix][iy] += fabsf((float) dcape);
6937 } while (p > ptop);
6938
6939 /* Check results... */
6940 if (!isfinite(met->plfc[ix][iy]))
6941 met->cin[ix][iy] = NAN;
6942 }
6943}
6944
6945/*****************************************************************************/
6946
6948 met_t *met) {
6949
6950 /* Set timer... */
6951 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
6952 LOG(2, "Calculate cloud data...");
6953
6954 /* Thresholds for cloud detection... */
6955 const double ccmin = 0.01, cwmin = 1e-6;
6956
6957 /* Loop over columns... */
6958#pragma omp parallel for default(shared) collapse(2)
6959 for (int ix = 0; ix < met->nx; ix++)
6960 for (int iy = 0; iy < met->ny; iy++) {
6961
6962 /* Init... */
6963 met->pct[ix][iy] = NAN;
6964 met->pcb[ix][iy] = NAN;
6965 met->cl[ix][iy] = 0;
6966
6967 /* Loop over pressure levels... */
6968 for (int ip = 0; ip < met->np - 1; ip++) {
6969
6970 /* Check pressure... */
6971 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
6972 continue;
6973
6974 /* Check ice water and liquid water content... */
6975 if (met->cc[ix][iy][ip] > ccmin
6976 && (met->lwc[ix][iy][ip] > cwmin
6977 || met->rwc[ix][iy][ip] > cwmin
6978 || met->iwc[ix][iy][ip] > cwmin
6979 || met->swc[ix][iy][ip] > cwmin)) {
6980
6981 /* Get cloud top pressure ... */
6982 met->pct[ix][iy]
6983 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
6984
6985 /* Get cloud bottom pressure ... */
6986 if (!isfinite(met->pcb[ix][iy]))
6987 met->pcb[ix][iy]
6988 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
6989 }
6990
6991 /* Get cloud water... */
6992 met->cl[ix][iy] += (float)
6993 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
6994 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
6995 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
6996 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
6997 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
6998 }
6999 }
7000}
7001
7002/*****************************************************************************/
7003
7005 const ctl_t *ctl,
7006 met_t *met) {
7007
7008 met_t *help;
7009
7010 /* Check parameters... */
7011 if (ctl->met_detrend <= 0)
7012 return;
7013
7014 /* Set timer... */
7015 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
7016 LOG(2, "Detrend meteo data...");
7017
7018 /* Allocate... */
7019 ALLOC(help, met_t, 1);
7020
7021 /* Calculate standard deviation... */
7022 const double sigma = ctl->met_detrend / 2.355;
7023 const double tssq = 2. * SQR(sigma);
7024
7025 /* Calculate box size in latitude... */
7026 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
7027 sy = MIN(MAX(1, sy), met->ny / 2);
7028
7029 /* Calculate background... */
7030#pragma omp parallel for default(shared) collapse(2)
7031 for (int ix = 0; ix < met->nx; ix++) {
7032 for (int iy = 0; iy < met->ny; iy++) {
7033
7034 /* Calculate Cartesian coordinates... */
7035 double x0[3];
7036 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
7037
7038 /* Calculate box size in longitude... */
7039 int sx =
7040 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
7041 fabs(met->lon[1] - met->lon[0]));
7042 sx = MIN(MAX(1, sx), met->nx / 2);
7043
7044 /* Init... */
7045 float wsum = 0;
7046 for (int ip = 0; ip < met->np; ip++) {
7047 help->t[ix][iy][ip] = 0;
7048 help->u[ix][iy][ip] = 0;
7049 help->v[ix][iy][ip] = 0;
7050 help->w[ix][iy][ip] = 0;
7051 }
7052
7053 /* Loop over neighboring grid points... */
7054 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
7055 int ix3 = ix2;
7056 if (ix3 < 0)
7057 ix3 += met->nx;
7058 else if (ix3 >= met->nx)
7059 ix3 -= met->nx;
7060 for (int iy2 = MAX(iy - sy, 0);
7061 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
7062
7063 /* Calculate Cartesian coordinates... */
7064 double x1[3];
7065 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
7066
7067 /* Calculate weighting factor... */
7068 const float w = (float) exp(-DIST2(x0, x1) / tssq);
7069
7070 /* Add data... */
7071 wsum += w;
7072 for (int ip = 0; ip < met->np; ip++) {
7073 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
7074 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
7075 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
7076 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
7077 }
7078 }
7079 }
7080
7081 /* Normalize... */
7082 for (int ip = 0; ip < met->np; ip++) {
7083 help->t[ix][iy][ip] /= wsum;
7084 help->u[ix][iy][ip] /= wsum;
7085 help->v[ix][iy][ip] /= wsum;
7086 help->w[ix][iy][ip] /= wsum;
7087 }
7088 }
7089 }
7090
7091 /* Subtract background... */
7092#pragma omp parallel for default(shared) collapse(3)
7093 for (int ix = 0; ix < met->nx; ix++)
7094 for (int iy = 0; iy < met->ny; iy++)
7095 for (int ip = 0; ip < met->np; ip++) {
7096 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
7097 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
7098 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
7099 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
7100 }
7101
7102 /* Free... */
7103 free(help);
7104}
7105
7106/*****************************************************************************/
7107
7109 met_t *met) {
7110
7111 /* Set timer... */
7112 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
7113 LOG(2, "Extrapolate meteo data...");
7114
7115 /* Loop over columns... */
7116#pragma omp parallel for default(shared) collapse(2)
7117 for (int ix = 0; ix < met->nx; ix++)
7118 for (int iy = 0; iy < met->ny; iy++) {
7119
7120 /* Find lowest valid data point... */
7121 int ip0;
7122 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
7123 if (!isfinite(met->t[ix][iy][ip0])
7124 || !isfinite(met->u[ix][iy][ip0])
7125 || !isfinite(met->v[ix][iy][ip0])
7126 || !isfinite(met->w[ix][iy][ip0]))
7127 break;
7128
7129 /* Extrapolate... */
7130 for (int ip = ip0; ip >= 0; ip--) {
7131 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
7132 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
7133 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
7134 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
7135 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
7136 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
7137 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
7138 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
7139 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
7140 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
7141 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
7142 }
7143 }
7144}
7145
7146/*****************************************************************************/
7147
7149 const ctl_t *ctl,
7150 met_t *met) {
7151
7152 float *help;
7153
7154 double logp[EP];
7155
7156 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
7157
7158 /* Set timer... */
7159 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
7160 LOG(2, "Calculate geopotential heights...");
7161
7162 /* Allocate... */
7163 ALLOC(help, float,
7164 EX * EY * EP);
7165
7166 /* Calculate log pressure... */
7167#pragma omp parallel for default(shared)
7168 for (int ip = 0; ip < met->np; ip++)
7169 logp[ip] = log(met->p[ip]);
7170
7171 /* Apply hydrostatic equation to calculate geopotential heights... */
7172#pragma omp parallel for default(shared) collapse(2)
7173 for (int ix = 0; ix < met->nx; ix++)
7174 for (int iy = 0; iy < met->ny; iy++) {
7175
7176 /* Get surface height and pressure... */
7177 const double zs = met->zs[ix][iy];
7178 const double lnps = log(met->ps[ix][iy]);
7179
7180 /* Get temperature and water vapor at the surface... */
7181 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
7182 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
7183 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
7184 const double h2os =
7185 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
7186 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
7187
7188 /* Upper part of profile... */
7189 met->z[ix][iy][ip0 + 1]
7190 = (float) (zs +
7191 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
7192 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
7193 for (int ip = ip0 + 2; ip < met->np; ip++)
7194 met->z[ix][iy][ip]
7195 = (float) (met->z[ix][iy][ip - 1] +
7196 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
7197 met->h2o[ix][iy][ip - 1], logp[ip],
7198 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7199
7200 /* Lower part of profile... */
7201 met->z[ix][iy][ip0]
7202 = (float) (zs +
7203 ZDIFF(lnps, ts, h2os, logp[ip0],
7204 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
7205 for (int ip = ip0 - 1; ip >= 0; ip--)
7206 met->z[ix][iy][ip]
7207 = (float) (met->z[ix][iy][ip + 1] +
7208 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
7209 met->h2o[ix][iy][ip + 1], logp[ip],
7210 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7211 }
7212
7213 /* Check control parameters... */
7214 if (dx == 0 || dy == 0)
7215 return;
7216
7217 /* Default smoothing parameters... */
7218 if (dx < 0 || dy < 0) {
7219 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
7220 dx = 3;
7221 dy = 2;
7222 } else {
7223 dx = 6;
7224 dy = 4;
7225 }
7226 }
7227
7228 /* Calculate weights for smoothing... */
7229 float ws[dx + 1][dy + 1];
7230#pragma omp parallel for default(shared) collapse(2)
7231 for (int ix = 0; ix <= dx; ix++)
7232 for (int iy = 0; iy < dy; iy++)
7233 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
7234 * (1.0f - (float) iy / (float) dy);
7235
7236 /* Copy data... */
7237#pragma omp parallel for default(shared) collapse(3)
7238 for (int ix = 0; ix < met->nx; ix++)
7239 for (int iy = 0; iy < met->ny; iy++)
7240 for (int ip = 0; ip < met->np; ip++)
7241 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
7242
7243 /* Horizontal smoothing... */
7244#pragma omp parallel for default(shared) collapse(3)
7245 for (int ip = 0; ip < met->np; ip++)
7246 for (int ix = 0; ix < met->nx; ix++)
7247 for (int iy = 0; iy < met->ny; iy++) {
7248 float res = 0, wsum = 0;
7249 int iy0 = MAX(iy - dy + 1, 0);
7250 int iy1 = MIN(iy + dy - 1, met->ny - 1);
7251 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
7252 int ix3 = ix2;
7253 if (ix3 < 0)
7254 ix3 += met->nx;
7255 else if (ix3 >= met->nx)
7256 ix3 -= met->nx;
7257 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
7258 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
7259 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
7260 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
7261 wsum += w;
7262 }
7263 }
7264 if (wsum > 0)
7265 met->z[ix][iy][ip] = res / wsum;
7266 else
7267 met->z[ix][iy][ip] = NAN;
7268 }
7269
7270 /* Free... */
7271 free(help);
7272}
7273
7274/*****************************************************************************/
7275#ifdef DD
7277 const char *filename,
7278 const int ncid,
7279 const ctl_t *ctl,
7280 met_t *met) {
7281
7282 char levname[LEN], tstr[10];
7283
7284 double rtime = 0, r, r2;
7285
7286 int varid, year2, mon2, day2, hour2, min2, sec2,
7287 year, mon, day, hour, min, sec;
7288
7289 size_t np;
7290
7291 /* Set timer... */
7292 SELECT_TIMER("READ_MET_NC_GRID_DD", "INPUT", NVTX_READ);
7293 LOG(2, "Read meteo grid information...");
7294
7295 /* MPTRAC meteo files... */
7296 if (ctl->met_clams == 0) {
7297
7298 /* Get time from filename... */
7299 met->time = time_from_filename(filename, 16);
7300
7301 /* Check time information from data file... */
7302 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7303 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
7304 NC(nc_get_var_double(ncid, varid, &rtime));
7305 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
7306 WARN("Time information in meteo file does not match filename!");
7307 } else
7308 WARN("Time information in meteo file is missing!");
7309 }
7310
7311 /* CLaMS meteo files... */
7312 else {
7313
7314 /* Read time from file... */
7315 NC_GET_DOUBLE("time", &rtime, 0);
7316
7317 /* Get time from filename (considering the century)... */
7318 if (rtime < 0)
7319 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
7320 else
7321 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
7322 year = atoi(tstr);
7323 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
7324 mon = atoi(tstr);
7325 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
7326 day = atoi(tstr);
7327 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
7328 hour = atoi(tstr);
7329 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
7330 }
7331
7332 /* Check time... */
7333 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7334 || day < 1 || day > 31 || hour < 0 || hour > 23)
7335 ERRMSG("Cannot read time from filename!");
7336 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
7337 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7338 met->time, year2, mon2, day2, hour2, min2);
7339
7340 /* Get global and local grid dimensions... */
7341 NC_INQ_DIM("lon", &met->nx_glob, 2, EX_GLOB);
7342 LOG(2, "Number of longitudes: %d", met->nx_glob);
7343 met->nx = (int) floor(met->nx_glob / ctl->dd_subdomains_zonal);
7344
7345 NC_INQ_DIM("lat", &met->ny_glob, 2, EY_GLOB);
7346 LOG(2, "Number of latitudes: %d", met->ny_glob);
7347 met->ny = (int) floor(met->ny_glob / ctl->dd_subdomains_meridional);;
7348
7349 /* Get global coordinates... */
7350 int dimid2;
7351 sprintf(levname, "lev");
7352 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7353 sprintf(levname, "plev");
7354 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7355 sprintf(levname, "hybrid");
7356
7357 NC_INQ_DIM(levname, &met->np_glob, 1, EP_GLOB);
7358 if (met->np_glob == 1) {
7359 sprintf(levname, "lev_2");
7360 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR) {
7361 sprintf(levname, "plev");
7362 NC(nc_inq_dimid(ncid, levname, &dimid2));
7363 }
7364 NC(nc_inq_dimlen(ncid, dimid2, &np));
7365 met->np_glob = (int) np;
7366 }
7367 met->np = met->np_glob;
7368
7369 LOG(2, "Number of levels: %d", met->np);
7370 if (met->np_glob < 2 || met->np_glob > EP_GLOB)
7371 ERRMSG("Number of levels out of range!");
7372
7373 /* Read longitudes and latitudes... */
7374 NC_GET_DOUBLE("lon", met->lon, 1);
7375 LOG(2, "Longitudes: %g, %g ... %g deg",
7376 met->lon[0], met->lon[1], met->lon[met->nx_glob - 1]);
7377 NC_GET_DOUBLE("lat", met->lat, 1);
7378 LOG(2, "Latitudes: %g, %g ... %g deg",
7379 met->lat[0], met->lat[1], met->lat[met->ny_glob - 1]);
7380
7381 /* Check grid spacing... */
7382 for (int ix = 2; ix < met->nx; ix++)
7383 if (fabs
7384 (fabs(met->lon[ix] - met->lon[ix - 1]) -
7385 fabs(met->lon[1] - met->lon[0])) > 0.001)
7386 ERRMSG("No regular grid spacing in longitudes!");
7387 for (int iy = 2; iy < met->ny; iy++)
7388 if (fabs
7389 (fabs(met->lat[iy] - met->lat[iy - 1]) -
7390 fabs(met->lat[1] - met->lat[0])) > 0.001) {
7391 WARN("No regular grid spacing in latitudes!");
7392 break;
7393 }
7394
7395 /* Get the MPI information... */
7396 int rank, size;
7397 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
7398 MPI_Comm_size(MPI_COMM_WORLD, &size);
7399
7400 /* Check for edge cases... */
7401 bool left = (rank <= ctl->dd_subdomains_meridional - 1);
7402 bool right = (rank >= size - ctl->dd_subdomains_meridional);
7403 bool top = (rank % ctl->dd_subdomains_meridional == 0);
7404 bool bottom =
7405 (rank % ctl->dd_subdomains_meridional ==
7406 ctl->dd_subdomains_meridional - 1);
7407
7408 /* Set the hyperslab for the subdomain... */
7409 met->subdomain_start[0] = 0;
7410 met->subdomain_start[1] = 0;
7411 met->subdomain_start[2] =
7412 (size_t) ((rank % ctl->dd_subdomains_meridional) * met->ny);
7413 met->subdomain_start[3] =
7414 (size_t) (floor(rank / ctl->dd_subdomains_meridional) * met->nx);
7415
7416 /* Extend subdomains at the right and bottom to fit the full domain. */
7417 if (right) {
7418 int gap = met->nx_glob - ctl->dd_subdomains_zonal * met->nx;
7419 if (gap > 0) {
7420 met->nx = met->nx + gap;
7421 WARN("Extended subdomains at the right to fit to full domain.");
7422 }
7423 }
7424 if (bottom) {
7425 int gap = met->ny_glob - ctl->dd_subdomains_meridional * met->ny;
7426 if (gap > 0) {
7427 met->ny = met->ny + gap;
7428 WARN("Extended subdomains at the bottom to fit to full domain.");
7429 }
7430 }
7431
7432 /* Block-size, i.e. count */
7433 met->subdomain_count[0] = 1;
7434 met->subdomain_count[1] = (size_t) met->np;
7435 met->subdomain_count[2] = (size_t) met->ny;
7436 met->subdomain_count[3] = (size_t) met->nx;
7437
7438 /* Create halos and include them into the subdomain... */
7439 if (!left && !right) {
7440 // If we are not at the left or right edge extend in zonal direction...
7441 // Move the start one point to the left...
7442 met->subdomain_count[3] =
7443 met->subdomain_count[3] + (size_t) (ctl->dd_halos_size * 2);
7444 met->subdomain_start[3] =
7445 met->subdomain_start[3] - (size_t) ctl->dd_halos_size;
7446 } else {
7447 // If we are at the left or right edge, extend only in one zonal direction...
7448 met->subdomain_count[3] =
7449 met->subdomain_count[3] + (size_t) ctl->dd_halos_size;
7450 if (!left)
7451 // If we are not at the left edge, move the start to the left...
7452 met->subdomain_start[3] =
7453 met->subdomain_start[3] - (size_t) ctl->dd_halos_size;
7454 }
7455
7456 if (!top && !bottom) {
7457 // If we are not at the upper or lower edge extend in meridional direction...
7458 // Move the start point one point down...
7459 met->subdomain_count[2] =
7460 met->subdomain_count[2] + (size_t) (ctl->dd_halos_size * 2);
7461 met->subdomain_start[2] =
7462 met->subdomain_start[2] - (size_t) ctl->dd_halos_size;
7463 } else {
7464 // If we are at the top or the lower edge only extend in one mer. direction...
7465 met->subdomain_count[2] =
7466 met->subdomain_count[2] + (size_t) ctl->dd_halos_size;
7467 if (!top)
7468 // If we are not at the top, move the start one upward...
7469 met->subdomain_start[2] =
7470 met->subdomain_start[2] - (size_t) ctl->dd_halos_size;
7471 }
7472
7473 /* Set boundary halo hyperslabs ... */
7474 double lon_shift = 0;
7475 if (left || right) {
7476
7477 met->nx = met->nx + ctl->dd_halos_size;
7478
7479 met->halo_bnd_start[0] = 0;
7480 met->halo_bnd_start[1] = 0;
7481 met->halo_bnd_start[3] = (size_t) (left ? (met->nx_glob - ctl->dd_halos_size) : (0)); //x
7482 met->halo_bnd_start[2] = met->subdomain_start[2]; //y
7483
7484 met->halo_bnd_count[0] = 1;
7485 met->halo_bnd_count[1] = (size_t) met->np;
7486 met->halo_bnd_count[3] = (size_t) ctl->dd_halos_size;
7487 met->halo_bnd_count[2] =
7488 (size_t) met->ny +
7489 (size_t) ctl->dd_halos_size * ((top || bottom) ? 1 : 2);
7490
7491 met->halo_offset_start = (left ? (int) met->halo_bnd_count[3] : 0);
7492 met->halo_offset_end = (left ? 0 : (int) met->subdomain_count[3]);
7493 lon_shift = (left ? -360 : 360);
7494
7495 }
7496
7497 /* Get the range of the entire meteodata... */
7498 double lon_range = met->lon[met->nx_glob - 1] - met->lon[0];
7499 double lat_range = met->lat[met->ny_glob - 1] - met->lat[0];
7500
7501 /* Focus on subdomain longitutes and latitudes... */
7502 for (int iy = 0; iy < (int) met->subdomain_count[2]; iy++) {
7503 int iy_ = (int) met->subdomain_start[2] + iy;
7504 met->lat[iy] = met->lat[iy_];
7505 }
7506
7507 /* Keep space at the beginning or end of the array for halo... */
7508 double help_lon[EX];
7509
7510 for (int ix = 0; ix < (int) met->subdomain_count[3]; ix++) {
7511 int ix_ = (int) met->subdomain_start[3] + ix;
7512 help_lon[ix + met->halo_offset_start] = met->lon[ix_];
7513 }
7514
7515 for (int ix = 0; ix < (int) met->halo_bnd_count[3]; ix++) {
7516 int ix_ = (int) met->halo_bnd_start[3] + ix;
7517 help_lon[ix + met->halo_offset_end] = met->lon[ix_] + lon_shift;
7518 }
7519
7520 /* Reset the grid dimensions... */
7521 met->nx = (int) met->subdomain_count[3] + (int) met->halo_bnd_count[3];
7522 met->ny = (int) met->subdomain_count[2];
7523
7524 for (int ix = 0; ix < (int) met->nx; ix++) {
7525 met->lon[ix] = help_lon[ix];
7526 }
7527
7528 /* Determine subdomain edges... */
7529 met->subdomain_lon_min = floor(rank / ctl->dd_subdomains_meridional)
7530 * (lon_range) / (double) ctl->dd_subdomains_zonal;
7532 + (lon_range) / (double) ctl->dd_subdomains_zonal;
7533 met->subdomain_lat_max = 90 + (rank % ctl->dd_subdomains_meridional)
7534 * (lat_range) / (double) ctl->dd_subdomains_meridional;
7536 + (lat_range) / (double) ctl->dd_subdomains_meridional;
7537
7538 LOG(2, " %d Subdomain longitudes: %g, %g ... %g deg", rank,
7539 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7540 LOG(2, " %d Subdomain latitudes: %g, %g ... %g deg", rank,
7541 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7542
7543 LOG(2, "Define subdomain properties.");
7544 LOG(2, "MPI information: Rank %d, Size %d", rank, size);
7545 LOG(2, "Edge position: l=%d,r=%d,t=%d, b=%d", (int) left, (int) right,
7546 (int) top, (int) bottom);
7547 LOG(2, "Sizes for limits: EX %d EY %d EP %d", EX, EY, EP);
7548 LOG(2, "Total size for subdomain meteo data: nx %d ny %d np %d", met->nx,
7549 met->ny, met->np);
7550 LOG(2, "Hyperslab sizes for boundary halos: nx %d ny %d np %d",
7551 (int) met->halo_bnd_count[3], (int) met->halo_bnd_count[2],
7552 (int) met->halo_bnd_count[1]);
7553 LOG(2, "Hyperslab sizes for subdomain and inner halos: nx %d ny %d np %d",
7554 (int) met->subdomain_count[3], (int) met->subdomain_count[2],
7555 (int) met->subdomain_count[1]);
7556 LOG(2, "Subdomain start: nx %ld ny %ld np %ld", met->subdomain_start[3],
7557 met->subdomain_start[2], met->subdomain_start[1]);
7558 LOG(2, "Boundary halo start: nx %ld ny %ld np %ld", met->halo_bnd_start[3],
7559 met->halo_bnd_start[2], met->halo_bnd_start[1]);
7560 LOG(2, "Offsets: nx %d ny %d", met->halo_offset_start,
7561 met->halo_offset_end);
7562
7563 /* Read pressure levels... */
7564 if (ctl->met_np <= 0) {
7565 NC_GET_DOUBLE(levname, met->p, 1);
7566 for (int ip = 0; ip < met->np; ip++)
7567 met->p[ip] /= 100.;
7568 LOG(2, "Altitude levels: %g, %g ... %g km",
7569 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7570 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7571 met->p[0], met->p[1], met->p[met->np - 1]);
7572 }
7573
7574 /* Read hybrid levels... */
7575 if (strcasecmp(levname, "hybrid") == 0)
7576 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
7577
7578}
7579#endif
7580
7581/*****************************************************************************/
7582#ifdef DD
7584 const int ncid,
7585 const ctl_t *ctl,
7586 met_t *met) {
7587
7588 /* Set timer... */
7589 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
7590 LOG(2, "Read surface data...");
7591
7592 /* Read surface pressure... */
7594 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, met->ps, 1.0f,
7595 1)) {
7596 for (int ix = 0; ix < met->nx; ix++)
7597 for (int iy = 0; iy < met->ny; iy++)
7598 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
7599 } else
7601 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, met->ps, 0.01f,
7602 1)) {
7603 WARN("Cannot not read surface pressure data (use lowest level)!");
7604 for (int ix = 0; ix < met->nx; ix++)
7605 for (int iy = 0; iy < met->ny; iy++)
7606 met->ps[ix][iy]
7607 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
7608 }
7609
7610 /* MPTRAC meteo data... */
7611 if (ctl->met_clams == 0) {
7612
7613 /* Read geopotential height at the surface... */
7615 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, met->zs,
7616 (float) (1. / (1000. * G0)), 1))
7618 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, met->zs,
7619 (float) (1. / 1000.), 1))
7620 WARN("Cannot read surface geopotential height!");
7621 }
7622
7623 /* CLaMS meteo data... */
7624 else {
7625
7626 /* Read geopotential height at the surface
7627 (use lowermost level of 3-D data field)... */
7628 float *help;
7629 ALLOC(help, float,
7630 EX * EY * EP);
7631 memcpy(help, met->pl, sizeof(met->pl));
7633 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
7634 (float) (1e-3 / G0)))
7635 ERRMSG("Cannot read geopotential height!");
7636 for (int ix = 0; ix < met->nx; ix++)
7637 for (int iy = 0; iy < met->ny; iy++)
7638 met->zs[ix][iy] = met->pl[ix][iy][0];
7639 memcpy(met->pl, help, sizeof(met->pl));
7640 free(help);
7641 }
7642
7643 /* Read temperature at the surface... */
7645 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, met->ts, 1.0, 1))
7646 WARN("Cannot read surface temperature!");
7647
7648 /* Read zonal wind at the surface... */
7650 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, met->us,
7651 1.0, 1))
7652 WARN("Cannot read surface zonal wind!");
7653
7654 /* Read meridional wind at the surface... */
7656 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, met->vs,
7657 1.0, 1))
7658 WARN("Cannot read surface meridional wind!");
7659
7660 /* Read eastward turbulent surface stress... */
7662 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, met->ess, 1.0,
7663 1))
7664 WARN("Cannot read eastward turbulent surface stress!");
7665
7666 /* Read northward turbulent surface stress... */
7668 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, met->nss, 1.0,
7669 1))
7670 WARN("Cannot read nothward turbulent surface stress!");
7671
7672 /* Read surface sensible heat flux... */
7674 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, met->shf, 1.0,
7675 1))
7676 WARN("Cannot read surface sensible heat flux!");
7677
7678 /* Read land-sea mask... */
7680 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, met->lsm, 1.0,
7681 1))
7682 WARN("Cannot read land-sea mask!");
7683
7684 /* Read sea surface temperature... */
7686 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, met->sst,
7687 1.0, 1))
7688 WARN("Cannot read sea surface temperature!");
7689
7690 /* Read PBL... */
7691 if (ctl->met_pbl == 0)
7693 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
7694 0.01f, 1))
7695 WARN("Cannot read planetary boundary layer pressure!");
7696 if (ctl->met_pbl == 1)
7698 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
7699 0.001f, 1))
7700 WARN("Cannot read planetary boundary layer height!");
7701
7702 /* Read CAPE... */
7703 if (ctl->met_cape == 0)
7705 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, met->cape,
7706 1.0, 1))
7707 WARN("Cannot read CAPE!");
7708
7709 /* Read CIN... */
7710 if (ctl->met_cape == 0)
7712 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, met->cin,
7713 1.0, 1))
7714 WARN("Cannot read convective inhibition!");
7715}
7716#endif
7717
7718/*****************************************************************************/
7719
7720#ifdef DD
7722 const int ncid,
7723 const ctl_t *ctl,
7724 met_t *met) {
7725
7726 /* Set timer... */
7727 SELECT_TIMER("READ_MET_NC_LEVELS_DD", "INPUT", NVTX_READ);
7728 LOG(2, "Read level data...");
7729
7730 /* Read temperature... */
7732 (ncid, "t", "T", "temp", "TEMP", ctl, met, met->t, 1.0))
7733 ERRMSG("Cannot read temperature!");
7734
7735 /* Read horizontal wind and vertical velocity... */
7736 if (!read_met_nc_3d_dd(ncid, "u", "U", NULL, NULL, ctl, met, met->u, 1.0))
7737 ERRMSG("Cannot read zonal wind!");
7738 if (!read_met_nc_3d_dd(ncid, "v", "V", NULL, NULL, ctl, met, met->v, 1.0))
7739 ERRMSG("Cannot read meridional wind!");
7741 (ncid, "w", "W", "omega", "OMEGA", ctl, met, met->w, 0.01f))
7742 WARN("Cannot read vertical velocity!");
7743
7744 /* Read water vapor... */
7745 if (!ctl->met_relhum) {
7747 (ncid, "q", "Q", "sh", "SH", ctl, met, met->h2o, (float) (MA / MH2O)))
7748 WARN("Cannot read specific humidity!");
7749 } else {
7751 (ncid, "rh", "RH", NULL, NULL, ctl, met, met->h2o, 0.01f))
7752 WARN("Cannot read relative humidity!");
7753#pragma omp parallel for default(shared) collapse(2)
7754 for (int ix = 0; ix < met->nx; ix++)
7755 for (int iy = 0; iy < met->ny; iy++)
7756 for (int ip = 0; ip < met->np; ip++) {
7757 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
7758 met->h2o[ix][iy][ip] =
7759 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
7760 }
7761 }
7762
7763 /* Read ozone... */
7765 (ncid, "o3", "O3", NULL, NULL, ctl, met, met->o3, (float) (MA / MO3)))
7766 WARN("Cannot read ozone data!");
7767
7768 /* Read cloud data... */
7770 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, met->lwc, 1.0))
7771 WARN("Cannot read cloud liquid water content!");
7773 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, met->rwc, 1.0))
7774 WARN("Cannot read cloud rain water content!");
7776 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, met->iwc, 1.0))
7777 WARN("Cannot read cloud ice water content!");
7779 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, met->swc, 1.0))
7780 WARN("Cannot read cloud snow water content!");
7782 (ncid, "cc", "CC", NULL, NULL, ctl, met, met->cc, 1.0))
7783 WARN("Cannot read cloud cover!");
7784
7785 /* Read zeta and zeta_dot... */
7787 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, met->zetal, 1.0))
7788 WARN("Cannot read ZETA!");
7790 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
7791 NULL, ctl, met, met->zeta_dotl, 0.00001157407f))
7792 WARN("Cannot read ZETA_DOT!");
7793
7794 /* Store velocities on model levels... */
7795 if (ctl->met_vert_coord != 0) {
7796#pragma omp parallel for default(shared)
7797 for (int ix = 0; ix < met->nx; ix++)
7798 for (int iy = 0; iy < met->ny; iy++)
7799 for (int ip = 0; ip < met->np; ip++) {
7800 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
7801 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
7802 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
7803 }
7804
7805 /* Save number of model levels... */
7806 met->npl = met->np;
7807 }
7808
7809 /* Get pressure on model levels... */
7810 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
7811
7812 /* Read 3-D pressure field... */
7813 if (ctl->met_vert_coord == 1) {
7815 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, met->pl,
7816 0.01f))
7818 (ncid, "press", "PRESS", NULL, NULL, ctl, met, met->pl, 1.0))
7819 ERRMSG("Cannot read pressure on model levels!");
7820
7821 }
7822
7823 /* Use a and b coefficients for full levels... */
7824 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
7825
7826 /* Grid level coefficients... */
7827 double hyam[EP], hybm[EP];
7828
7829 /* Read coefficients... */
7830 if (ctl->met_vert_coord == 2) {
7831 int varid;
7832 NC_GET_DOUBLE("hyam", hyam, 1);
7833 NC_GET_DOUBLE("hybm", hybm, 1);
7834 }
7835
7836 /* Use control parameters... */
7837 else if (ctl->met_vert_coord == 3) {
7838
7839 /* Check number of levels... */
7840 if (met->np != ctl->met_nlev)
7841 ERRMSG("Mismatch in number of model levels!");
7842
7843 /* Copy parameters... */
7844 for (int ip = 0; ip < met->np; ip++) {
7845 hyam[ip] = ctl->met_lev_hyam[ip];
7846 hybm[ip] = ctl->met_lev_hybm[ip];
7847 }
7848 }
7849
7850 /* Calculate pressure... */
7851 for (int ix = 0; ix < met->nx; ix++)
7852 for (int iy = 0; iy < met->ny; iy++)
7853 for (int ip = 0; ip < met->np; ip++)
7854 met->pl[ix][iy][ip] =
7855 (float) (hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy]);
7856
7857 }
7858
7859 /* Use a and b coefficients for half levels... */
7860 else if (ctl->met_vert_coord == 4) {
7861
7862 /* Grid level coefficients... */
7863 double hyam[EP], hybm[EP];
7864
7865 /* Use control parameters... */
7866 for (int ip = 0; ip < met->np + 1; ip++) {
7867 hyam[ip] = ctl->met_lev_hyam[ip];
7868 hybm[ip] = ctl->met_lev_hybm[ip];
7869 }
7870
7871 /* Check number of levels... */
7872 if (met->np + 1 != ctl->met_nlev)
7873 ERRMSG("Mismatch in number of model levels!");
7874
7875 /* Calculate pressure... */
7876#pragma omp parallel for default(shared) collapse(2)
7877 for (int ix = 0; ix < met->nx; ix++)
7878 for (int iy = 0; iy < met->ny; iy++)
7879 for (int ip = 0; ip < met->np; ip++) {
7880 double p0 = hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy];
7881 double p1 = hyam[ip + 1] / 100. + hybm[ip + 1] * met->ps[ix][iy];
7882 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
7883 }
7884 }
7885
7886 /* Check ordering of pressure levels... */
7887 for (int ix = 0; ix < met->nx; ix++)
7888 for (int iy = 0; iy < met->ny; iy++)
7889 for (int ip = 1; ip < met->np; ip++)
7890 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
7891 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
7892 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
7893 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
7894 ERRMSG("Pressure profiles are not monotonic!");
7895 }
7896
7897 /* Interpolate from model levels to pressure levels... */
7898 if (ctl->met_np > 0) {
7899
7900 /* Interpolate variables... */
7901 read_met_ml2pl(ctl, met, met->t, "T");
7902 read_met_ml2pl(ctl, met, met->u, "U");
7903 read_met_ml2pl(ctl, met, met->v, "V");
7904 read_met_ml2pl(ctl, met, met->w, "W");
7905 read_met_ml2pl(ctl, met, met->h2o, "H2O");
7906 read_met_ml2pl(ctl, met, met->o3, "O3");
7907 read_met_ml2pl(ctl, met, met->lwc, "LWC");
7908 read_met_ml2pl(ctl, met, met->rwc, "RWC");
7909 read_met_ml2pl(ctl, met, met->iwc, "IWC");
7910 read_met_ml2pl(ctl, met, met->swc, "SWC");
7911 read_met_ml2pl(ctl, met, met->cc, "CC");
7912
7913 /* Set new pressure levels... */
7914 met->np = ctl->met_np;
7915 for (int ip = 0; ip < met->np; ip++) {
7916 met->p[ip] = ctl->met_p[ip];
7917 }
7918 }
7919
7920 /* Check ordering of pressure levels... */
7921 for (int ip = 1; ip < met->np; ip++)
7922 if (met->p[ip - 1] < met->p[ip])
7923 ERRMSG("Pressure levels must be descending!");
7924
7925}
7926#endif
7927
7928/*****************************************************************************/
7929
7930#ifdef DD
7931int read_met_nc_dd(
7932 const char *filename,
7933 const ctl_t *ctl,
7934 met_t *met) {
7935
7936 int ncid;
7937
7938 /* Open netCDF file... */
7939 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7940 WARN("Cannot open file!");
7941 return 0;
7942 }
7943
7944 /* Read coordinates of meteo data... */
7945 read_met_nc_grid_dd(filename, ncid, ctl, met);
7946
7947 /* Read surface data... */
7948 read_met_nc_surface_dd(ncid, ctl, met);
7949
7950 /* Read meteo data on vertical levels... */
7951 read_met_nc_levels_dd(ncid, ctl, met);
7952
7953 /* Close file... */
7954 NC(nc_close(ncid));
7955
7956 /* Return success... */
7957 return 1;
7958}
7959#endif
7960
7961
7962/*****************************************************************************/
7963
7964#ifdef DD
7966 const int ncid,
7967 const char *varname,
7968 const char *varname2,
7969 const char *varname3,
7970 const char *varname4,
7971 const char *varname5,
7972 const char *varname6,
7973 const ctl_t *ctl,
7974 const met_t *met,
7975 float dest[EX][EY],
7976 const float scl,
7977 const int init) {
7978
7979 char varsel[LEN];
7980
7981 int varid;
7982
7983 /* Check if variable exists... */
7984 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7985 sprintf(varsel, "%s", varname);
7986 else if (varname2 != NULL
7987 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7988 sprintf(varsel, "%s", varname2);
7989 else if (varname3 != NULL
7990 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7991 sprintf(varsel, "%s", varname3);
7992 else if (varname4 != NULL
7993 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7994 sprintf(varsel, "%s", varname4);
7995 else if (varname5 != NULL
7996 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
7997 sprintf(varsel, "%s", varname5);
7998 else if (varname6 != NULL
7999 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
8000 sprintf(varsel, "%s", varname6);
8001 else
8002 return 0;
8003
8004
8005
8006 /* Read fill value and missing value... */
8007 float fillval, missval;
8008 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8009 fillval = 0;
8010 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8011 missval = 0;
8012
8013 /* Write info... */
8014 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8015 varsel, fillval, missval);
8016
8017 /* Define hyperslab... */
8018 int rank, size;
8019 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
8020 MPI_Comm_size(MPI_COMM_WORLD, &size);
8021
8022 /* Allocate... */
8023 float *help;
8024 size_t help_subdomain_start[3];
8025 size_t help_subdomain_count[3];
8026
8027 help_subdomain_start[0] = 0;
8028 help_subdomain_start[1] = met->subdomain_start[2];
8029 help_subdomain_start[2] = met->subdomain_start[3];
8030
8031 help_subdomain_count[0] = 1;
8032 help_subdomain_count[1] = met->subdomain_count[2]; //y
8033 help_subdomain_count[2] = met->subdomain_count[3]; //x
8034
8035 ALLOC(help, float,
8036 (int) met->subdomain_count[2] * (int) met->subdomain_count[3]
8037 );
8038
8039 /* Read data... */
8040 NC(nc_get_vara_float
8041 (ncid, varid, help_subdomain_start, help_subdomain_count, help));
8042
8043 /* Read halos at boundaries... */
8044 size_t help_halo_bnd_start[3];
8045 size_t help_halo_bnd_count[3];
8046
8047 help_halo_bnd_start[0] = 0;
8048 help_halo_bnd_start[1] = met->halo_bnd_start[2];
8049 help_halo_bnd_start[2] = met->halo_bnd_start[3];
8050
8051 help_halo_bnd_count[0] = 1;
8052 help_halo_bnd_count[1] = met->halo_bnd_count[2]; //y
8053 help_halo_bnd_count[2] = met->halo_bnd_count[3]; //x
8054
8055 float *help_halo;
8056 ALLOC(help_halo, float,
8057 help_halo_bnd_count[1] * help_halo_bnd_count[2]);
8058 NC(nc_get_vara_float
8059 (ncid, varid, help_halo_bnd_start, help_halo_bnd_count, help_halo));
8060
8061 /* Check meteo data layout... */
8062 if (ctl->met_convention == 0) {
8063
8064 /* Copy and check data (ordering: lat, lon)... */
8065#pragma omp parallel for default(shared) num_threads(12)
8066 for (int ix = 0; ix < (int) help_subdomain_count[2]; ix++)
8067 for (int iy = 0; iy < (int) help_subdomain_count[1]; iy++) {
8068 if (init == 1)
8069 dest[ix + met->halo_offset_start][iy] = 0;
8070 float aux = help[ARRAY_2D(iy, ix, (int) help_subdomain_count[2])];
8071 if ((fillval == 0 || aux != fillval)
8072 && (missval == 0 || aux != missval)
8073 && fabsf(aux) < 1e14f) {
8074 dest[ix + met->halo_offset_start][iy] += scl * aux;
8075 } else
8076 dest[ix + met->halo_offset_start][iy] = NAN;
8077 }
8078
8079 /* Copy and check data (ordering: lat, lon)... */
8080#pragma omp parallel for default(shared) num_threads(12)
8081 for (int ix = 0; ix < (int) help_halo_bnd_count[2]; ix++)
8082 for (int iy = 0; iy < (int) help_halo_bnd_count[1]; iy++) {
8083 if (init == 1)
8084 dest[ix + met->halo_offset_end][iy] = 0;
8085 float aux = help_halo[ARRAY_2D(iy, ix, (int) help_halo_bnd_count[2])];
8086 if ((fillval == 0 || aux != fillval)
8087 && (missval == 0 || aux != missval)
8088 && fabsf(aux) < 1e14f)
8089 dest[ix + met->halo_offset_end][iy] += scl * aux;
8090 else {
8091 dest[ix + met->halo_offset_end][iy] = NAN;
8092 }
8093 }
8094
8095 } else {
8096
8097 /* Copy and check data (ordering: lon, lat)... */
8098#pragma omp parallel for default(shared) num_threads(12)
8099 for (int iy = 0; iy < met->ny; iy++)
8100 for (int ix = 0; ix < met->nx; ix++) {
8101 if (init)
8102 dest[ix][iy] = 0;
8103 float aux = help[ARRAY_2D(ix, iy, met->ny)];
8104 if ((fillval == 0 || aux != fillval)
8105 && (missval == 0 || aux != missval)
8106 && fabsf(aux) < 1e14f)
8107 dest[ix][iy] += scl * aux;
8108 else
8109 dest[ix][iy] = NAN;
8110 }
8111
8112 }
8113
8114 /* Free... */
8115 free(help);
8116 free(help_halo);
8117
8118
8119 /* Return... */
8120 return 1;
8121}
8122#endif
8123
8124/*****************************************************************************/
8125
8126#ifdef DD
8128 const int ncid,
8129 const char *varname,
8130 const char *varname2,
8131 const char *varname3,
8132 const char *varname4,
8133 const ctl_t *ctl,
8134 const met_t *met,
8135 float dest[EX][EY][EP],
8136 const float scl) {
8137
8138 char varsel[LEN];
8139
8140 int varid;
8141
8142 /* Check if variable exists... */
8143 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8144 sprintf(varsel, "%s", varname);
8145 else if (varname2 != NULL
8146 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8147 sprintf(varsel, "%s", varname2);
8148 else if (varname3 != NULL
8149 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8150 sprintf(varsel, "%s", varname3);
8151 else if (varname4 != NULL
8152 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8153 sprintf(varsel, "%s", varname4);
8154 else
8155 return 0;
8156
8157 /* Read fill value and missing value... */
8158 float fillval, missval;
8159 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8160 fillval = 0;
8161 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8162 missval = 0;
8163
8164 /* Write info... */
8165 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
8166 varsel, fillval, missval);
8167
8168 /* Define hyperslab... */
8169 int rank, size;
8170 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
8171 MPI_Comm_size(MPI_COMM_WORLD, &size);
8172
8173 /* Allocate... */
8174 float *help;
8175 ALLOC(help, float,
8176 (int) met->subdomain_count[0] * (int) met->subdomain_count[1]
8177 * (int) met->subdomain_count[2] * (int) met->subdomain_count[3]);
8178
8179 /* Read data... */
8180 NC(nc_get_vara_float
8181 (ncid, varid, met->subdomain_start, met->subdomain_count, help));
8182
8183 /* Read halos separately at boundaries... */
8184 float *help_halo;
8185 ALLOC(help_halo, float,
8186 met->halo_bnd_count[0] * met->halo_bnd_count[1] *
8187 met->halo_bnd_count[2] * met->halo_bnd_count[3]) NC(
8188 nc_get_vara_float(ncid,
8189 varid,
8190 met->halo_bnd_start,
8191 met->halo_bnd_count,
8192 help_halo));
8193
8194 /* Check meteo data layout... */
8195 if (ctl->met_convention == 0) {
8196 /* Copy and check data (ordering: lev, lat, lon)... */
8197#pragma omp parallel for default(shared) num_threads(12)
8198 for (int ix = 0; ix < (int) met->subdomain_count[3]; ix++)
8199 for (int iy = 0; iy < (int) met->subdomain_count[2]; iy++)
8200 for (int ip = 0; ip < met->np; ip++) {
8201 float aux = help[ARRAY_3D(ip, iy, (int) met->subdomain_count[2], ix,
8202 (int) met->subdomain_count[3])];
8203 if ((fillval == 0 || aux != fillval)
8204 && (missval == 0 || aux != missval)
8205 && fabsf(aux) < 1e14f)
8206 dest[ix + met->halo_offset_start][iy][ip] = scl * aux;
8207 else
8208 dest[ix + met->halo_offset_start][iy][ip] = NAN;
8209 }
8210
8211#pragma omp parallel for default(shared) num_threads(12)
8212 for (int ix = 0; ix < (int) met->halo_bnd_count[3]; ix++)
8213 for (int iy = 0; iy < (int) met->halo_bnd_count[2]; iy++)
8214 for (int ip = 0; ip < met->np; ip++) {
8215 float aux =
8216 help_halo[ARRAY_3D(ip, iy, (int) met->halo_bnd_count[2], ix,
8217 (int) met->halo_bnd_count[3])];
8218 if ((fillval == 0 || aux != fillval)
8219 && (missval == 0 || aux != missval)
8220 && fabsf(aux) < 1e14f)
8221 dest[ix + met->halo_offset_end][iy][ip] = scl * aux;
8222 else
8223 dest[ix + met->halo_offset_end][iy][ip] = NAN;
8224 }
8225
8226 } else {
8227
8228 /* Copy and check data (ordering: lon, lat, lev)... */
8229#pragma omp parallel for default(shared) num_threads(12)
8230 for (int ip = 0; ip < met->np; ip++)
8231 for (int iy = 0; iy < (int) met->subdomain_count[2]; iy++)
8232 for (int ix = 0; ix < (int) met->subdomain_count[3]; ix++) {
8233 float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
8234 if ((fillval == 0 || aux != fillval)
8235 && (missval == 0 || aux != missval)
8236 && fabsf(aux) < 1e14f)
8237 dest[ix + met->halo_offset_end][iy][ip] = scl * aux;
8238 else
8239 dest[ix + met->halo_offset_end][iy][ip] = NAN;
8240 }
8241
8242#pragma omp parallel for default(shared) num_threads(12)
8243 for (int ip = 0; ip < met->np; ip++)
8244 for (int iy = 0; iy < (int) met->halo_bnd_count[2]; iy++)
8245 for (int ix = 0; ix < (int) met->halo_bnd_count[3]; ix++) {
8246 float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
8247 if ((fillval == 0 || aux != fillval)
8248 && (missval == 0 || aux != missval)
8249 && fabsf(aux) < 1e14f)
8250 dest[ix + met->halo_offset_start][iy][ip] = scl * aux;
8251 else
8252 dest[ix + met->halo_offset_start][iy][ip] = NAN;
8253 }
8254 }
8255
8256 /* Free... */
8257 free(help);
8258 free(help_halo);
8259
8260 /* Return... */
8261 return 1;
8262}
8263#endif
8264
8265
8266/*****************************************************************************/
8267
8268#ifdef ECCODES
8269int read_met_grib(
8270 const char *filename,
8271 const ctl_t *ctl,
8272 met_t *met) {
8273
8274 /* Set filenames... */
8275 size_t filename_len = strlen(filename) + 1;
8276 char sf_filename[filename_len];
8277 char ml_filename[filename_len];
8278 strcpy(sf_filename, filename);
8279 strcpy(ml_filename, filename);
8280 get_met_replace(ml_filename, "XX", "ml");
8281 get_met_replace(sf_filename, "XX", "sf");
8282
8283 /* Open files... */
8284 FILE *ml_file = fopen(ml_filename, "rb");
8285 FILE *sf_file = fopen(sf_filename, "rb");
8286 if (ml_file == NULL || sf_file == NULL) {
8287 if (ml_file != NULL) {
8288 fclose(ml_file);
8289 WARN("Cannot open file: %s", sf_filename);
8290 }
8291 if (sf_file != NULL) {
8292 fclose(sf_file);
8293 WARN("Cannot open file: %s", ml_filename);
8294 }
8295 return 0;
8296 }
8297
8298 /* Get handles for model level data... */
8299 int ml_num_messages = 0, err = 0;
8300 ECC(codes_count_in_file(0, ml_file, &ml_num_messages));
8301 codes_handle **ml_handles =
8302 (codes_handle **) malloc(sizeof(codes_handle *) *
8303 (size_t) ml_num_messages);
8304 for (int i = 0; i < ml_num_messages; i++) {
8305 codes_handle *h = NULL;
8306 if ((h = codes_grib_handle_new_from_file(0, ml_file, &err)) != NULL)
8307 ml_handles[i] = h;
8308 }
8309
8310 /* Get handles for surface data... */
8311 int sf_num_messages = 0;
8312 ECC(codes_count_in_file(0, sf_file, &sf_num_messages));
8313 codes_handle **sf_handles =
8314 (codes_handle **) malloc(sizeof(codes_handle *) *
8315 (size_t) sf_num_messages);
8316 for (int i = 0; i < sf_num_messages; i++) {
8317 codes_handle *h = NULL;
8318 if ((h = codes_grib_handle_new_from_file(0, sf_file, &err)) != NULL)
8319 sf_handles[i] = h;
8320 }
8321
8322 /* Close files... */
8323 fclose(ml_file);
8324 fclose(sf_file);
8325
8326 /* Read grid data... */
8327 read_met_grib_grid(ml_handles, ml_num_messages, met);
8328
8329 /* Read surface data... */
8330 read_met_grib_surface(sf_handles, sf_num_messages, ctl, met);
8331 for (int i = 0; i < sf_num_messages; i++)
8332 codes_handle_delete(sf_handles[i]);
8333 free(sf_handles);
8334
8335 /* Compute 3D pressure field... */
8336 size_t value_count;
8337 ECC(codes_get_size(ml_handles[0], "pv", &value_count));
8338 double *values = (double *) malloc(value_count * sizeof(double));
8339 ECC(codes_get_double_array(ml_handles[0], "pv", values, &value_count));
8340 double a_vals[138], b_vals[138];
8341 for (int i = 0; i <= 137; i++) {
8342 a_vals[i] = values[i];
8343 b_vals[i] = values[i + 137];
8344 }
8345 for (int nx = 0; nx < met->nx; nx++)
8346 for (int ny = 0; ny < met->ny; ny++)
8347 for (int level = 0; level <= met->npl; level++) {
8348 const float p1 =
8349 (float) ((a_vals[level] * 0.01f + met->ps[nx][ny] * b_vals[level]));
8350 const float p2 =
8351 (float) ((a_vals[level + 1] * 0.01f +
8352 met->ps[nx][ny] * b_vals[level + 1]));
8353 met->pl[nx][ny][level] = (p1 + p2) * 0.5f;
8354 }
8355
8356 /* Read model level data... */
8357 read_met_grib_levels(ml_handles, ml_num_messages, ctl, met);
8358 for (int i = 0; i < ml_num_messages; i++)
8359 codes_handle_delete(ml_handles[i]);
8360 free(ml_handles);
8361
8362 /* Return success... */
8363 return 1;
8364}
8365#endif
8366
8367/*****************************************************************************/
8368
8369#ifdef ECCODES
8370void read_met_grib_grid(
8371 codes_handle **handles,
8372 int count_handles,
8373 met_t *met) {
8374
8375 /* Set timer... */
8376 SELECT_TIMER("READ_MET_GRIB_GRID", "INPUT", NVTX_READ);
8377 LOG(2, "Read meteo grid information...");
8378
8379 /* Read date... */
8380 char datestr[50];
8381 char timestr[50];
8382 char year[20], month[20], day[20], hour[20];
8383 size_t s = sizeof(datestr);
8384
8385 ECC(codes_get_string(handles[0], "dataDate", datestr, &s));
8386 ECC(codes_get_string(handles[0], "dataTime", timestr, &s));
8387 strncpy(year, datestr, 4);
8388 year[4] = '\0';
8389 strncpy(month, datestr + 4, 2);
8390 month[2] = '\0';
8391 strncpy(day, datestr + 6, 2);
8392 day[2] = '\0';
8393 strncpy(hour, timestr, 2);
8394 hour[2] = '\0';
8395 time2jsec(atoi(year), atoi(month), atoi(day), atoi(hour), 0, 0, 0,
8396 &(met->time));
8397
8398 /* Write info... */
8399 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
8400 met->time, atoi(year), atoi(month), atoi(day), atoi(hour), 0);
8401
8402 /* Read grid information... */
8403 long count_lat = 0, count_lon = 0;
8404 ECC(codes_get_long(handles[0], "Nj", &count_lat));
8405 ECC(codes_get_long(handles[0], "Ni", &count_lon));
8406 met->ny = (int) count_lat;
8407 met->nx = (int) count_lon;
8408
8409 /* Check grid dimensions... */
8410 LOG(2, "Number of longitudes: %d", met->nx);
8411 if (met->nx < 2 || met->nx > EX)
8412 ERRMSG("Number of longitudes out of range!");
8413 LOG(2, "Number of latitudes: %d", met->ny);
8414 if (met->ny < 2 || met->ny > EY)
8415 ERRMSG("Number of latitudes out of range!");
8416
8417 double first_lon, last_lon, first_lat, last_lat, inc_lon, inc_lat;
8418 ECC(codes_get_double
8419 (handles[0], "longitudeOfFirstGridPointInDegrees", &first_lon));
8420 ECC(codes_get_double
8421 (handles[0], "latitudeOfFirstGridPointInDegrees", &first_lat));
8422 ECC(codes_get_double
8423 (handles[0], "longitudeOfLastGridPointInDegrees", &last_lon));
8424 ECC(codes_get_double
8425 (handles[0], "latitudeOfLastGridPointInDegrees", &last_lat));
8426 ECC(codes_get_double(handles[0], "iDirectionIncrementInDegrees", &inc_lon));
8427 ECC(codes_get_double(handles[0], "jDirectionIncrementInDegrees", &inc_lat));
8428
8429 long jscanpos, iscanneg;
8430 ECC(codes_get_long(handles[0], "iScansNegatively", &iscanneg));
8431 ECC(codes_get_long(handles[0], "jScansPositively", &jscanpos));
8432
8433 /* Compute longitude-latitude grid... */
8434 int counter = 0;
8435 if (iscanneg == 0)
8436 for (double i = first_lon; i <= last_lon + 1e-6; i += inc_lon) {
8437 met->lon[counter] = i;
8438 counter += 1;
8439 } else
8440 for (double i = first_lon; i > last_lon - 1e-6; i -= inc_lon) {
8441 met->lon[counter] = i;
8442 counter += 1;
8443 }
8444
8445 counter = 0;
8446 if (jscanpos == 0)
8447 for (double i = first_lat; i > last_lat - 1e-6; i -= inc_lat) {
8448 met->lat[counter] = i;
8449 counter += 1;
8450 } else
8451 for (double i = first_lat; i <= last_lat + 1e-6; i += inc_lat) {
8452 met->lat[counter] = i;
8453 counter += 1;
8454 }
8455
8456 /* Write info... */
8457 LOG(2, "Longitudes: %g, %g ... %g deg",
8458 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
8459 LOG(2, "Latitudes: %g, %g ... %g deg",
8460 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
8461
8462 /* Read vertical levels... */
8463 int max_level = 0;
8464 for (int i = 0; i < count_handles; i++) {
8465 long level;
8466 ECC(codes_get_long(handles[i], "level", &level));
8467 if (level > max_level)
8468 max_level = (int) level;
8469 }
8470 met->npl = max_level;
8471
8472 /* Check number of levels... */
8473 LOG(2, "Number of levels: %d", met->npl);
8474 if (met->npl < 2 || met->npl > EP)
8475 ERRMSG("Number of levels out of range!");
8476}
8477#endif
8478
8479/*****************************************************************************/
8480
8481#ifdef ECCODES
8482void read_met_grib_levels(
8483 codes_handle **handles,
8484 const int num_messages,
8485 const ctl_t *ctl,
8486 met_t *met) {
8487
8488 /* Set timer... */
8489 SELECT_TIMER("READ_MET_GRIB_LEVELS", "INPUT", NVTX_READ);
8490 LOG(2, "Read level data...");
8491
8492 /* Init... */
8493 int t_flag = 0, u_flag = 0, v_flag = 0, w_flag = 0, o3_flag = 0, h2o_flag =
8494 0, lwc_flag = 0, rwc_flag = 0, iwc_flag = 0, swc_flag = 0, cc_flag = 0;
8495
8496 /* Iterate over all messages... */
8497 for (int i = 0; i < num_messages; i++) {
8498
8499 size_t max_size = 50;
8500 char short_name[max_size];
8501 size_t value_count;
8502 double *values;
8503
8504 /* Get the current level */
8505 long current_level;
8506 ECC(codes_get_long(handles[i], "level", &current_level));
8507 current_level -= 1;
8508
8509 /* Retrieve data from current message */
8510 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
8511 ECC(codes_get_size(handles[i], "values", &value_count));
8512 ALLOC(values, double,
8513 value_count);
8514 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
8515
8516 /* Read temperature... */
8517 ECC_READ_3D("t", current_level, met->t, 1.0, t_flag);
8518
8519 /* Read horizontal wind and vertical velocity... */
8520 ECC_READ_3D("u", current_level, met->u, 1.0, u_flag);
8521 ECC_READ_3D("v", current_level, met->v, 1.0, v_flag);
8522 ECC_READ_3D("w", current_level, met->w, 0.01f, w_flag);
8523
8524 /* Read water vapor and ozone... */
8525 ECC_READ_3D("q", current_level, met->h2o, (float) (MA / MH2O), h2o_flag);
8526 ECC_READ_3D("o3", current_level, met->o3, (float) (MA / MO3), o3_flag);
8527
8528 /* Read cloud data... */
8529 ECC_READ_3D("clwc", current_level, met->lwc, 1.0, lwc_flag);
8530 ECC_READ_3D("crwc", current_level, met->rwc, 1.0, rwc_flag);
8531 ECC_READ_3D("ciwc", current_level, met->iwc, 1.0, iwc_flag);
8532 ECC_READ_3D("cswc", current_level, met->swc, 1.0, swc_flag);
8533 ECC_READ_3D("cc", current_level, met->cc, 1.0, cc_flag);
8534
8535 /*Free allocated array */
8536 free(values);
8537 }
8538
8539 /* Check whether data were found... */
8540 if (t_flag != met->npl)
8541 ERRMSG("Cannot read temperature!");
8542 if (u_flag != met->npl)
8543 ERRMSG("Cannot read zonal wind!");
8544 if (v_flag != met->npl)
8545 ERRMSG("Cannot read meridional wind!");
8546 if (w_flag != met->npl)
8547 WARN("Cannot read vertical velocity!");
8548 if (h2o_flag != met->npl)
8549 WARN("Cannot read specific humidity!");
8550 if (o3_flag != met->npl)
8551 WARN("Cannot read ozone data!");
8552 if (lwc_flag != met->npl)
8553 WARN("Cannot read cloud liquid water content!");
8554 if (rwc_flag != met->npl)
8555 WARN("Cannot read cloud rain water content!");
8556 if (iwc_flag != met->npl)
8557 WARN("Cannot read cloud ice water content!");
8558 if (swc_flag != met->npl)
8559 WARN("Cannot read cloud snow water content!");
8560 if (cc_flag != met->npl)
8561 WARN("Cannot read cloud cover!");
8562
8563 /* Check ordering of pressure levels... */
8564 for (int ix = 0; ix < met->nx; ix++)
8565 for (int iy = 0; iy < met->ny; iy++)
8566 for (int ip = 1; ip < met->np; ip++)
8567 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
8568 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
8569 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
8570 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip])) {
8571 LOG(1, "%f %f %f %f", met->pl[ix][iy][0], met->pl[ix][iy][1],
8572 met->pl[ix][iy][ip - 1], met->pl[ix][iy][ip]);
8573 ERRMSG("Pressure profiles are not monotonic!");
8574 }
8575
8576 /* Interpolate from model levels to pressure levels... */
8577 if (ctl->met_np > 0) {
8578 met->np = ctl->met_np;
8579
8580 /* Interpolate variables... */
8581 read_met_ml2pl(ctl, met, met->t, "T");
8582 read_met_ml2pl(ctl, met, met->u, "U");
8583 read_met_ml2pl(ctl, met, met->v, "V");
8584 read_met_ml2pl(ctl, met, met->w, "W");
8585 read_met_ml2pl(ctl, met, met->h2o, "H2O");
8586 read_met_ml2pl(ctl, met, met->o3, "O3");
8587 read_met_ml2pl(ctl, met, met->lwc, "LWC");
8588 read_met_ml2pl(ctl, met, met->rwc, "RWC");
8589 read_met_ml2pl(ctl, met, met->iwc, "IWC");
8590 read_met_ml2pl(ctl, met, met->swc, "SWC");
8591 read_met_ml2pl(ctl, met, met->cc, "CC");
8592
8593 /* Set new pressure levels... */
8594 for (int ip = 0; ip < met->np; ip++)
8595 met->p[ip] = ctl->met_p[ip];
8596 }
8597
8598 /* Check ordering of pressure levels... */
8599 for (int ip = 1; ip < met->np; ip++)
8600 if (met->p[ip - 1] < met->p[ip])
8601 ERRMSG("Pressure levels must be descending!");
8602}
8603#endif
8604
8605/*****************************************************************************/
8606
8607#ifdef ECCODES
8608void read_met_grib_surface(
8609 codes_handle **handles,
8610 const int num_messages,
8611 const ctl_t *ctl,
8612 met_t *met) {
8613
8614 /* Set timer... */
8615 SELECT_TIMER("READ_MET_GRIB_SURFACE", "INPUT", NVTX_READ);
8616 LOG(2, "Read surface data...");
8617
8618 /* Init... */
8619 int sp_flag = 0, z_flag = 0, t_flag = 0, u_flag = 0, v_flag = 0, lsm_flag =
8620 0, sst_flag = 0, cape_flag = 0, cin_flag = 0, pbl_flag = 0;
8621
8622 /* Iterate over all messages... */
8623 for (int i = 0; i < num_messages; i++) {
8624
8625 size_t max_size = 50;
8626 char short_name[max_size];
8627 size_t value_count;
8628
8629 /* Store values with shortname... */
8630 ECC(codes_get_string(handles[i], "shortName", short_name, &max_size));
8631 ECC(codes_get_size(handles[i], "values", &value_count));
8632 double *values = (double *) malloc(value_count * sizeof(double));
8633 ECC(codes_get_double_array(handles[i], "values", values, &value_count));
8634
8635 /*Read surface pressure... */
8636 ECC_READ_2D("sp", met->ps, 0.01f, sp_flag);
8637
8638 /*Read geopotential height at the surface... */
8639 ECC_READ_2D("z", met->zs, (float) (1. / (1000. * G0)), z_flag);
8640
8641 /* Read temperature at the surface... */
8642 ECC_READ_2D("2t", met->ts, 1.0f, t_flag);
8643
8644 /* Read zonal wind at the surface... */
8645 ECC_READ_2D("10u", met->us, 1.0f, u_flag);
8646
8647 /* Read meridional wind at the surface... */
8648 ECC_READ_2D("10v", met->vs, 1.0f, v_flag);
8649
8650 /* Read land-sea mask... */
8651 ECC_READ_2D("lsm", met->lsm, 1.0f, lsm_flag);
8652
8653 /* Read sea surface temperature... */
8654 ECC_READ_2D("sst", met->sst, 1.0f, sst_flag);
8655 if (ctl->met_cape == 0) {
8656
8657 /* Read CAPE... */
8658 ECC_READ_2D("cape", met->cape, 1.0f, cape_flag);
8659
8660 /* Read CIN... */
8661 ECC_READ_2D("cin", met->cin, 1.0f, cin_flag);
8662 }
8663
8664 /* Read PBL... */
8665 if (ctl->met_pbl == 0)
8666 ECC_READ_2D("blh", met->pbl, 0.0001f, pbl_flag);
8667
8668 /* Free... */
8669 free(values);
8670 }
8671
8672 /* Check whether data have been read... */
8673 if (sp_flag == 0)
8674 WARN("Cannot read surface pressure data!");
8675 if (z_flag == 0)
8676 WARN("Cannot read surface geopotential height!");
8677 if (t_flag == 0)
8678 WARN("Cannot read surface temperature!");
8679 if (u_flag == 0)
8680 WARN("Cannot read surface zonal wind!");
8681 if (v_flag == 0)
8682 WARN("Cannot read surface meridional wind!");
8683 if (lsm_flag == 0)
8684 WARN("Cannot read land-sea mask!");
8685 if (sst_flag == 0)
8686 WARN("Cannot read sea surface temperature!");
8687 if (ctl->met_cape == 0) {
8688 if (cape_flag == 0)
8689 WARN("Cannot read CAPE!");
8690 if (cin_flag == 0)
8691 WARN("Cannot read convective inhibition!");
8692 }
8693 if (ctl->met_pbl == 0 && pbl_flag == 0)
8694 WARN("Cannot read planetary boundary layer!");
8695}
8696#endif
8697
8698/*****************************************************************************/
8699
8701 const ctl_t *ctl,
8702 const met_t *met,
8703 float var[EX][EY][EP],
8704 const char *varname) {
8705
8706 double aux[EP], p[EP];
8707
8708 /* Set timer... */
8709 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
8710 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
8711
8712 /* Loop over columns... */
8713#pragma omp parallel for default(shared) private(aux,p) collapse(2)
8714 for (int ix = 0; ix < met->nx; ix++)
8715 for (int iy = 0; iy < met->ny; iy++) {
8716
8717 /* Copy pressure profile... */
8718 for (int ip = 0; ip < met->np; ip++)
8719 p[ip] = met->pl[ix][iy][ip];
8720
8721 /* Interpolate... */
8722 for (int ip = 0; ip < ctl->met_np; ip++) {
8723 double pt = ctl->met_p[ip];
8724 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
8725 pt = p[0];
8726 else if ((pt > p[met->np - 1] && p[1] > p[0])
8727 || (pt < p[met->np - 1] && p[1] < p[0]))
8728 pt = p[met->np - 1];
8729 int ip2 = locate_irr(p, met->np, pt);
8730 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
8731 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
8732 }
8733
8734 /* Copy data... */
8735 for (int ip = 0; ip < ctl->met_np; ip++)
8736 var[ix][iy][ip] = (float) aux[ip];
8737 }
8738}
8739
8740/*****************************************************************************/
8741
8743 const ctl_t *ctl,
8744 met_t *met) {
8745
8746 /* Check parameters... */
8747 if (ctl->advect_vert_coord != 1)
8748 return;
8749
8750 /* Set timer... */
8751 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
8752 LOG(2, "Make zeta profiles monotone...");
8753
8754 /* Create monotone zeta profiles... */
8755#pragma omp parallel for default(shared) collapse(2)
8756 for (int i = 0; i < met->nx; i++)
8757 for (int j = 0; j < met->ny; j++) {
8758 int k = 1;
8759
8760 while (k < met->npl) { /* Check if there is an inversion at level k... */
8761 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
8762 /* Find the upper level k+l over the inversion... */
8763 int l = 0;
8764 do {
8765 l++;
8766 }
8767 while ((met->zetal[i][j][k - 1] >=
8768 met->zetal[i][j][k + l]) & (k + l < met->npl));
8769
8770 /* Interpolate linear between the top and bottom
8771 of the inversion... */
8772 float s =
8773 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
8774 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
8775
8776 for (int m = k; m < k + l; m++) {
8777 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
8778 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
8779 }
8780
8781 /* Search for more inversions above the last inversion ... */
8782 k = k + l;
8783 } else {
8784 k++;
8785 }
8786 }
8787 }
8788
8789 /* Create monotone pressure profiles... */
8790#pragma omp parallel for default(shared) collapse(2)
8791 for (int i = 0; i < met->nx; i++)
8792 for (int j = 0; j < met->ny; j++) {
8793 int k = 1;
8794
8795 while (k < met->npl) { /* Check if there is an inversion at level k... */
8796 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
8797
8798 /* Find the upper level k+l over the inversion... */
8799 int l = 0;
8800 do {
8801 l++;
8802 }
8803 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
8804 met->npl));
8805
8806 /* Interpolate linear between the top and bottom
8807 of the inversion... */
8808 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
8809 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
8810
8811 for (int m = k; m < k + l; m++) {
8812 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
8813 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
8814 }
8815
8816 /* Search for more inversions above the last inversion ... */
8817 k += l;
8818 } else {
8819 k++;
8820 }
8821 }
8822 }
8823}
8824
8825/*****************************************************************************/
8826
8828 const char *filename,
8829 const ctl_t *ctl,
8830 met_t *met) {
8831
8832 int ncid;
8833
8834 /* Open netCDF file... */
8835 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
8836 WARN("Cannot open file!");
8837 return 0;
8838 }
8839
8840 /* Read coordinates of meteo data... */
8841 read_met_nc_grid(filename, ncid, ctl, met);
8842
8843 /* Read surface data... */
8844 read_met_nc_surface(ncid, ctl, met);
8845
8846 /* Read meteo data on vertical levels... */
8847 read_met_nc_levels(ncid, ctl, met);
8848
8849 /* Close file... */
8850 NC(nc_close(ncid));
8851
8852 /* Return success... */
8853 return 1;
8854}
8855
8856/*****************************************************************************/
8857
8859 const int ncid,
8860 const char *varname,
8861 const char *varname2,
8862 const char *varname3,
8863 const char *varname4,
8864 const char *varname5,
8865 const char *varname6,
8866 const ctl_t *ctl,
8867 const met_t *met,
8868 float dest[EX][EY],
8869 const float scl,
8870 const int init) {
8871
8872 char varsel[LEN];
8873
8874 float offset, scalfac;
8875
8876 int varid;
8877
8878 /* Check if variable exists... */
8879 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
8880 sprintf(varsel, "%s", varname);
8881 else if (varname2 != NULL
8882 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
8883 sprintf(varsel, "%s", varname2);
8884 else if (varname3 != NULL
8885 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
8886 sprintf(varsel, "%s", varname3);
8887 else if (varname4 != NULL
8888 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
8889 sprintf(varsel, "%s", varname4);
8890 else if (varname5 != NULL
8891 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
8892 sprintf(varsel, "%s", varname5);
8893 else if (varname6 != NULL
8894 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
8895 sprintf(varsel, "%s", varname6);
8896 else
8897 return 0;
8898
8899 /* Read packed data... */
8900 if (ctl->met_nc_scale
8901 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
8902 && nc_get_att_float(ncid, varid, "scale_factor",
8903 &scalfac) == NC_NOERR) {
8904
8905 /* Allocate... */
8906 short *help;
8907 ALLOC(help, short,
8908 EX * EY * EP);
8909
8910 /* Read fill value and missing value... */
8911 short fillval, missval;
8912 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8913 fillval = 0;
8914 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
8915 missval = 0;
8916
8917 /* Write info... */
8918 LOG(2, "Read 2-D variable: %s"
8919 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
8920 varsel, fillval, missval, scalfac, offset);
8921
8922 /* Read data... */
8923 NC(nc_get_var_short(ncid, varid, help));
8924
8925 /* Check meteo data layout... */
8926 if (ctl->met_convention != 0)
8927 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
8928
8929 /* Copy and check data... */
8930 omp_set_dynamic(1);
8931#pragma omp parallel for default(shared)
8932 for (int ix = 0; ix < met->nx; ix++)
8933 for (int iy = 0; iy < met->ny; iy++) {
8934 if (init)
8935 dest[ix][iy] = 0;
8936 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
8937 if ((fillval == 0 || aux != fillval)
8938 && (missval == 0 || aux != missval)
8939 && fabsf(aux * scalfac + offset) < 1e14f)
8940 dest[ix][iy] += scl * (aux * scalfac + offset);
8941 else
8942 dest[ix][iy] = NAN;
8943 }
8944 omp_set_dynamic(0);
8945
8946 /* Free... */
8947 free(help);
8948 }
8949
8950 /* Unpacked data... */
8951 else {
8952
8953 /* Allocate... */
8954 float *help;
8955 ALLOC(help, float,
8956 EX * EY);
8957
8958 /* Read fill value and missing value... */
8959 float fillval, missval;
8960 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
8961 fillval = 0;
8962 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
8963 missval = 0;
8964
8965 /* Write info... */
8966 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
8967 varsel, fillval, missval);
8968
8969 /* Read data... */
8970 NC(nc_get_var_float(ncid, varid, help));
8971
8972 /* Check meteo data layout... */
8973 if (ctl->met_convention == 0) {
8974
8975 /* Copy and check data (ordering: lat, lon)... */
8976 omp_set_dynamic(1);
8977#pragma omp parallel for default(shared)
8978 for (int ix = 0; ix < met->nx; ix++)
8979 for (int iy = 0; iy < met->ny; iy++) {
8980 if (init)
8981 dest[ix][iy] = 0;
8982 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
8983 if ((fillval == 0 || aux != fillval)
8984 && (missval == 0 || aux != missval)
8985 && fabsf(aux) < 1e14f)
8986 dest[ix][iy] += scl * aux;
8987 else
8988 dest[ix][iy] = NAN;
8989 }
8990 omp_set_dynamic(0);
8991
8992 } else {
8993
8994 /* Copy and check data (ordering: lon, lat)... */
8995 omp_set_dynamic(1);
8996#pragma omp parallel for default(shared)
8997 for (int iy = 0; iy < met->ny; iy++)
8998 for (int ix = 0; ix < met->nx; ix++) {
8999 if (init)
9000 dest[ix][iy] = 0;
9001 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
9002 if ((fillval == 0 || aux != fillval)
9003 && (missval == 0 || aux != missval)
9004 && fabsf(aux) < 1e14f)
9005 dest[ix][iy] += scl * aux;
9006 else
9007 dest[ix][iy] = NAN;
9008 }
9009 omp_set_dynamic(0);
9010 }
9011
9012 /* Free... */
9013 free(help);
9014 }
9015
9016 /* Return... */
9017 return 1;
9018}
9019
9020/*****************************************************************************/
9021
9023 const int ncid,
9024 const char *varname,
9025 const char *varname2,
9026 const char *varname3,
9027 const char *varname4,
9028 const ctl_t *ctl,
9029 const met_t *met,
9030 float dest[EX][EY][EP],
9031 const float scl) {
9032
9033 char varsel[LEN];
9034
9035 float offset, scalfac;
9036
9037 int varid;
9038
9039 /* Check if variable exists... */
9040 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
9041 sprintf(varsel, "%s", varname);
9042 else if (varname2 != NULL
9043 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
9044 sprintf(varsel, "%s", varname2);
9045 else if (varname3 != NULL
9046 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
9047 sprintf(varsel, "%s", varname3);
9048 else if (varname4 != NULL
9049 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
9050 sprintf(varsel, "%s", varname4);
9051 else
9052 return 0;
9053
9054 /* Read packed data... */
9055 if (ctl->met_nc_scale
9056 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
9057 && nc_get_att_float(ncid, varid, "scale_factor",
9058 &scalfac) == NC_NOERR) {
9059
9060 /* Allocate... */
9061 short *help;
9062 ALLOC(help, short,
9063 EX * EY * EP);
9064
9065 /* Read fill value and missing value... */
9066 short fillval, missval;
9067 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9068 fillval = 0;
9069 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
9070 missval = 0;
9071
9072 /* Write info... */
9073 LOG(2, "Read 3-D variable: %s "
9074 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
9075 varsel, fillval, missval, scalfac, offset);
9076
9077 /* Read data... */
9078 NC(nc_get_var_short(ncid, varid, help));
9079
9080 /* Check meteo data layout... */
9081 if (ctl->met_convention != 0)
9082 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
9083
9084 /* Copy and check data... */
9085 omp_set_dynamic(1);
9086#pragma omp parallel for default(shared)
9087 for (int ix = 0; ix < met->nx; ix++)
9088 for (int iy = 0; iy < met->ny; iy++)
9089 for (int ip = 0; ip < met->np; ip++) {
9090 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9091 if ((fillval == 0 || aux != fillval)
9092 && (missval == 0 || aux != missval)
9093 && fabsf(aux * scalfac + offset) < 1e14f)
9094 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
9095 else
9096 dest[ix][iy][ip] = NAN;
9097 }
9098 omp_set_dynamic(0);
9099
9100 /* Free... */
9101 free(help);
9102 }
9103
9104 /* Unpacked data... */
9105 else {
9106
9107 /* Allocate... */
9108 float *help;
9109 ALLOC(help, float,
9110 EX * EY * EP);
9111
9112 /* Read fill value and missing value... */
9113 float fillval, missval;
9114 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
9115 fillval = 0;
9116 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
9117 missval = 0;
9118
9119 /* Write info... */
9120 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
9121 varsel, fillval, missval);
9122
9123 /* Read data... */
9124 NC(nc_get_var_float(ncid, varid, help));
9125
9126 /* Check meteo data layout... */
9127 if (ctl->met_convention == 0) {
9128
9129 /* Copy and check data (ordering: lev, lat, lon)... */
9130 omp_set_dynamic(1);
9131#pragma omp parallel for default(shared)
9132 for (int ix = 0; ix < met->nx; ix++)
9133 for (int iy = 0; iy < met->ny; iy++)
9134 for (int ip = 0; ip < met->np; ip++) {
9135 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
9136 if ((fillval == 0 || aux != fillval)
9137 && (missval == 0 || aux != missval)
9138 && fabsf(aux) < 1e14f)
9139 dest[ix][iy][ip] = scl * aux;
9140 else
9141 dest[ix][iy][ip] = NAN;
9142 }
9143 omp_set_dynamic(0);
9144
9145 } else {
9146
9147 /* Copy and check data (ordering: lon, lat, lev)... */
9148 omp_set_dynamic(1);
9149#pragma omp parallel for default(shared)
9150 for (int ip = 0; ip < met->np; ip++)
9151 for (int iy = 0; iy < met->ny; iy++)
9152 for (int ix = 0; ix < met->nx; ix++) {
9153 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
9154 if ((fillval == 0 || aux != fillval)
9155 && (missval == 0 || aux != missval)
9156 && fabsf(aux) < 1e14f)
9157 dest[ix][iy][ip] = scl * aux;
9158 else
9159 dest[ix][iy][ip] = NAN;
9160 }
9161 omp_set_dynamic(0);
9162 }
9163
9164 /* Free... */
9165 free(help);
9166 }
9167
9168 /* Return... */
9169 return 1;
9170}
9171
9172/*****************************************************************************/
9173
9175 const char *filename,
9176 const int ncid,
9177 const ctl_t *ctl,
9178 met_t *met) {
9179
9180 char levname[LEN], tstr[10];
9181
9182 double rtime = 0, r, r2;
9183
9184 int varid, ndims, dimids[NC_MAX_DIMS], year2, mon2, day2, hour2, min2, sec2,
9185 year, mon, day, hour, min, sec;
9186
9187 size_t dimlen;
9188
9189 /* Set timer... */
9190 SELECT_TIMER("READ_MET_NC_GRID", "INPUT", NVTX_READ);
9191 LOG(2, "Read meteo grid information...");
9192
9193 /* MPTRAC meteo files... */
9194 if (ctl->met_clams == 0) {
9195
9196 /* Get time from filename... */
9197 met->time = time_from_filename(filename, 16);
9198
9199 /* Check time information from data file... */
9200 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
9201 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
9202 NC(nc_get_var_double(ncid, varid, &rtime));
9203 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
9204 WARN("Time information in meteo file does not match filename!");
9205 } else
9206 WARN("Time information in meteo file is missing!");
9207 }
9208
9209 /* CLaMS meteo files... */
9210 else {
9211
9212 /* Read time from file... */
9213 NC_GET_DOUBLE("time", &rtime, 0);
9214
9215 /* Get time from filename (considering the century)... */
9216 if (rtime < 0)
9217 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
9218 else
9219 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
9220 year = atoi(tstr);
9221 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
9222 mon = atoi(tstr);
9223 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
9224 day = atoi(tstr);
9225 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
9226 hour = atoi(tstr);
9227 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
9228 }
9229
9230 /* Check time... */
9231 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
9232 || day < 1 || day > 31 || hour < 0 || hour > 23)
9233 ERRMSG("Cannot read time from filename!");
9234 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
9235 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
9236 met->time, year2, mon2, day2, hour2, min2);
9237
9238 /* Get grid dimensions... */
9239 NC_INQ_DIM("lon", &met->nx, 2, EX);
9240 LOG(2, "Number of longitudes: %d", met->nx);
9241
9242 NC_INQ_DIM("lat", &met->ny, 2, EY);
9243 LOG(2, "Number of latitudes: %d", met->ny);
9244
9245 /* Read longitudes and latitudes... */
9246 NC_GET_DOUBLE("lon", met->lon, 1);
9247 LOG(2, "Longitudes: %g, %g ... %g deg",
9248 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
9249 NC_GET_DOUBLE("lat", met->lat, 1);
9250 LOG(2, "Latitudes: %g, %g ... %g deg",
9251 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
9252
9253 /* Check grid spacing... */
9254 for (int ix = 2; ix < met->nx; ix++)
9255 if (fabs
9256 (fabs(met->lon[ix] - met->lon[ix - 1]) -
9257 fabs(met->lon[1] - met->lon[0])) > 0.001)
9258 ERRMSG("No regular grid spacing in longitudes!");
9259 for (int iy = 2; iy < met->ny; iy++)
9260 if (fabs
9261 (fabs(met->lat[iy] - met->lat[iy - 1]) -
9262 fabs(met->lat[1] - met->lat[0])) > 0.001) {
9263 WARN("No regular grid spacing in latitudes!");
9264 break;
9265 }
9266
9267 /* Get vertical dimension... */
9268 if (nc_inq_varid(ncid, "u", &varid) != NC_NOERR)
9269 if (nc_inq_varid(ncid, "U", &varid) != NC_NOERR)
9270 ERRMSG
9271 ("Variable 'u' or 'U' not found, cannot determine vertical dimension!");
9272
9273 NC(nc_inq_varndims(ncid, varid, &ndims));
9274 NC(nc_inq_vardimid(ncid, varid, dimids));
9275
9276 if (ndims == 4) {
9277 NC(nc_inq_dim
9278 (ncid, dimids[ctl->met_convention == 0 ? 1 : 3], levname, &dimlen));
9279 } else if (ndims == 3) {
9280 NC(nc_inq_dim
9281 (ncid, dimids[ctl->met_convention == 0 ? 0 : 2], levname, &dimlen));
9282 } else
9283 ERRMSG("Cannot determine vertical dimension!")
9284 met->np = (int) dimlen;
9285
9286 LOG(2, "Number of levels: %d", met->np);
9287 if (met->np < 2 || met->np > EP)
9288 ERRMSG("Number of levels out of range!");
9289
9290 /* Read pressure levels... */
9291 if (ctl->met_np <= 0) {
9292 NC_GET_DOUBLE(levname, met->p, 1);
9293 for (int ip = 0; ip < met->np; ip++)
9294 met->p[ip] /= 100.;
9295 LOG(2, "Altitude levels: %g, %g ... %g km",
9296 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
9297 LOG(2, "Pressure levels: %g, %g ... %g hPa",
9298 met->p[0], met->p[1], met->p[met->np - 1]);
9299 }
9300
9301 /* Read hybrid levels... */
9302 if (strcasecmp(levname, "hybrid") == 0)
9303 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
9304}
9305
9306/*****************************************************************************/
9307
9309 const int ncid,
9310 const ctl_t *ctl,
9311 met_t *met) {
9312
9313 /* Set timer... */
9314 SELECT_TIMER("READ_MET_NC_LEVELS", "INPUT", NVTX_READ);
9315 LOG(2, "Read level data...");
9316
9317 /* Read temperature... */
9318 if (!read_met_nc_3d(ncid, "t", "T", "temp", "TEMP", ctl, met, met->t, 1.0))
9319 ERRMSG("Cannot read temperature!");
9320
9321 /* Read horizontal wind and vertical velocity... */
9322 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, met->u, 1.0))
9323 ERRMSG("Cannot read zonal wind!");
9324 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, met->v, 1.0))
9325 ERRMSG("Cannot read meridional wind!");
9326 if (!read_met_nc_3d
9327 (ncid, "w", "W", "omega", "OMEGA", ctl, met, met->w, 0.01f))
9328 WARN("Cannot read vertical velocity!");
9329
9330 /* Read water vapor... */
9331 if (!ctl->met_relhum) {
9332 if (!read_met_nc_3d
9333 (ncid, "q", "Q", "sh", "SH", ctl, met, met->h2o, (float) (MA / MH2O)))
9334 WARN("Cannot read specific humidity!");
9335 } else {
9336 if (!read_met_nc_3d
9337 (ncid, "rh", "RH", NULL, NULL, ctl, met, met->h2o, 0.01f))
9338 WARN("Cannot read relative humidity!");
9339#pragma omp parallel for default(shared) collapse(2)
9340 for (int ix = 0; ix < met->nx; ix++)
9341 for (int iy = 0; iy < met->ny; iy++)
9342 for (int ip = 0; ip < met->np; ip++) {
9343 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
9344 met->h2o[ix][iy][ip] =
9345 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
9346 }
9347 }
9348
9349 /* Read ozone... */
9350 if (!read_met_nc_3d
9351 (ncid, "o3", "O3", NULL, NULL, ctl, met, met->o3, (float) (MA / MO3)))
9352 WARN("Cannot read ozone data!");
9353
9354 /* Read cloud data... */
9355 if (!read_met_nc_3d
9356 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, met->lwc, 1.0))
9357 WARN("Cannot read cloud liquid water content!");
9358 if (!read_met_nc_3d
9359 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, met->rwc, 1.0))
9360 WARN("Cannot read cloud rain water content!");
9361 if (!read_met_nc_3d
9362 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, met->iwc, 1.0))
9363 WARN("Cannot read cloud ice water content!");
9364 if (!read_met_nc_3d
9365 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, met->swc, 1.0))
9366 WARN("Cannot read cloud snow water content!");
9367 if (!read_met_nc_3d(ncid, "cc", "CC", NULL, NULL, ctl, met, met->cc, 1.0))
9368 WARN("Cannot read cloud cover!");
9369
9370 /* Read zeta and zeta_dot... */
9371 if (!read_met_nc_3d
9372 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, met->zetal, 1.0))
9373 WARN("Cannot read ZETA!");
9374 if (!read_met_nc_3d
9375 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
9376 NULL, ctl, met, met->zeta_dotl, 0.00001157407f))
9377 WARN("Cannot read ZETA_DOT!");
9378
9379 /* Store velocities on model levels... */
9380 if (ctl->met_vert_coord != 0) {
9381 for (int ix = 0; ix < met->nx; ix++)
9382 for (int iy = 0; iy < met->ny; iy++)
9383 for (int ip = 0; ip < met->np; ip++) {
9384 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
9385 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
9386 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
9387 }
9388
9389 /* Save number of model levels... */
9390 met->npl = met->np;
9391 }
9392
9393 /* Get pressure on model levels... */
9394 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
9395
9396 /* Read 3-D pressure field... */
9397 if (ctl->met_vert_coord == 1) {
9398 if (!read_met_nc_3d
9399 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, met->pl,
9400 0.01f))
9401 if (!read_met_nc_3d
9402 (ncid, "press", "PRESS", NULL, NULL, ctl, met, met->pl, 1.0))
9403 ERRMSG("Cannot read pressure on model levels!");
9404 }
9405
9406 /* Use a and b coefficients for full levels... */
9407 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
9408
9409 /* Grid level coefficients... */
9410 double hyam[EP], hybm[EP];
9411
9412 /* Read coefficients from file... */
9413 if (ctl->met_vert_coord == 2) {
9414 int varid;
9415 if (nc_inq_varid(ncid, "hyam", &varid) == NC_NOERR
9416 && nc_inq_varid(ncid, "hybm", &varid) == NC_NOERR) {
9417 NC_GET_DOUBLE("hyam", hyam, 1);
9418 NC_GET_DOUBLE("hybm", hybm, 1);
9419 } else if (nc_inq_varid(ncid, "a_hybrid_level", &varid) == NC_NOERR
9420 && nc_inq_varid(ncid, "b_hybrid_level",
9421 &varid) == NC_NOERR) {
9422 NC_GET_DOUBLE("a_hybrid_level", hyam, 1);
9423 NC_GET_DOUBLE("b_hybrid_level", hybm, 1);
9424 } else
9425 ERRMSG("Cannot read a and b level coefficients from netCDF file!");
9426 }
9427
9428 /* Use control parameters... */
9429 else if (ctl->met_vert_coord == 3) {
9430
9431 /* Check number of levels... */
9432 if (met->np != ctl->met_nlev)
9433 ERRMSG("Mismatch in number of model levels!");
9434
9435 /* Copy parameters... */
9436 for (int ip = 0; ip < met->np; ip++) {
9437 hyam[ip] = ctl->met_lev_hyam[ip];
9438 hybm[ip] = ctl->met_lev_hybm[ip];
9439 }
9440 }
9441
9442 /* Calculate pressure... */
9443 for (int ix = 0; ix < met->nx; ix++)
9444 for (int iy = 0; iy < met->ny; iy++)
9445 for (int ip = 0; ip < met->np; ip++)
9446 met->pl[ix][iy][ip] =
9447 (float) (hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy]);
9448 }
9449
9450 /* Use a and b coefficients for half levels... */
9451 else if (ctl->met_vert_coord == 4) {
9452
9453 /* Grid level coefficients... */
9454 double hyam[EP], hybm[EP];
9455
9456 /* Use control parameters... */
9457 for (int ip = 0; ip < met->np + 1; ip++) {
9458 hyam[ip] = ctl->met_lev_hyam[ip];
9459 hybm[ip] = ctl->met_lev_hybm[ip];
9460 }
9461
9462 /* Check number of levels... */
9463 if (met->np + 1 != ctl->met_nlev)
9464 ERRMSG("Mismatch in number of model levels!");
9465
9466 /* Calculate pressure... */
9467#pragma omp parallel for default(shared) collapse(2)
9468 for (int ix = 0; ix < met->nx; ix++)
9469 for (int iy = 0; iy < met->ny; iy++)
9470 for (int ip = 0; ip < met->np; ip++) {
9471 double p0 = hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy];
9472 double p1 = hyam[ip + 1] / 100. + hybm[ip + 1] * met->ps[ix][iy];
9473 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
9474 }
9475 }
9476
9477 /* Check ordering of pressure levels... */
9478 for (int ix = 0; ix < met->nx; ix++)
9479 for (int iy = 0; iy < met->ny; iy++)
9480 for (int ip = 1; ip < met->np; ip++)
9481 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
9482 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
9483 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
9484 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
9485 ERRMSG("Pressure profiles are not monotonic!");
9486 }
9487
9488 /* Interpolate from model levels to pressure levels... */
9489 if (ctl->met_np > 0) {
9490
9491 /* Check pressure on model levels... */
9492 if (met->pl[0][0][0] <= 0)
9493 ERRMSG("Pressure on model levels is missing, check MET_VERT_COORD!");
9494
9495 /* Interpolate variables... */
9496 read_met_ml2pl(ctl, met, met->t, "T");
9497 read_met_ml2pl(ctl, met, met->u, "U");
9498 read_met_ml2pl(ctl, met, met->v, "V");
9499 read_met_ml2pl(ctl, met, met->w, "W");
9500 read_met_ml2pl(ctl, met, met->h2o, "H2O");
9501 read_met_ml2pl(ctl, met, met->o3, "O3");
9502 read_met_ml2pl(ctl, met, met->lwc, "LWC");
9503 read_met_ml2pl(ctl, met, met->rwc, "RWC");
9504 read_met_ml2pl(ctl, met, met->iwc, "IWC");
9505 read_met_ml2pl(ctl, met, met->swc, "SWC");
9506 read_met_ml2pl(ctl, met, met->cc, "CC");
9507
9508 /* Set new pressure levels... */
9509 met->np = ctl->met_np;
9510 for (int ip = 0; ip < met->np; ip++)
9511 met->p[ip] = ctl->met_p[ip];
9512 }
9513
9514 /* Check ordering of pressure levels... */
9515 for (int ip = 1; ip < met->np; ip++)
9516 if (met->p[ip - 1] < met->p[ip])
9517 ERRMSG("Pressure levels must be descending!");
9518}
9519
9520/*****************************************************************************/
9521
9523 const int ncid,
9524 const ctl_t *ctl,
9525 met_t *met) {
9526
9527 /* Set timer... */
9528 SELECT_TIMER("READ_MET_NC_SURFACE", "INPUT", NVTX_READ);
9529 LOG(2, "Read surface data...");
9530
9531 /* Read surface pressure... */
9532 if (read_met_nc_2d
9533 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, met->ps,
9534 1.0f, 1)) {
9535 for (int ix = 0; ix < met->nx; ix++)
9536 for (int iy = 0; iy < met->ny; iy++)
9537 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
9538 } else
9539 if (!read_met_nc_2d
9540 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, met->ps, 0.01f,
9541 1)) {
9542 WARN("Cannot not read surface pressure data (use lowest level)!");
9543 for (int ix = 0; ix < met->nx; ix++)
9544 for (int iy = 0; iy < met->ny; iy++)
9545 met->ps[ix][iy]
9546 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
9547 }
9548
9549 /* MPTRAC meteo data... */
9550 if (ctl->met_clams == 0) {
9551
9552 /* Read geopotential height at the surface... */
9553 if (!read_met_nc_2d
9554 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, met->zs,
9555 (float) (1. / (1000. * G0)), 1))
9556 if (!read_met_nc_2d
9557 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, met->zs,
9558 (float) (1. / 1000.), 1))
9559 WARN("Cannot read surface geopotential height!");
9560 }
9561
9562 /* CLaMS meteo data... */
9563 else {
9564
9565 /* Read geopotential height at the surface
9566 (use lowermost level of 3-D data field)... */
9567 float *help;
9568 ALLOC(help, float,
9569 EX * EY * EP);
9570 memcpy(help, met->pl, sizeof(met->pl));
9571 if (!read_met_nc_3d
9572 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
9573 (float) (1e-3 / G0)))
9574 ERRMSG("Cannot read geopotential height!");
9575 for (int ix = 0; ix < met->nx; ix++)
9576 for (int iy = 0; iy < met->ny; iy++)
9577 met->zs[ix][iy] = met->pl[ix][iy][0];
9578 memcpy(met->pl, help, sizeof(met->pl));
9579 free(help);
9580 }
9581
9582 /* Read temperature at the surface... */
9583 if (!read_met_nc_2d
9584 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, met->ts, 1.0, 1))
9585 WARN("Cannot read surface temperature!");
9586
9587 /* Read zonal wind at the surface... */
9588 if (!read_met_nc_2d
9589 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, met->us,
9590 1.0, 1))
9591 WARN("Cannot read surface zonal wind!");
9592
9593 /* Read meridional wind at the surface... */
9594 if (!read_met_nc_2d
9595 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, met->vs,
9596 1.0, 1))
9597 WARN("Cannot read surface meridional wind!");
9598
9599 /* Read eastward turbulent surface stress... */
9600 if (!read_met_nc_2d
9601 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, met->ess,
9602 1.0, 1))
9603 WARN("Cannot read eastward turbulent surface stress!");
9604
9605 /* Read northward turbulent surface stress... */
9606 if (!read_met_nc_2d
9607 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, met->nss,
9608 1.0, 1))
9609 WARN("Cannot read nothward turbulent surface stress!");
9610
9611 /* Read surface sensible heat flux... */
9612 if (!read_met_nc_2d
9613 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, met->shf,
9614 1.0, 1))
9615 WARN("Cannot read surface sensible heat flux!");
9616
9617 /* Read land-sea mask... */
9618 if (!read_met_nc_2d
9619 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, met->lsm, 1.0,
9620 1))
9621 WARN("Cannot read land-sea mask!");
9622
9623 /* Read sea surface temperature... */
9624 if (!read_met_nc_2d
9625 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, met->sst,
9626 1.0, 1))
9627 WARN("Cannot read sea surface temperature!");
9628
9629 /* Read PBL... */
9630 if (ctl->met_pbl == 0)
9631 if (!read_met_nc_2d
9632 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
9633 0.01f, 1))
9634 WARN("Cannot read planetary boundary layer pressure!");
9635 if (ctl->met_pbl == 1)
9636 if (!read_met_nc_2d
9637 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
9638 0.001f, 1))
9639 WARN("Cannot read planetary boundary layer height!");
9640
9641 /* Read CAPE... */
9642 if (ctl->met_cape == 0)
9643 if (!read_met_nc_2d
9644 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, met->cape,
9645 1.0, 1))
9646 WARN("Cannot read CAPE!");
9647
9648 /* Read CIN... */
9649 if (ctl->met_cape == 0)
9650 if (!read_met_nc_2d
9651 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, met->cin,
9652 1.0, 1))
9653 WARN("Cannot read convective inhibition!");
9654}
9655
9656/*****************************************************************************/
9657
9659 const ctl_t *ctl,
9660 met_t *met) {
9661
9662 /* Set timer... */
9663 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
9664 LOG(2, "Calculate planetary boundary layer...");
9665
9666 /* Convert PBL height from meteo file to pressure... */
9667 if (ctl->met_pbl == 1) {
9668
9669 /* Loop over grid points... */
9670#pragma omp parallel for default(shared) collapse(2)
9671 for (int ix = 0; ix < met->nx; ix++)
9672 for (int iy = 0; iy < met->ny; iy++) {
9673
9674 /* Get pressure at top of PBL... */
9675 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
9676 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
9677 met->pbl[ix][iy] =
9678 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
9679 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
9680 }
9681 }
9682
9683 /* Determine PBL based on Richardson number... */
9684 else if (ctl->met_pbl == 2) {
9685
9686 /* Parameters used to estimate the height of the PBL
9687 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
9688 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
9689
9690 /* Loop over grid points... */
9691#pragma omp parallel for default(shared) collapse(2)
9692 for (int ix = 0; ix < met->nx; ix++)
9693 for (int iy = 0; iy < met->ny; iy++) {
9694
9695 /* Set bottom level of PBL... */
9696 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
9697
9698 /* Find lowest level near the bottom... */
9699 int ip;
9700 for (ip = 1; ip < met->np; ip++)
9701 if (met->p[ip] < pbl_bot)
9702 break;
9703
9704 /* Get near surface data... */
9705 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
9706 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
9707 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
9708
9709 /* Init... */
9710 double rib_old = 0;
9711
9712 /* Loop over levels... */
9713 for (; ip < met->np; ip++) {
9714
9715 /* Get squared horizontal wind speed... */
9716 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
9717 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
9718 vh2 = MAX(vh2, SQR(umin));
9719
9720 /* Calculate bulk Richardson number... */
9721 const double rib =
9722 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
9723 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
9724 met->h2o[ix][iy][ip]) - tvs) / vh2;
9725
9726 /* Check for critical value... */
9727 if (rib >= rib_crit) {
9728 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
9729 rib, met->p[ip], rib_crit));
9730 if (met->pbl[ix][iy] > pbl_bot)
9731 met->pbl[ix][iy] = (float) pbl_bot;
9732 break;
9733 }
9734
9735 /* Save Richardson number... */
9736 rib_old = rib;
9737 }
9738 }
9739 }
9740
9741 /* Determine PBL based on potential temperature... */
9742 if (ctl->met_pbl == 3) {
9743
9744 /* Parameters used to estimate the height of the PBL
9745 (following HYSPLIT model)... */
9746 const double dtheta = 2.0, zmin = 0.1;
9747
9748 /* Loop over grid points... */
9749#pragma omp parallel for default(shared) collapse(2)
9750 for (int ix = 0; ix < met->nx; ix++)
9751 for (int iy = 0; iy < met->ny; iy++) {
9752
9753 /* Potential temperature at the surface... */
9754 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
9755
9756 /* Find topmost level where theta exceeds surface value by 2 K... */
9757 int ip;
9758 for (ip = met->np - 2; ip > 0; ip--)
9759 if (met->p[ip] >= 300.)
9760 if (met->p[ip] > met->ps[ix][iy]
9761 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
9762 break;
9763
9764 /* Interpolate... */
9765 met->pbl[ix][iy]
9766 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
9767 met->p[ip + 1],
9768 THETA(met->p[ip], met->t[ix][iy][ip]),
9769 met->p[ip], theta0 + dtheta));
9770
9771 /* Check minimum value... */
9772 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
9773 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
9774 met->pbl[ix][iy] = (float) pbl_min;
9775 }
9776 }
9777
9778 /* Loop over grid points... */
9779#pragma omp parallel for default(shared) collapse(2)
9780 for (int ix = 0; ix < met->nx; ix++)
9781 for (int iy = 0; iy < met->ny; iy++) {
9782
9783 /* Check minimum value... */
9784 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
9785 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
9786
9787 /* Check maximum value... */
9788 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
9789 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
9790 }
9791}
9792
9793/*****************************************************************************/
9794
9796 met_t *met) {
9797
9798 /* Set timer... */
9799 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
9800 LOG(2, "Apply periodic boundary conditions...");
9801
9802 /* Check longitudes... */
9803 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
9804 + met->lon[1] - met->lon[0] - 360) < 0.01))
9805 return;
9806
9807 /* Increase longitude counter... */
9808 if ((++met->nx) >= EX)
9809 ERRMSG("Cannot create periodic boundary conditions!");
9810
9811 /* Set longitude... */
9812 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
9813
9814 /* Loop over latitudes and pressure levels... */
9815#pragma omp parallel for default(shared)
9816 for (int iy = 0; iy < met->ny; iy++) {
9817 met->ps[met->nx - 1][iy] = met->ps[0][iy];
9818 met->zs[met->nx - 1][iy] = met->zs[0][iy];
9819 met->ts[met->nx - 1][iy] = met->ts[0][iy];
9820 met->us[met->nx - 1][iy] = met->us[0][iy];
9821 met->vs[met->nx - 1][iy] = met->vs[0][iy];
9822 met->ess[met->nx - 1][iy] = met->ess[0][iy];
9823 met->nss[met->nx - 1][iy] = met->nss[0][iy];
9824 met->shf[met->nx - 1][iy] = met->shf[0][iy];
9825 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
9826 met->sst[met->nx - 1][iy] = met->sst[0][iy];
9827 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
9828 met->cape[met->nx - 1][iy] = met->cape[0][iy];
9829 met->cin[met->nx - 1][iy] = met->cin[0][iy];
9830 for (int ip = 0; ip < met->np; ip++) {
9831 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
9832 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
9833 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
9834 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
9835 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
9836 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
9837 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
9838 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
9839 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
9840 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
9841 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
9842 }
9843 for (int ip = 0; ip < met->npl; ip++) {
9844 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
9845 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
9846 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
9847 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
9848 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
9849 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
9850 }
9851 }
9852}
9853
9854/*****************************************************************************/
9855
9857 met_t *met) {
9858
9859 /* Set timer... */
9860 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
9861 LOG(2, "Apply fix for polar winds...");
9862
9863 /* Check latitudes... */
9864 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
9865 return;
9866
9867 /* Loop over hemispheres... */
9868 for (int ihem = 0; ihem < 2; ihem++) {
9869
9870 /* Set latitude indices... */
9871 int i89 = 1, i90 = 0, sign = 1;
9872 if (ihem == 1) {
9873 i89 = met->ny - 2;
9874 i90 = met->ny - 1;
9875 }
9876 if (met->lat[i90] < 0)
9877 sign = -1;
9878
9879 /* Look-up table of cosinus and sinus... */
9880 double clon[EX], slon[EX];
9881#pragma omp parallel for default(shared)
9882 for (int ix = 0; ix < met->nx; ix++) {
9883 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
9884 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
9885 }
9886
9887 /* Loop over levels... */
9888#pragma omp parallel for default(shared)
9889 for (int ip = 0; ip < met->np; ip++) {
9890
9891 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
9892 double vel89x = 0, vel89y = 0;
9893 for (int ix = 0; ix < met->nx; ix++) {
9894 vel89x +=
9895 (met->u[ix][i89][ip] * clon[ix] -
9896 met->v[ix][i89][ip] * slon[ix]) / met->nx;
9897 vel89y +=
9898 (met->u[ix][i89][ip] * slon[ix] +
9899 met->v[ix][i89][ip] * clon[ix]) / met->nx;
9900 }
9901
9902 /* Replace 90 degree winds by 89 degree mean... */
9903 for (int ix = 0; ix < met->nx; ix++) {
9904 met->u[ix][i90][ip]
9905 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
9906 met->v[ix][i90][ip]
9907 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
9908 }
9909 }
9910 }
9911}
9912
9913/*****************************************************************************/
9914
9916 met_t *met) {
9917
9918 double pows[EP];
9919
9920 /* Set timer... */
9921 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
9922 LOG(2, "Calculate potential vorticity...");
9923
9924 /* Set powers... */
9925#pragma omp parallel for default(shared)
9926 for (int ip = 0; ip < met->np; ip++)
9927 pows[ip] = pow(1000. / met->p[ip], 0.286);
9928
9929 /* Loop over grid points... */
9930#pragma omp parallel for default(shared)
9931 for (int ix = 0; ix < met->nx; ix++) {
9932
9933 /* Set indices... */
9934 const int ix0 = MAX(ix - 1, 0);
9935 const int ix1 = MIN(ix + 1, met->nx - 1);
9936
9937 /* Loop over grid points... */
9938 for (int iy = 0; iy < met->ny; iy++) {
9939
9940 /* Set indices... */
9941 const int iy0 = MAX(iy - 1, 0);
9942 const int iy1 = MIN(iy + 1, met->ny - 1);
9943
9944 /* Set auxiliary variables... */
9945 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
9946 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
9947 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
9948 const double c0 = cos(DEG2RAD(met->lat[iy0]));
9949 const double c1 = cos(DEG2RAD(met->lat[iy1]));
9950 const double cr = cos(DEG2RAD(latr));
9951 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
9952
9953 /* Loop over grid points... */
9954 for (int ip = 0; ip < met->np; ip++) {
9955
9956 /* Get gradients in longitude... */
9957 const double dtdx
9958 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
9959 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
9960
9961 /* Get gradients in latitude... */
9962 const double dtdy
9963 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
9964 const double dudy
9965 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
9966
9967 /* Set indices... */
9968 const int ip0 = MAX(ip - 1, 0);
9969 const int ip1 = MIN(ip + 1, met->np - 1);
9970
9971 /* Get gradients in pressure... */
9972 double dtdp, dudp, dvdp;
9973 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
9974 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
9975 if (ip != ip0 && ip != ip1) {
9976 double denom = dp0 * dp1 * (dp0 + dp1);
9977 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
9978 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
9979 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
9980 / denom;
9981 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
9982 - dp1 * dp1 * met->u[ix][iy][ip0]
9983 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
9984 / denom;
9985 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
9986 - dp1 * dp1 * met->v[ix][iy][ip0]
9987 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
9988 / denom;
9989 } else {
9990 const double denom = dp0 + dp1;
9991 dtdp =
9992 (met->t[ix][iy][ip1] * pows[ip1] -
9993 met->t[ix][iy][ip0] * pows[ip0]) / denom;
9994 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
9995 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
9996 }
9997
9998 /* Calculate PV... */
9999 met->pv[ix][iy][ip] = (float)
10000 (1e6 * G0 *
10001 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
10002 }
10003 }
10004 }
10005
10006 /* Fix for polar regions... */
10007#pragma omp parallel for default(shared)
10008 for (int ix = 0; ix < met->nx; ix++)
10009 for (int ip = 0; ip < met->np; ip++) {
10010 met->pv[ix][0][ip]
10011 = met->pv[ix][1][ip]
10012 = met->pv[ix][2][ip];
10013 met->pv[ix][met->ny - 1][ip]
10014 = met->pv[ix][met->ny - 2][ip]
10015 = met->pv[ix][met->ny - 3][ip];
10016 }
10017}
10018
10019/*****************************************************************************/
10020
10022 met_t *met) {
10023
10024 /* Set timer... */
10025 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
10026 LOG(2, "Calculate total column ozone...");
10027
10028 /* Loop over columns... */
10029#pragma omp parallel for default(shared) collapse(2)
10030 for (int ix = 0; ix < met->nx; ix++)
10031 for (int iy = 0; iy < met->ny; iy++) {
10032
10033 /* Integrate... */
10034 double cd = 0;
10035 for (int ip = 1; ip < met->np; ip++)
10036 if (met->p[ip - 1] <= met->ps[ix][iy]) {
10037 const double vmr =
10038 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
10039 const double dp = met->p[ip - 1] - met->p[ip];
10040 cd += vmr * MO3 / MA * dp * 1e2 / G0;
10041 }
10042
10043 /* Convert to Dobson units... */
10044 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
10045 }
10046}
10047
10048/*****************************************************************************/
10049
10051 const ctl_t *ctl,
10052 met_t *met) {
10053
10054 met_t *help;
10055
10056 /* Check parameters... */
10057 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
10058 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
10059 return;
10060
10061 /* Set timer... */
10062 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
10063 LOG(2, "Downsampling of meteo data...");
10064
10065 /* Allocate... */
10066 ALLOC(help, met_t, 1);
10067
10068 /* Copy data... */
10069 help->nx = met->nx;
10070 help->ny = met->ny;
10071 help->np = met->np;
10072 memcpy(help->lon, met->lon, sizeof(met->lon));
10073 memcpy(help->lat, met->lat, sizeof(met->lat));
10074 memcpy(help->p, met->p, sizeof(met->p));
10075
10076 /* Smoothing... */
10077 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
10078 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
10079 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
10080 help->ps[ix][iy] = 0;
10081 help->zs[ix][iy] = 0;
10082 help->ts[ix][iy] = 0;
10083 help->us[ix][iy] = 0;
10084 help->vs[ix][iy] = 0;
10085 help->ess[ix][iy] = 0;
10086 help->nss[ix][iy] = 0;
10087 help->shf[ix][iy] = 0;
10088 help->lsm[ix][iy] = 0;
10089 help->sst[ix][iy] = 0;
10090 help->pbl[ix][iy] = 0;
10091 help->cape[ix][iy] = 0;
10092 help->cin[ix][iy] = 0;
10093 help->t[ix][iy][ip] = 0;
10094 help->u[ix][iy][ip] = 0;
10095 help->v[ix][iy][ip] = 0;
10096 help->w[ix][iy][ip] = 0;
10097 help->h2o[ix][iy][ip] = 0;
10098 help->o3[ix][iy][ip] = 0;
10099 help->lwc[ix][iy][ip] = 0;
10100 help->rwc[ix][iy][ip] = 0;
10101 help->iwc[ix][iy][ip] = 0;
10102 help->swc[ix][iy][ip] = 0;
10103 help->cc[ix][iy][ip] = 0;
10104 float wsum = 0;
10105 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
10106 ix2++) {
10107 int ix3 = ix2;
10108 if (ix3 < 0)
10109 ix3 += met->nx;
10110 else if (ix3 >= met->nx)
10111 ix3 -= met->nx;
10112
10113 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
10114 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
10115 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
10116 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
10117 float w = (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
10118 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
10119 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
10120 help->ps[ix][iy] += w * met->ps[ix3][iy2];
10121 help->zs[ix][iy] += w * met->zs[ix3][iy2];
10122 help->ts[ix][iy] += w * met->ts[ix3][iy2];
10123 help->us[ix][iy] += w * met->us[ix3][iy2];
10124 help->vs[ix][iy] += w * met->vs[ix3][iy2];
10125 help->ess[ix][iy] += w * met->ess[ix3][iy2];
10126 help->nss[ix][iy] += w * met->nss[ix3][iy2];
10127 help->shf[ix][iy] += w * met->shf[ix3][iy2];
10128 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
10129 help->sst[ix][iy] += w * met->sst[ix3][iy2];
10130 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
10131 help->cape[ix][iy] += w * met->cape[ix3][iy2];
10132 help->cin[ix][iy] += w * met->cin[ix3][iy2];
10133 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
10134 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
10135 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
10136 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
10137 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
10138 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
10139 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
10140 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
10141 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
10142 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
10143 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
10144 wsum += w;
10145 }
10146 }
10147 help->ps[ix][iy] /= wsum;
10148 help->zs[ix][iy] /= wsum;
10149 help->ts[ix][iy] /= wsum;
10150 help->us[ix][iy] /= wsum;
10151 help->vs[ix][iy] /= wsum;
10152 help->ess[ix][iy] /= wsum;
10153 help->nss[ix][iy] /= wsum;
10154 help->shf[ix][iy] /= wsum;
10155 help->lsm[ix][iy] /= wsum;
10156 help->sst[ix][iy] /= wsum;
10157 help->pbl[ix][iy] /= wsum;
10158 help->cape[ix][iy] /= wsum;
10159 help->cin[ix][iy] /= wsum;
10160 help->t[ix][iy][ip] /= wsum;
10161 help->u[ix][iy][ip] /= wsum;
10162 help->v[ix][iy][ip] /= wsum;
10163 help->w[ix][iy][ip] /= wsum;
10164 help->h2o[ix][iy][ip] /= wsum;
10165 help->o3[ix][iy][ip] /= wsum;
10166 help->lwc[ix][iy][ip] /= wsum;
10167 help->rwc[ix][iy][ip] /= wsum;
10168 help->iwc[ix][iy][ip] /= wsum;
10169 help->swc[ix][iy][ip] /= wsum;
10170 help->cc[ix][iy][ip] /= wsum;
10171 }
10172 }
10173 }
10174
10175 /* Downsampling... */
10176 met->nx = 0;
10177 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
10178 met->lon[met->nx] = help->lon[ix];
10179 met->ny = 0;
10180 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
10181 met->lat[met->ny] = help->lat[iy];
10182 met->ps[met->nx][met->ny] = help->ps[ix][iy];
10183 met->zs[met->nx][met->ny] = help->zs[ix][iy];
10184 met->ts[met->nx][met->ny] = help->ts[ix][iy];
10185 met->us[met->nx][met->ny] = help->us[ix][iy];
10186 met->vs[met->nx][met->ny] = help->vs[ix][iy];
10187 met->ess[met->nx][met->ny] = help->ess[ix][iy];
10188 met->nss[met->nx][met->ny] = help->nss[ix][iy];
10189 met->shf[met->nx][met->ny] = help->shf[ix][iy];
10190 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
10191 met->sst[met->nx][met->ny] = help->sst[ix][iy];
10192 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
10193 met->cape[met->nx][met->ny] = help->cape[ix][iy];
10194 met->cin[met->nx][met->ny] = help->cin[ix][iy];
10195 met->np = 0;
10196 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
10197 met->p[met->np] = help->p[ip];
10198 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
10199 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
10200 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
10201 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
10202 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
10203 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
10204 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
10205 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
10206 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
10207 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
10208 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
10209 met->np++;
10210 }
10211 met->ny++;
10212 }
10213 met->nx++;
10214 }
10215
10216 /* Free... */
10217 free(help);
10218}
10219
10220/*****************************************************************************/
10221
10223 const ctl_t *ctl,
10224 const clim_t *clim,
10225 met_t *met) {
10226
10227 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
10228 th2[200], z[EP], z2[200];
10229
10230 /* Set timer... */
10231 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
10232 LOG(2, "Calculate tropopause...");
10233
10234 /* Get altitude and pressure profiles... */
10235#pragma omp parallel for default(shared)
10236 for (int iz = 0; iz < met->np; iz++)
10237 z[iz] = Z(met->p[iz]);
10238#pragma omp parallel for default(shared)
10239 for (int iz = 0; iz <= 190; iz++) {
10240 z2[iz] = 4.5 + 0.1 * iz;
10241 p2[iz] = P(z2[iz]);
10242 }
10243
10244 /* Do not calculate tropopause... */
10245 if (ctl->met_tropo == 0)
10246#pragma omp parallel for default(shared) collapse(2)
10247 for (int ix = 0; ix < met->nx; ix++)
10248 for (int iy = 0; iy < met->ny; iy++)
10249 met->pt[ix][iy] = NAN;
10250
10251 /* Use tropopause climatology... */
10252 else if (ctl->met_tropo == 1) {
10253#pragma omp parallel for default(shared) collapse(2)
10254 for (int ix = 0; ix < met->nx; ix++)
10255 for (int iy = 0; iy < met->ny; iy++)
10256 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
10257 }
10258
10259 /* Use cold point... */
10260 else if (ctl->met_tropo == 2) {
10261
10262 /* Loop over grid points... */
10263#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10264 for (int ix = 0; ix < met->nx; ix++)
10265 for (int iy = 0; iy < met->ny; iy++) {
10266
10267 /* Interpolate temperature profile... */
10268 for (int iz = 0; iz < met->np; iz++)
10269 t[iz] = met->t[ix][iy][iz];
10270 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
10271
10272 /* Find minimum... */
10273 int iz = (int) gsl_stats_min_index(t2, 1, 171);
10274 if (iz > 0 && iz < 170)
10275 met->pt[ix][iy] = (float) p2[iz];
10276 else
10277 met->pt[ix][iy] = NAN;
10278 }
10279 }
10280
10281 /* Use WMO definition... */
10282 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
10283
10284 /* Loop over grid points... */
10285#pragma omp parallel for default(shared) private(t,t2) collapse(2)
10286 for (int ix = 0; ix < met->nx; ix++)
10287 for (int iy = 0; iy < met->ny; iy++) {
10288
10289 /* Interpolate temperature profile... */
10290 int iz;
10291 for (iz = 0; iz < met->np; iz++)
10292 t[iz] = met->t[ix][iy][iz];
10293 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
10294
10295 /* Find 1st tropopause... */
10296 met->pt[ix][iy] = NAN;
10297 for (iz = 0; iz <= 170; iz++) {
10298 int found = 1;
10299 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10300 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10301 found = 0;
10302 break;
10303 }
10304 if (found) {
10305 if (iz > 0 && iz < 170)
10306 met->pt[ix][iy] = (float) p2[iz];
10307 break;
10308 }
10309 }
10310
10311 /* Find 2nd tropopause... */
10312 if (ctl->met_tropo == 4) {
10313 met->pt[ix][iy] = NAN;
10314 for (; iz <= 170; iz++) {
10315 int found = 1;
10316 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
10317 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
10318 found = 0;
10319 break;
10320 }
10321 if (found)
10322 break;
10323 }
10324 for (; iz <= 170; iz++) {
10325 int found = 1;
10326 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
10327 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
10328 found = 0;
10329 break;
10330 }
10331 if (found) {
10332 if (iz > 0 && iz < 170)
10333 met->pt[ix][iy] = (float) p2[iz];
10334 break;
10335 }
10336 }
10337 }
10338 }
10339 }
10340
10341 /* Use dynamical tropopause... */
10342 else if (ctl->met_tropo == 5) {
10343
10344 /* Loop over grid points... */
10345#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
10346 for (int ix = 0; ix < met->nx; ix++)
10347 for (int iy = 0; iy < met->ny; iy++) {
10348
10349 /* Interpolate potential vorticity profile... */
10350 for (int iz = 0; iz < met->np; iz++)
10351 pv[iz] = met->pv[ix][iy][iz];
10352 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
10353
10354 /* Interpolate potential temperature profile... */
10355 for (int iz = 0; iz < met->np; iz++)
10356 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
10357 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
10358
10359 /* Find dynamical tropopause... */
10360 met->pt[ix][iy] = NAN;
10361 for (int iz = 0; iz <= 170; iz++)
10362 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
10363 || th2[iz] >= ctl->met_tropo_theta) {
10364 if (iz > 0 && iz < 170)
10365 met->pt[ix][iy] = (float) p2[iz];
10366 break;
10367 }
10368 }
10369 }
10370
10371 else
10372 ERRMSG("Cannot calculate tropopause!");
10373
10374 /* Interpolate temperature, geopotential height, and water vapor... */
10375#pragma omp parallel for default(shared) collapse(2)
10376 for (int ix = 0; ix < met->nx; ix++)
10377 for (int iy = 0; iy < met->ny; iy++) {
10378 double h2ot, tt, zt;
10380 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
10381 met->lat[iy], &tt, ci, cw, 1);
10382 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
10383 met->lat[iy], &zt, ci, cw, 0);
10384 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
10385 met->lat[iy], &h2ot, ci, cw, 0);
10386 met->tt[ix][iy] = (float) tt;
10387 met->zt[ix][iy] = (float) zt;
10388 met->h2ot[ix][iy] = (float) h2ot;
10389 }
10390}
10391
10392/*****************************************************************************/
10393
10395 const char *filename,
10396 const ctl_t *ctl,
10397 double *rt,
10398 double *rz,
10399 double *rlon,
10400 double *rlat,
10401 double *robs,
10402 int *nobs) {
10403
10404 /* Write info... */
10405 LOG(1, "Read observation data: %s", filename);
10406
10407 /* Read data... */
10408 if (ctl->obs_type == 0)
10409 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
10410 else if (ctl->obs_type == 1)
10411 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
10412 else
10413 ERRMSG("Set OBS_TYPE to 0 or 1!");
10414
10415 /* Check time... */
10416 for (int i = 1; i < *nobs; i++)
10417 if (rt[i] < rt[i - 1])
10418 ERRMSG("Time must be ascending!");
10419
10420 /* Write info... */
10421 int n = *nobs;
10422 double mini, maxi;
10423 LOG(2, "Number of observations: %d", *nobs);
10424 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
10425 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
10426 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
10427 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
10428 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
10429 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
10430 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
10431 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
10432 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
10433 LOG(2, "Observation range: %g ... %g", mini, maxi);
10434}
10435
10436/*****************************************************************************/
10437
10439 const char *filename,
10440 double *rt,
10441 double *rz,
10442 double *rlon,
10443 double *rlat,
10444 double *robs,
10445 int *nobs) {
10446
10447 /* Open observation data file... */
10448 FILE *in;
10449 if (!(in = fopen(filename, "r")))
10450 ERRMSG("Cannot open file!");
10451
10452 /* Read observations... */
10453 char line[LEN];
10454 while (fgets(line, LEN, in))
10455 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
10456 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
10457 if ((++(*nobs)) >= NOBS)
10458 ERRMSG("Too many observations!");
10459
10460 /* Close observation data file... */
10461 fclose(in);
10462}
10463
10464/*****************************************************************************/
10465
10467 const char *filename,
10468 double *rt,
10469 double *rz,
10470 double *rlon,
10471 double *rlat,
10472 double *robs,
10473 int *nobs) {
10474
10475 int ncid, varid;
10476
10477 /* Open netCDF file... */
10478 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
10479 ERRMSG("Cannot open file!");
10480
10481 /* Read the observations from the NetCDF file... */
10482 NC_INQ_DIM("nobs", nobs, 1, NOBS);
10483 NC_GET_DOUBLE("time", rt, 1);
10484 NC_GET_DOUBLE("alt", rz, 1);
10485 NC_GET_DOUBLE("lon", rlon, 1);
10486 NC_GET_DOUBLE("lat", rlat, 1);
10487 NC_GET_DOUBLE("obs", robs, 1);
10488
10489 /* Close file... */
10490 NC(nc_close(ncid));
10491}
10492
10493/*****************************************************************************/
10494
10496 const char *filename,
10497 int argc,
10498 char *argv[],
10499 const char *varname,
10500 const int arridx,
10501 const char *defvalue,
10502 char *value) {
10503
10504 FILE *in = NULL;
10505
10506 char fullname1[LEN], fullname2[LEN], rval[LEN];
10507
10508 int contain = 0, i;
10509
10510 /* Open file... */
10511 if (filename[strlen(filename) - 1] != '-')
10512 if (!(in = fopen(filename, "r")))
10513 ERRMSG("Cannot open file!");
10514
10515 /* Set full variable name... */
10516 if (arridx >= 0) {
10517 sprintf(fullname1, "%s[%d]", varname, arridx);
10518 sprintf(fullname2, "%s[*]", varname);
10519 } else {
10520 sprintf(fullname1, "%s", varname);
10521 sprintf(fullname2, "%s", varname);
10522 }
10523
10524 /* Read data... */
10525 if (in != NULL) {
10526 char dummy[LEN], line[LEN], rvarname[LEN];
10527 while (fgets(line, LEN, in)) {
10528 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
10529 if (strcasecmp(rvarname, fullname1) == 0 ||
10530 strcasecmp(rvarname, fullname2) == 0) {
10531 contain = 1;
10532 break;
10533 }
10534 }
10535 }
10536 for (i = 1; i < argc - 1; i++)
10537 if (strcasecmp(argv[i], fullname1) == 0 ||
10538 strcasecmp(argv[i], fullname2) == 0) {
10539 sprintf(rval, "%s", argv[i + 1]);
10540 contain = 1;
10541 break;
10542 }
10543
10544 /* Close file... */
10545 if (in != NULL)
10546 fclose(in);
10547
10548 /* Check for missing variables... */
10549 if (!contain) {
10550 if (strlen(defvalue) > 0)
10551 sprintf(rval, "%s", defvalue);
10552 else
10553 ERRMSG("Missing variable %s!\n", fullname1);
10554 }
10555
10556 /* Write info... */
10557 LOG(1, "%s = %s", fullname1, rval);
10558
10559 /* Return values... */
10560 if (value != NULL)
10561 sprintf(value, "%s", rval);
10562 return atof(rval);
10563}
10564
10565/*****************************************************************************/
10566
10567double sedi(
10568 const double p,
10569 const double T,
10570 const double rp,
10571 const double rhop) {
10572
10573 /* Convert particle radius from microns to m... */
10574 const double rp_help = rp * 1e-6;
10575
10576 /* Density of dry air [kg / m^3]... */
10577 const double rho = RHO(p, T);
10578
10579 /* Dynamic viscosity of air [kg / (m s)]... */
10580 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
10581
10582 /* Thermal velocity of an air molecule [m / s]... */
10583 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
10584
10585 /* Mean free path of an air molecule [m]... */
10586 const double lambda = 2. * eta / (rho * v);
10587
10588 /* Knudsen number for air (dimensionless)... */
10589 const double K = lambda / rp_help;
10590
10591 /* Cunningham slip-flow correction (dimensionless)... */
10592 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
10593
10594 /* Sedimentation velocity [m / s]... */
10595 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
10596}
10597
10598/*****************************************************************************/
10599
10601 const double *x,
10602 const double *y,
10603 const int n,
10604 const double *x2,
10605 double *y2,
10606 const int n2,
10607 const int method) {
10608
10609 /* Cubic spline interpolation... */
10610 if (method == 1) {
10611
10612 /* Allocate... */
10613 gsl_interp_accel *acc = gsl_interp_accel_alloc();
10614 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
10615
10616 /* Interpolate profile... */
10617 gsl_spline_init(s, x, y, (size_t) n);
10618 for (int i = 0; i < n2; i++)
10619 if (x2[i] <= x[0])
10620 y2[i] = y[0];
10621 else if (x2[i] >= x[n - 1])
10622 y2[i] = y[n - 1];
10623 else
10624 y2[i] = gsl_spline_eval(s, x2[i], acc);
10625
10626 /* Free... */
10627 gsl_spline_free(s);
10628 gsl_interp_accel_free(acc);
10629 }
10630
10631 /* Linear interpolation... */
10632 else {
10633 for (int i = 0; i < n2; i++)
10634 if (x2[i] <= x[0])
10635 y2[i] = y[0];
10636 else if (x2[i] >= x[n - 1])
10637 y2[i] = y[n - 1];
10638 else {
10639 int idx = locate_irr(x, n, x2[i]);
10640 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
10641 }
10642 }
10643}
10644
10645/*****************************************************************************/
10646
10648 const float *data,
10649 const int n) {
10650
10651 if (n <= 0)
10652 return 0;
10653
10654 float mean = 0, var = 0;
10655
10656 for (int i = 0; i < n; ++i) {
10657 mean += data[i];
10658 var += SQR(data[i]);
10659 }
10660
10661 var = var / (float) n - SQR(mean / (float) n);
10662
10663 return (var > 0 ? sqrtf(var) : 0);
10664}
10665
10666/*****************************************************************************/
10667
10669 const double sec,
10670 const double lon,
10671 const double lat) {
10672
10673 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
10674 const double D = sec / 86400 - 0.5;
10675
10676 /* Geocentric apparent ecliptic longitude [rad]... */
10677 const double g = DEG2RAD(357.529 + 0.98560028 * D);
10678 const double q = 280.459 + 0.98564736 * D;
10679 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
10680
10681 /* Mean obliquity of the ecliptic [rad]... */
10682 const double e = DEG2RAD(23.439 - 0.00000036 * D);
10683
10684 /* Declination [rad]... */
10685 const double sindec = sin(e) * sin(L);
10686
10687 /* Right ascension [rad]... */
10688 const double ra = atan2(cos(e) * sin(L), cos(L));
10689
10690 /* Greenwich Mean Sidereal Time [h]... */
10691 const double GMST = 18.697374558 + 24.06570982441908 * D;
10692
10693 /* Local Sidereal Time [h]... */
10694 const double LST = GMST + lon / 15;
10695
10696 /* Hour angle [rad]... */
10697 const double h = LST / 12 * M_PI - ra;
10698
10699 /* Convert latitude... */
10700 const double lat_help = DEG2RAD(lat);
10701
10702 /* Return solar zenith angle [rad]... */
10703 return acos(sin(lat_help) * sindec +
10704 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
10705}
10706
10707/*****************************************************************************/
10708
10710 const int year,
10711 const int mon,
10712 const int day,
10713 const int hour,
10714 const int min,
10715 const int sec,
10716 const double remain,
10717 double *jsec) {
10718
10719 struct tm t0, t1;
10720
10721 t0.tm_year = 100;
10722 t0.tm_mon = 0;
10723 t0.tm_mday = 1;
10724 t0.tm_hour = 0;
10725 t0.tm_min = 0;
10726 t0.tm_sec = 0;
10727
10728 t1.tm_year = year - 1900;
10729 t1.tm_mon = mon - 1;
10730 t1.tm_mday = day;
10731 t1.tm_hour = hour;
10732 t1.tm_min = min;
10733 t1.tm_sec = sec;
10734
10735 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
10736}
10737
10738/*****************************************************************************/
10739
10741 const char *name,
10742 const char *group,
10743 const int output) {
10744
10745 static char names[NTIMER][100], groups[NTIMER][100];
10746
10747 static double rt_name[NTIMER], rt_group[NTIMER],
10748 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
10749
10750 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
10751
10752 /* Get time... */
10753 t1 = omp_get_wtime();
10754 dt = t1 - t0;
10755
10756 /* Add elapsed time to current timers... */
10757 if (iname >= 0) {
10758 rt_name[iname] += dt;
10759 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
10760 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
10761 ct_name[iname]++;
10762 }
10763 if (igroup >= 0)
10764 rt_group[igroup] += t1 - t0;
10765
10766 /* Report timers... */
10767 if (output) {
10768 for (int i = 0; i < nname; i++)
10769 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
10770 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
10771 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
10772 for (int i = 0; i < ngroup; i++)
10773 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
10774 double total = 0.0;
10775 for (int i = 0; i < nname; i++)
10776 total += rt_name[i];
10777 LOG(1, "TIMER_TOTAL = %.3f s", total);
10778 }
10779
10780 /* Identify IDs of next timer... */
10781 for (iname = 0; iname < nname; iname++)
10782 if (strcasecmp(name, names[iname]) == 0)
10783 break;
10784 for (igroup = 0; igroup < ngroup; igroup++)
10785 if (strcasecmp(group, groups[igroup]) == 0)
10786 break;
10787
10788 /* Check whether this is a new timer... */
10789 if (iname >= nname) {
10790 sprintf(names[iname], "%s", name);
10791 if ((++nname) >= NTIMER)
10792 ERRMSG("Too many timers!");
10793 }
10794
10795 /* Check whether this is a new group... */
10796 if (igroup >= ngroup) {
10797 sprintf(groups[igroup], "%s", group);
10798 if ((++ngroup) >= NTIMER)
10799 ERRMSG("Too many groups!");
10800 }
10801
10802 /* Save starting time... */
10803 t0 = t1;
10804}
10805
10806/*****************************************************************************/
10807
10809 const char *filename,
10810 const int offset) {
10811
10812 char tstr[10];
10813
10814 double t;
10815
10816 /* Get time from filename... */
10817 int len = (int) strlen(filename);
10818 sprintf(tstr, "%.4s", &filename[len - offset]);
10819 int year = atoi(tstr);
10820 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
10821 int mon = atoi(tstr);
10822 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
10823 int day = atoi(tstr);
10824 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
10825 int hour = atoi(tstr);
10826 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
10827 int min = atoi(tstr);
10828
10829 /* Check time... */
10830 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
10831 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
10832 ERRMSG("Cannot read time from filename!");
10833
10834 /* Convert time to Julian seconds... */
10835 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
10836
10837 /* Return time... */
10838 return t;
10839}
10840
10841/*****************************************************************************/
10842
10844 const clim_t *clim,
10845 const atm_t *atm,
10846 const int ip) {
10847
10848 /* Get tropopause pressure... */
10849 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
10850
10851 /* Get pressure range... */
10852 const double p1 = pt * 0.866877899;
10853 const double p0 = pt / 0.866877899;
10854
10855 /* Get weighting factor... */
10856 if (atm->p[ip] > p0)
10857 return 1;
10858 else if (atm->p[ip] < p1)
10859 return 0;
10860 else
10861 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
10862}
10863
10864/*****************************************************************************/
10865
10867 const char *filename,
10868 const ctl_t *ctl,
10869 const atm_t *atm,
10870 const double t) {
10871
10872 FILE *out;
10873
10874 /* Set time interval for output... */
10875 const double t0 = t - 0.5 * ctl->dt_mod;
10876 const double t1 = t + 0.5 * ctl->dt_mod;
10877
10878 /* Check if gnuplot output is requested... */
10879 if (ctl->atm_gpfile[0] != '-') {
10880
10881 /* Create gnuplot pipe... */
10882 if (!(out = popen("gnuplot", "w")))
10883 ERRMSG("Cannot create pipe to gnuplot!");
10884
10885 /* Set plot filename... */
10886 fprintf(out, "set out \"%s.png\"\n", filename);
10887
10888 /* Set time string... */
10889 double r;
10890 int year, mon, day, hour, min, sec;
10891 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
10892 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
10893 year, mon, day, hour, min);
10894
10895 /* Dump gnuplot file to pipe... */
10896 FILE *in;
10897 if (!(in = fopen(ctl->atm_gpfile, "r")))
10898 ERRMSG("Cannot open file!");
10899 char line[LEN];
10900 while (fgets(line, LEN, in))
10901 fprintf(out, "%s", line);
10902 fclose(in);
10903 }
10904
10905 else {
10906
10907 /* Create file... */
10908 if (!(out = fopen(filename, "w")))
10909 ERRMSG("Cannot create file!");
10910 }
10911
10912 /* Write header... */
10913 fprintf(out,
10914 "# $1 = time [s]\n"
10915 "# $2 = altitude [km]\n"
10916 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
10917 for (int iq = 0; iq < ctl->nq; iq++)
10918 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
10919 ctl->qnt_unit[iq]);
10920 fprintf(out, "\n");
10921
10922 /* Write data... */
10923 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
10924
10925 /* Check time... */
10926 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
10927 continue;
10928
10929 /* Write output... */
10930 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
10931 atm->lon[ip], atm->lat[ip]);
10932 for (int iq = 0; iq < ctl->nq; iq++) {
10933 fprintf(out, " ");
10934 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
10935 fprintf(out, ctl->qnt_format[iq], NAN);
10936 else
10937 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
10938 }
10939 fprintf(out, "\n");
10940 }
10941
10942 /* Close file... */
10943 fclose(out);
10944}
10945
10946/*****************************************************************************/
10947
10949 const char *filename,
10950 const ctl_t *ctl,
10951 const atm_t *atm) {
10952
10953 FILE *out;
10954
10955 /* Create file... */
10956 if (!(out = fopen(filename, "w")))
10957 ERRMSG("Cannot create file!");
10958
10959 /* Write version of binary data... */
10960 int version = 100;
10961 FWRITE(&version, int,
10962 1,
10963 out);
10964
10965 /* Write data... */
10966 FWRITE(&atm->np, int,
10967 1,
10968 out);
10969 FWRITE(atm->time, double,
10970 (size_t) atm->np,
10971 out);
10972 FWRITE(atm->p, double,
10973 (size_t) atm->np,
10974 out);
10975 FWRITE(atm->lon, double,
10976 (size_t) atm->np,
10977 out);
10978 FWRITE(atm->lat, double,
10979 (size_t) atm->np,
10980 out);
10981 for (int iq = 0; iq < ctl->nq; iq++)
10982 FWRITE(atm->q[iq], double,
10983 (size_t) atm->np,
10984 out);
10985
10986 /* Write final flag... */
10987 int final = 999;
10988 FWRITE(&final, int,
10989 1,
10990 out);
10991
10992 /* Close file... */
10993 fclose(out);
10994}
10995
10996/*****************************************************************************/
10997
10999 const char *filename,
11000 const ctl_t *ctl,
11001 const atm_t *atm) {
11002
11003 int tid, pid, ncid, varid;
11004 size_t start[2], count[2];
11005
11006 /* Create file... */
11007 nc_create(filename, NC_NETCDF4, &ncid);
11008
11009 /* Define dimensions... */
11010 NC(nc_def_dim(ncid, "time", 1, &tid));
11011 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11012
11013 /* Define variables and their attributes... */
11014 int dim_ids[2] = { tid, pid };
11015 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11016 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11017 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11018 ctl->atm_nc_level, 0);
11019 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11020 ctl->atm_nc_level, 0);
11021 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11022 ctl->atm_nc_level, 0);
11023 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11024 for (int iq = 0; iq < ctl->nq; iq++)
11025 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11026 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11027 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11028
11029 /* Define global attributes... */
11030 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11031 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11032
11033 /* End definitions... */
11034 NC(nc_enddef(ncid));
11035
11036 /* Write data... */
11037 NC_PUT_DOUBLE("time", atm->time, 0);
11038 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11039 NC_PUT_DOUBLE("LON", atm->lon, 0);
11040 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11041 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11042 for (int iq = 0; iq < ctl->nq; iq++)
11043 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11044
11045 /* Close file... */
11046 NC(nc_close(ncid));
11047}
11048
11049/*****************************************************************************/
11050
11052 const char *dirname,
11053 const ctl_t *ctl,
11054 const atm_t *atm,
11055 const double t) {
11056
11057 /* Global Counter... */
11058 static size_t out_cnt = 0;
11059
11060 double r, r_start, r_stop;
11061 int year, mon, day, hour, min, sec;
11062 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
11063 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
11064 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
11065
11066 int ncid, varid, tid, pid, cid;
11067 int dim_ids[2];
11068
11069 /* time, nparc */
11070 size_t start[2];
11071 size_t count[2];
11072
11073 /* Determine start and stop times of calculation... */
11074 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11075 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
11076 &min_start, &sec_start, &r_start);
11077 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
11078 &min_stop, &sec_stop, &r_stop);
11079
11080 sprintf(filename_out,
11081 "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc", dirname,
11082 year_start % 100, mon_start, day_start, hour_start,
11083 year_stop % 100, mon_stop, day_stop, hour_stop);
11084 LOG(1, "Write traj file: %s", filename_out);
11085
11086 /* Define hyperslap for the traj_file... */
11087 start[0] = out_cnt;
11088 start[1] = 0;
11089 count[0] = 1;
11090 count[1] = (size_t) atm->np;
11091
11092 /* Create the file at the first timestep... */
11093 if (out_cnt == 0) {
11094
11095 /* Create file... */
11096 nc_create(filename_out, NC_NETCDF4, &ncid);
11097
11098 /* Define dimensions... */
11099 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
11100 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11101 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
11102 dim_ids[0] = tid;
11103 dim_ids[1] = pid;
11104
11105 /* Define variables and their attributes... */
11106 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11107 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11108 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
11109 ctl->atm_nc_level, 0);
11110 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
11111 ctl->atm_nc_level, 0);
11112 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
11113 ctl->atm_nc_level, 0);
11114 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
11115 ctl->atm_nc_level, 0);
11116 for (int iq = 0; iq < ctl->nq; iq++)
11117 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11118 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11119 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11120
11121 /* Define global attributes... */
11122 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11123 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11124
11125 /* End definitions... */
11126 NC(nc_enddef(ncid));
11127 NC(nc_close(ncid));
11128 }
11129
11130 /* Increment global counter to change hyperslap... */
11131 out_cnt++;
11132
11133 /* Open file... */
11134 NC(nc_open(filename_out, NC_WRITE, &ncid));
11135
11136 /* Write data... */
11137 NC_PUT_DOUBLE("time", atm->time, 1);
11138 NC_PUT_DOUBLE("LAT", atm->lat, 1);
11139 NC_PUT_DOUBLE("LON", atm->lon, 1);
11140 NC_PUT_DOUBLE("PRESS", atm->p, 1);
11141 if (ctl->advect_vert_coord == 1) {
11142 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
11143 } else if (ctl->qnt_zeta >= 0) {
11144 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
11145 }
11146 for (int iq = 0; iq < ctl->nq; iq++)
11147 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
11148
11149 /* Close file... */
11150 NC(nc_close(ncid));
11151
11152 /* At the last time step create the init_fix_YYYYMMDDHH file... */
11153 if ((year == year_stop) && (mon == mon_stop)
11154 && (day == day_stop) && (hour == hour_stop)) {
11155
11156 /* Set filename... */
11157 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
11158 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
11159 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
11160 LOG(1, "Write init file: %s", filename_init);
11161
11162 /* Create file... */
11163 nc_create(filename_init, NC_NETCDF4, &ncid);
11164
11165 /* Define dimensions... */
11166 NC(nc_def_dim(ncid, "time", 1, &tid));
11167 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
11168 dim_ids[0] = tid;
11169 dim_ids[1] = pid;
11170
11171 /* Define variables and their attributes... */
11172 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
11173 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11174 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
11175 ctl->atm_nc_level, 0);
11176 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
11177 ctl->atm_nc_level, 0);
11178 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
11179 ctl->atm_nc_level, 0);
11180 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
11181 for (int iq = 0; iq < ctl->nq; iq++)
11182 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
11183 ctl->qnt_name[iq], ctl->qnt_unit[iq],
11184 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11185
11186 /* Define global attributes... */
11187 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
11188 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
11189
11190 /* End definitions... */
11191 NC(nc_enddef(ncid));
11192
11193 /* Write data... */
11194 NC_PUT_DOUBLE("time", atm->time, 0);
11195 NC_PUT_DOUBLE("LAT", atm->lat, 0);
11196 NC_PUT_DOUBLE("LON", atm->lon, 0);
11197 NC_PUT_DOUBLE("PRESS", atm->p, 0);
11198 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
11199 for (int iq = 0; iq < ctl->nq; iq++)
11200 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11201
11202 /* Close file... */
11203 NC(nc_close(ncid));
11204 }
11205}
11206
11207/*****************************************************************************/
11208
11210 const char *filename,
11211 const ctl_t *ctl,
11212 const atm_t *atm) {
11213
11214 int ncid, obsid, varid;
11215
11216 size_t start[2], count[2];
11217
11218 /* Create file... */
11219 NC(nc_create(filename, NC_NETCDF4, &ncid));
11220
11221 /* Define dimensions... */
11222 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
11223
11224 /* Define variables and their attributes... */
11225 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
11226 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
11227 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
11228 ctl->atm_nc_level, 0);
11229 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
11230 ctl->atm_nc_level, 0);
11231 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
11232 ctl->atm_nc_level, 0);
11233 for (int iq = 0; iq < ctl->nq; iq++)
11234 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
11235 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
11236 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
11237
11238 /* Define global attributes... */
11239 NC_PUT_ATT_GLOBAL("featureType", "point");
11240
11241 /* End definitions... */
11242 NC(nc_enddef(ncid));
11243
11244 /* Write data... */
11245 NC_PUT_DOUBLE("time", atm->time, 0);
11246 NC_PUT_DOUBLE("press", atm->p, 0);
11247 NC_PUT_DOUBLE("lon", atm->lon, 0);
11248 NC_PUT_DOUBLE("lat", atm->lat, 0);
11249 for (int iq = 0; iq < ctl->nq; iq++)
11250 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
11251
11252 /* Close file... */
11253 NC(nc_close(ncid));
11254}
11255
11256/*****************************************************************************/
11257
11259 const char *filename,
11260 const ctl_t *ctl,
11261 const atm_t *atm,
11262 const double t) {
11263
11264 static FILE *out;
11265
11266 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
11267 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
11268
11269 static int *obscount, nobs, nk;
11270
11271 static int ct[NENS], cx[NENS], cy[NENS], cz[NENS], n[NENS];
11272
11273 const int ensemble = (ctl->nens > 0);
11274
11275 /* Set timer */
11276 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
11277
11278 /* Check quantities... */
11279 if (ctl->qnt_m < 0)
11280 ERRMSG("Need quantity mass!");
11281 if (ensemble) {
11282 if (ctl->qnt_ens < 0)
11283 ERRMSG("Missing ensemble IDs!");
11284 if (ctl->nens > NENS)
11285 ERRMSG("Too many ensembles!");
11286 }
11287
11288 /* Init... */
11289 if (t == ctl->t_start) {
11290
11291 /* Allocate.. */
11292 ALLOC(area, double,
11293 ctl->csi_ny);
11294 ALLOC(rt, double,
11295 NOBS);
11296 ALLOC(rz, double,
11297 NOBS);
11298 ALLOC(rlon, double,
11299 NOBS);
11300 ALLOC(rlat, double,
11301 NOBS);
11302 ALLOC(robs, double,
11303 NOBS);
11304
11305 /* Read observation data... */
11306 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11307
11308 /* Read kernel data... */
11309 if (ctl->csi_kernel[0] != '-')
11310 read_kernel(ctl->csi_kernel, kz, kw, &nk);
11311
11312 /* Create new file... */
11313 LOG(1, "Write CSI%s data: %s", ensemble ? " ensemble" : "", filename);
11314 if (!(out = fopen(filename, "w")))
11315 ERRMSG("Cannot create file!");
11316
11317 /* Write header... */
11318 fprintf(out,
11319 "# $1 = time [s]\n"
11320 "# $2 = ensemble ID\n"
11321 "# $3 = number of hits (cx)\n"
11322 "# $4 = number of misses (cy)\n"
11323 "# $5 = number of false alarms (cz)\n"
11324 "# $6 = number of observations (cx + cy)\n"
11325 "# $7 = number of forecasts (cx + cz)\n"
11326 "# $8 = bias (%%)\n"
11327 "# $9 = POD (%%)\n"
11328 "# $10 = FAR (%%)\n"
11329 "# $11 = CSI (%%)\n"
11330 "# $12 = hits by random chance\n"
11331 "# $13 = ETS (%%)\n"
11332 "# $14 = Pearson R\n"
11333 "# $15 = Spearman R\n"
11334 "# $16 = mean error [kg/m²]\n"
11335 "# $17 = RMSE [kg/m²]\n"
11336 "# $18 = MAE [kg/m²]\n"
11337 "# $19 = log-likelihood\n" "# $20 = number of points\n\n");
11338
11339 /* Set grid box size... */
11340 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
11341 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
11342 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
11343
11344 /* Set horizontal coordinates... */
11345 for (int iy = 0; iy < ctl->csi_ny; iy++) {
11346 double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
11347 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.0) * cos(DEG2RAD(lat));
11348 }
11349 }
11350
11351 /* Set time interval... */
11352 double t0 = t - 0.5 * ctl->dt_mod;
11353 double t1 = t + 0.5 * ctl->dt_mod;
11354
11355 /* Allocate... */
11356 int grid_size = ctl->csi_nx * ctl->csi_ny * ctl->csi_nz;
11357 ALLOC(modmean, double,
11358 (ensemble ? ctl->nens : 1) * grid_size);
11359 ALLOC(obsmean, double,
11360 grid_size);
11361 ALLOC(obscount, int,
11362 grid_size);
11363 ALLOC(obsstd, double,
11364 grid_size);
11365
11366 /* Init... */
11367 for (int i = 0; i < (ensemble ? ctl->nens : 1); i++)
11368 ct[i] = cx[i] = cy[i] = cz[i] = n[i] = 0;
11369
11370 /* Loop over observations... */
11371 for (int i = 0; i < nobs; i++) {
11372 if (rt[i] < t0 || rt[i] >= t1 || !isfinite(robs[i]))
11373 continue;
11374
11375 /* Calculate indices... */
11376 int ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
11377 int iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
11378 int iz = (int) ((rz[i] - ctl->csi_z0) / dz);
11379 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11380 || iz >= ctl->csi_nz)
11381 continue;
11382
11383 /* Get mean observation index... */
11384 const int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11385 obsmean[idx] += robs[i];
11386 obsstd[idx] += SQR(robs[i]);
11387 obscount[idx]++;
11388 }
11389
11390 /* Analyze model data... */
11391 for (int ip = 0; ip < atm->np; ip++) {
11392
11393 /* Check time... */
11394 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11395 continue;
11396
11397 /* Get ensemble ID... */
11398 int ens_id = ensemble ? (int) atm->q[ctl->qnt_ens][ip] : 0;
11399 if (ens_id < 0 || ens_id >= (ensemble ? ctl->nens : 1))
11400 ERRMSG("Ensemble ID out of range!");
11401
11402 /* Get indices... */
11403 int ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
11404 int iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
11405 int iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
11406 if (ix < 0 || ix >= ctl->csi_nx || iy < 0 || iy >= ctl->csi_ny || iz < 0
11407 || iz >= ctl->csi_nz)
11408 continue;
11409
11410 /* Get total mass in grid cell... */
11411 int idx =
11412 ens_id * grid_size + ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11413 modmean[idx] +=
11414 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11415 }
11416
11417 /* Analyze all grid cells... */
11418 for (int ix = 0; ix < ctl->csi_nx; ix++)
11419 for (int iy = 0; iy < ctl->csi_ny; iy++)
11420 for (int iz = 0; iz < ctl->csi_nz; iz++) {
11421
11422 /* Calculate mean observation index... */
11423 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
11424 if (obscount[idx]) {
11425 obsmean[idx] /= obscount[idx];
11426 obsstd[idx] = sqrt(obsstd[idx] - SQR(obsmean[idx]));
11427 }
11428
11429 /* Calculate model mean per ensemble... */
11430 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11431 int midx = e * grid_size + idx;
11432 if (modmean[midx] > 0)
11433 modmean[midx] /= (1e6 * area[iy]);
11434 }
11435
11436 /* Check number of observations... */
11437 if (obscount[idx]) {
11438
11439 /* Calculate CSI... */
11440 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11441 int midx = e * grid_size + idx;
11442 ct[e]++;
11443 if (obsmean[idx] >= ctl->csi_obsmin
11444 && modmean[midx] >= ctl->csi_modmin)
11445 cx[e]++;
11446 else if (obsmean[idx] >= ctl->csi_obsmin)
11447 cy[e]++;
11448 else if (modmean[midx] >= ctl->csi_modmin)
11449 cz[e]++;
11450
11451 /* Save data for other verification statistics... */
11452 if (obsmean[idx] >= ctl->csi_obsmin
11453 || modmean[midx] >= ctl->csi_modmin) {
11454 x[n[e]] = modmean[midx];
11455 y[n[e]] = obsmean[idx];
11456 if (modmean[midx] >= ctl->csi_modmin)
11457 obsstdn[n[e]] = obsstd[idx];
11458 if ((++n[e]) >= NCSI)
11459 ERRMSG("Too many points for statistics!");
11460 }
11461 }
11462 }
11463 }
11464
11465 /* Write output... */
11466 if (fmod(t, ctl->csi_dt_out) == 0) {
11467 for (int e = 0; e < (ensemble ? ctl->nens : 1); e++) {
11468
11469 if (n[e] == 0)
11470 continue;
11471
11472 /* Calculate verification statistics
11473 (https://www.cawcr.gov.au/projects/verification/) ... */
11474 static double work[2 * NCSI], work2[2 * NCSI];
11475 int n_obs = cx[e] + cy[e];
11476 int n_for = cx[e] + cz[e];
11477 double cx_rd = (ct[e] > 0) ? (1. * n_obs * n_for) / ct[e] : NAN;
11478 double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
11479 double pod = (n_obs > 0) ? 100. * cx[e] / n_obs : NAN;
11480 double far = (n_for > 0) ? 100. * cz[e] / n_for : NAN;
11481 double csi =
11482 (cx[e] + cy[e] + cz[e] >
11483 0) ? 100. * cx[e] / (cx[e] + cy[e] + cz[e]) : NAN;
11484 double ets =
11485 (cx[e] + cy[e] + cz[e] - cx_rd >
11486 0) ? 100. * (cx[e] - cx_rd) / (cx[e] + cy[e] + cz[e] - cx_rd) : NAN;
11487 double rho_p = gsl_stats_correlation(x, 1, y, 1, (size_t) n[e]);
11488 double rho_s = gsl_stats_spearman(x, 1, y, 1, (size_t) n[e], work);
11489 for (int i = 0; i < n[e]; i++) {
11490 work[i] = x[i] - y[i];
11491 work2[i] = (obsstdn[i] != 0) ? work[i] / obsstdn[i] : 0;
11492 }
11493 double mean = gsl_stats_mean(work, 1, (size_t) n[e]);
11494 double rmse = gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n[e], 0.0);
11495 double absdev = gsl_stats_absdev_m(work, 1, (size_t) n[e], 0.0);
11496 double loglikelihood = gsl_stats_tss(work2, 1, (size_t) n[e]) * -0.5;
11497
11498 /* Write... */
11499 fprintf(out,
11500 "%.2f %d %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n",
11501 t, ensemble ? e : -999, cx[e], cy[e], cz[e], n_obs, n_for, bias,
11502 pod, far, csi, cx_rd, ets, rho_p, rho_s, mean, rmse, absdev,
11503 loglikelihood, n[e]);
11504
11505 /* Set counters to zero... */
11506 ct[e] = cx[e] = cy[e] = cz[e] = n[e] = 0;
11507 }
11508 }
11509
11510 /* Free... */
11511 free(modmean);
11512 free(obsmean);
11513 free(obscount);
11514 free(obsstd);
11515
11516 /* Finalize... */
11517 if (t == ctl->t_stop) {
11518
11519 /* Close output file... */
11520 fclose(out);
11521
11522 /* Free... */
11523 free(area);
11524 free(rt);
11525 free(rz);
11526 free(rlon);
11527 free(rlat);
11528 free(robs);
11529 }
11530}
11531
11532/*****************************************************************************/
11533
11535 const char *filename,
11536 const ctl_t *ctl,
11537 const atm_t *atm,
11538 const double t) {
11539
11540 static FILE *out;
11541
11542 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
11543 x[3], zm[NENS];
11544
11545 static int n[NENS];
11546
11547 /* Set timer... */
11548 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
11549
11550 /* Check quantities... */
11551 if (ctl->qnt_ens < 0)
11552 ERRMSG("Missing ensemble IDs!");
11553
11554 /* Set time interval... */
11555 const double t0 = t - 0.5 * ctl->dt_mod;
11556 const double t1 = t + 0.5 * ctl->dt_mod;
11557
11558 /* Init... */
11559 for (int i = 0; i < NENS; i++) {
11560 for (int iq = 0; iq < ctl->nq; iq++)
11561 qm[iq][i] = qs[iq][i] = 0;
11562 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
11563 n[i] = 0;
11564 }
11565
11566 /* Loop over air parcels... */
11567 for (int ip = 0; ip < atm->np; ip++) {
11568
11569 /* Check time... */
11570 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11571 continue;
11572
11573 /* Check ensemble ID... */
11574 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
11575 ERRMSG("Ensemble ID is out of range!");
11576
11577 /* Get means... */
11578 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
11579 for (int iq = 0; iq < ctl->nq; iq++) {
11580 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
11581 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
11582 }
11583 xm[ctl->qnt_ens][0] += x[0];
11584 xm[ctl->qnt_ens][1] += x[1];
11585 xm[ctl->qnt_ens][2] += x[2];
11586 zm[ctl->qnt_ens] += Z(atm->p[ip]);
11587 n[ctl->qnt_ens]++;
11588 }
11589
11590 /* Create file... */
11591 LOG(1, "Write ensemble data: %s", filename);
11592 if (!(out = fopen(filename, "w")))
11593 ERRMSG("Cannot create file!");
11594
11595 /* Write header... */
11596 fprintf(out,
11597 "# $1 = time [s]\n"
11598 "# $2 = altitude [km]\n"
11599 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11600 for (int iq = 0; iq < ctl->nq; iq++)
11601 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
11602 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11603 for (int iq = 0; iq < ctl->nq; iq++)
11604 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
11605 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11606 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
11607
11608 /* Write data... */
11609 for (int i = 0; i < NENS; i++)
11610 if (n[i] > 0) {
11611 cart2geo(xm[i], &dummy, &lon, &lat);
11612 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
11613 for (int iq = 0; iq < ctl->nq; iq++) {
11614 fprintf(out, " ");
11615 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
11616 }
11617 for (int iq = 0; iq < ctl->nq; iq++) {
11618 fprintf(out, " ");
11619 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
11620 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
11621 }
11622 fprintf(out, " %d\n", n[i]);
11623 }
11624
11625 /* Close file... */
11626 fclose(out);
11627}
11628
11629/*****************************************************************************/
11630
11632 const char *filename,
11633 const ctl_t *ctl,
11634 met_t *met0,
11635 met_t *met1,
11636 const atm_t *atm,
11637 const double t) {
11638
11639 static double kz[EP], kw[EP];
11640
11641 static int nk;
11642
11643 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
11644
11645 int *ixs, *iys, *izs, *np;
11646
11647 /* Set timer... */
11648 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
11649
11650 /* Write info... */
11651 LOG(1, "Write grid data: %s", filename);
11652
11653 /* Init... */
11654 if (t == ctl->t_start) {
11655
11656 /* Read kernel data... */
11657 if (ctl->grid_kernel[0] != '-')
11658 read_kernel(ctl->grid_kernel, kz, kw, &nk);
11659 }
11660
11661 /* Allocate... */
11662 ALLOC(cd, double,
11663 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11664 for (int iq = 0; iq < ctl->nq; iq++) {
11665 ALLOC(mean[iq], double,
11666 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11667 ALLOC(sigma[iq], double,
11668 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11669 }
11670 ALLOC(vmr_impl, double,
11671 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11672 ALLOC(z, double,
11673 ctl->grid_nz);
11674 ALLOC(lon, double,
11675 ctl->grid_nx);
11676 ALLOC(lat, double,
11677 ctl->grid_ny);
11678 ALLOC(area, double,
11679 ctl->grid_ny);
11680 ALLOC(press, double,
11681 ctl->grid_nz);
11682 ALLOC(np, int,
11683 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11684 ALLOC(ixs, int,
11685 atm->np);
11686 ALLOC(iys, int,
11687 atm->np);
11688 ALLOC(izs, int,
11689 atm->np);
11690
11691 /* Set grid box size... */
11692 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
11693 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
11694 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
11695
11696 /* Set vertical coordinates... */
11697#pragma omp parallel for default(shared)
11698 for (int iz = 0; iz < ctl->grid_nz; iz++) {
11699 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
11700 press[iz] = P(z[iz]);
11701 }
11702
11703 /* Set horizontal coordinates... */
11704 for (int ix = 0; ix < ctl->grid_nx; ix++)
11705 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
11706#pragma omp parallel for default(shared)
11707 for (int iy = 0; iy < ctl->grid_ny; iy++) {
11708 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
11709 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
11710 }
11711
11712 /* Set time interval for output... */
11713 const double t0 = t - 0.5 * ctl->dt_mod;
11714 const double t1 = t + 0.5 * ctl->dt_mod;
11715
11716 /* Get grid box indices... */
11717#pragma omp parallel for default(shared)
11718 for (int ip = 0; ip < atm->np; ip++) {
11719 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
11720 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
11721 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
11722 if (atm->time[ip] < t0 || atm->time[ip] > t1
11723 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
11724 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
11725 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
11726 izs[ip] = -1;
11727 }
11728
11729 /* Average data... */
11730 for (int ip = 0; ip < atm->np; ip++)
11731 if (izs[ip] >= 0) {
11732 int idx =
11733 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
11734 double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
11735 np[idx]++;
11736 for (int iq = 0; iq < ctl->nq; iq++) {
11737 mean[iq][idx] += kernel * atm->q[iq][ip];
11738 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
11739 }
11740 }
11741
11742 /* Calculate column density and volume mixing ratio... */
11743#pragma omp parallel for default(shared)
11744 for (int ix = 0; ix < ctl->grid_nx; ix++)
11745 for (int iy = 0; iy < ctl->grid_ny; iy++)
11746 for (int iz = 0; iz < ctl->grid_nz; iz++) {
11747
11748 /* Get grid index... */
11749 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
11750
11751 /* Calculate column density... */
11752 cd[idx] = NAN;
11753 if (ctl->qnt_m >= 0)
11754 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
11755
11756 /* Calculate volume mixing ratio (implicit)... */
11757 vmr_impl[idx] = NAN;
11758 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
11759 && met1 != NULL) {
11760 vmr_impl[idx] = 0;
11761 if (mean[ctl->qnt_m][idx] > 0) {
11762
11763 /* Get temperature... */
11764 double temp;
11766 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
11767 lon[ix], lat[iy], &temp, ci, cw, 1);
11768
11769 /* Calculate volume mixing ratio... */
11770 vmr_impl[idx] =
11771 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
11772 }
11773 }
11774
11775 /* Calculate mean... */
11776 if (np[idx] > 0)
11777 for (int iq = 0; iq < ctl->nq; iq++) {
11778 mean[iq][idx] /= np[idx];
11779 double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
11780 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
11781 } else
11782 for (int iq = 0; iq < ctl->nq; iq++) {
11783 mean[iq][idx] = NAN;
11784 sigma[iq][idx] = NAN;
11785 }
11786 }
11787
11788 /* Write ASCII data... */
11789 if (ctl->grid_type == 0)
11790 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
11791 t, z, lon, lat, area, dz, np);
11792
11793 /* Write netCDF data... */
11794 else if (ctl->grid_type == 1)
11795 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
11796 t, z, lon, lat, area, dz, np);
11797
11798 /* Error message... */
11799 else
11800 ERRMSG("Grid data format GRID_TYPE unknown!");
11801
11802 /* Free... */
11803 free(cd);
11804 for (int iq = 0; iq < ctl->nq; iq++) {
11805 free(mean[iq]);
11806 free(sigma[iq]);
11807 }
11808 free(vmr_impl);
11809 free(z);
11810 free(lon);
11811 free(lat);
11812 free(area);
11813 free(press);
11814 free(np);
11815 free(ixs);
11816 free(iys);
11817 free(izs);
11818}
11819
11820/*****************************************************************************/
11821
11823 const char *filename,
11824 const ctl_t *ctl,
11825 const double *cd,
11826 double *mean[NQ],
11827 double *sigma[NQ],
11828 const double *vmr_impl,
11829 const double t,
11830 const double *z,
11831 const double *lon,
11832 const double *lat,
11833 const double *area,
11834 const double dz,
11835 const int *np) {
11836
11837 FILE *out;
11838
11839 /* Check if gnuplot output is requested... */
11840 if (ctl->grid_gpfile[0] != '-') {
11841
11842 /* Create gnuplot pipe... */
11843 if (!(out = popen("gnuplot", "w")))
11844 ERRMSG("Cannot create pipe to gnuplot!");
11845
11846 /* Set plot filename... */
11847 fprintf(out, "set out \"%s.png\"\n", filename);
11848
11849 /* Set time string... */
11850 double r;
11851 int year, mon, day, hour, min, sec;
11852 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
11853 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
11854 year, mon, day, hour, min);
11855
11856 /* Dump gnuplot file to pipe... */
11857 FILE *in;
11858 char line[LEN];
11859 if (!(in = fopen(ctl->grid_gpfile, "r")))
11860 ERRMSG("Cannot open file!");
11861 while (fgets(line, LEN, in))
11862 fprintf(out, "%s", line);
11863 fclose(in);
11864 }
11865
11866 else {
11867
11868 /* Create file... */
11869 if (!(out = fopen(filename, "w")))
11870 ERRMSG("Cannot create file!");
11871 }
11872
11873 /* Write header... */
11874 fprintf(out,
11875 "# $1 = time [s]\n"
11876 "# $2 = altitude [km]\n"
11877 "# $3 = longitude [deg]\n"
11878 "# $4 = latitude [deg]\n"
11879 "# $5 = surface area [km^2]\n"
11880 "# $6 = layer depth [km]\n"
11881 "# $7 = column density (implicit) [kg/m^2]\n"
11882 "# $8 = volume mixing ratio (implicit) [ppv]\n"
11883 "# $9 = number of particles [1]\n");
11884 for (int iq = 0; iq < ctl->nq; iq++)
11885 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
11886 ctl->qnt_unit[iq]);
11887 if (ctl->grid_stddev)
11888 for (int iq = 0; iq < ctl->nq; iq++)
11889 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
11890 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11891 fprintf(out, "\n");
11892
11893 /* Write data... */
11894 for (int ix = 0; ix < ctl->grid_nx; ix++) {
11895 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
11896 fprintf(out, "\n");
11897 for (int iy = 0; iy < ctl->grid_ny; iy++) {
11898 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
11899 fprintf(out, "\n");
11900 for (int iz = 0; iz < ctl->grid_nz; iz++) {
11901 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
11902 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
11903 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
11904 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
11905 for (int iq = 0; iq < ctl->nq; iq++) {
11906 fprintf(out, " ");
11907 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
11908 }
11909 if (ctl->grid_stddev)
11910 for (int iq = 0; iq < ctl->nq; iq++) {
11911 fprintf(out, " ");
11912 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
11913 }
11914 fprintf(out, "\n");
11915 }
11916 }
11917 }
11918 }
11919
11920 /* Close file... */
11921 fclose(out);
11922}
11923
11924/*****************************************************************************/
11925
11927 const char *filename,
11928 const ctl_t *ctl,
11929 const double *cd,
11930 double *mean[NQ],
11931 double *sigma[NQ],
11932 const double *vmr_impl,
11933 const double t,
11934 const double *z,
11935 const double *lon,
11936 const double *lat,
11937 const double *area,
11938 const double dz,
11939 const int *np) {
11940
11941 char longname[2 * LEN], varname[2 * LEN];
11942
11943 double *help;
11944
11945 int *help2, ncid, dimid[10], varid;
11946
11947 size_t start[2], count[2];
11948
11949 /* Allocate... */
11950 ALLOC(help, double,
11951 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11952 ALLOC(help2, int,
11953 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
11954
11955 /* Create file... */
11956 NC(nc_create(filename, NC_NETCDF4, &ncid));
11957
11958 /* Define dimensions... */
11959 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
11960 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
11961 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
11962 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
11963 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
11964
11965 /* Define variables and their attributes... */
11966 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
11967 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
11968 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
11969 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
11970 0);
11971 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
11972 0);
11973 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
11974 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
11975
11976 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
11977 ctl->grid_nc_level, 0);
11978 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid,
11979 "volume mixing ratio (implicit)", "ppv", ctl->grid_nc_level, 0);
11980 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
11981 for (int iq = 0; iq < ctl->nq; iq++) {
11982 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
11983 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
11984 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
11985 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
11986 if (ctl->grid_stddev) {
11987 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
11988 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
11989 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
11990 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
11991 }
11992 }
11993 /* End definitions... */
11994 NC(nc_enddef(ncid));
11995
11996 /* Write data... */
11997 NC_PUT_DOUBLE("time", &t, 0);
11998 NC_PUT_DOUBLE("lon", lon, 0);
11999 NC_PUT_DOUBLE("lat", lat, 0);
12000 NC_PUT_DOUBLE("z", z, 0);
12001 NC_PUT_DOUBLE("area", area, 0);
12002 NC_PUT_DOUBLE("dz", &dz, 0);
12003
12004 for (int ix = 0; ix < ctl->grid_nx; ix++)
12005 for (int iy = 0; iy < ctl->grid_ny; iy++)
12006 for (int iz = 0; iz < ctl->grid_nz; iz++)
12007 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12008 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12009 NC_PUT_DOUBLE("cd", help, 0);
12010
12011 for (int ix = 0; ix < ctl->grid_nx; ix++)
12012 for (int iy = 0; iy < ctl->grid_ny; iy++)
12013 for (int iz = 0; iz < ctl->grid_nz; iz++)
12014 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12015 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12016 NC_PUT_DOUBLE("vmr_impl", help, 0);
12017
12018 for (int ix = 0; ix < ctl->grid_nx; ix++)
12019 for (int iy = 0; iy < ctl->grid_ny; iy++)
12020 for (int iz = 0; iz < ctl->grid_nz; iz++)
12021 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12022 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12023 NC_PUT_INT("np", help2, 0);
12024
12025 for (int iq = 0; iq < ctl->nq; iq++) {
12026 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
12027 for (int ix = 0; ix < ctl->grid_nx; ix++)
12028 for (int iy = 0; iy < ctl->grid_ny; iy++)
12029 for (int iz = 0; iz < ctl->grid_nz; iz++)
12030 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12031 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12032 NC_PUT_DOUBLE(varname, help, 0);
12033 }
12034
12035 if (ctl->grid_stddev)
12036 for (int iq = 0; iq < ctl->nq; iq++) {
12037 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
12038 for (int ix = 0; ix < ctl->grid_nx; ix++)
12039 for (int iy = 0; iy < ctl->grid_ny; iy++)
12040 for (int iz = 0; iz < ctl->grid_nz; iz++)
12041 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
12042 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
12043 NC_PUT_DOUBLE(varname, help, 0);
12044 }
12045
12046 /* Close file... */
12047 NC(nc_close(ncid));
12048
12049 /* Free... */
12050 free(help);
12051 free(help2);
12052}
12053
12054/*****************************************************************************/
12055
12057 const char *filename,
12058 const ctl_t *ctl,
12059 met_t *met) {
12060
12061 /* Create file... */
12062 FILE *out;
12063 if (!(out = fopen(filename, "w")))
12064 ERRMSG("Cannot create file!");
12065
12066 /* Write type of binary data... */
12067 FWRITE(&ctl->met_type, int,
12068 1,
12069 out);
12070
12071 /* Write version of binary data... */
12072 int version = 103;
12073 FWRITE(&version, int,
12074 1,
12075 out);
12076
12077 /* Write grid data... */
12078 FWRITE(&met->time, double,
12079 1,
12080 out);
12081 FWRITE(&met->nx, int,
12082 1,
12083 out);
12084 FWRITE(&met->ny, int,
12085 1,
12086 out);
12087 FWRITE(&met->np, int,
12088 1,
12089 out);
12090 FWRITE(met->lon, double,
12091 (size_t) met->nx,
12092 out);
12093 FWRITE(met->lat, double,
12094 (size_t) met->ny,
12095 out);
12096 FWRITE(met->p, double,
12097 (size_t) met->np,
12098 out);
12099
12100 /* Write surface data... */
12101 write_met_bin_2d(out, met, met->ps, "PS");
12102 write_met_bin_2d(out, met, met->ts, "TS");
12103 write_met_bin_2d(out, met, met->zs, "ZS");
12104 write_met_bin_2d(out, met, met->us, "US");
12105 write_met_bin_2d(out, met, met->vs, "VS");
12106 write_met_bin_2d(out, met, met->ess, "ESS");
12107 write_met_bin_2d(out, met, met->nss, "NSS");
12108 write_met_bin_2d(out, met, met->shf, "SHF");
12109 write_met_bin_2d(out, met, met->lsm, "LSM");
12110 write_met_bin_2d(out, met, met->sst, "SST");
12111 write_met_bin_2d(out, met, met->pbl, "PBL");
12112 write_met_bin_2d(out, met, met->pt, "PT");
12113 write_met_bin_2d(out, met, met->tt, "TT");
12114 write_met_bin_2d(out, met, met->zt, "ZT");
12115 write_met_bin_2d(out, met, met->h2ot, "H2OT");
12116 write_met_bin_2d(out, met, met->pct, "PCT");
12117 write_met_bin_2d(out, met, met->pcb, "PCB");
12118 write_met_bin_2d(out, met, met->cl, "CL");
12119 write_met_bin_2d(out, met, met->plcl, "PLCL");
12120 write_met_bin_2d(out, met, met->plfc, "PLFC");
12121 write_met_bin_2d(out, met, met->pel, "PEL");
12122 write_met_bin_2d(out, met, met->cape, "CAPE");
12123 write_met_bin_2d(out, met, met->cin, "CIN");
12124 write_met_bin_2d(out, met, met->o3c, "O3C");
12125
12126 /* Write level data... */
12127 write_met_bin_3d(out, ctl, met, met->z, "Z",
12128 ctl->met_zfp_prec[0], ctl->met_zfp_tol[0]);
12129 write_met_bin_3d(out, ctl, met, met->t, "T",
12130 ctl->met_zfp_prec[1], ctl->met_zfp_tol[1]);
12131 write_met_bin_3d(out, ctl, met, met->u, "U",
12132 ctl->met_zfp_prec[2], ctl->met_zfp_tol[2]);
12133 write_met_bin_3d(out, ctl, met, met->v, "V",
12134 ctl->met_zfp_prec[3], ctl->met_zfp_tol[3]);
12135 write_met_bin_3d(out, ctl, met, met->w, "W",
12136 ctl->met_zfp_prec[4], ctl->met_zfp_tol[4]);
12137 write_met_bin_3d(out, ctl, met, met->pv, "PV",
12138 ctl->met_zfp_prec[5], ctl->met_zfp_tol[5]);
12139 write_met_bin_3d(out, ctl, met, met->h2o, "H2O",
12140 ctl->met_zfp_prec[6], ctl->met_zfp_tol[6]);
12141 write_met_bin_3d(out, ctl, met, met->o3, "O3",
12142 ctl->met_zfp_prec[7], ctl->met_zfp_tol[7]);
12143 write_met_bin_3d(out, ctl, met, met->lwc, "LWC",
12144 ctl->met_zfp_prec[8], ctl->met_zfp_tol[8]);
12145 write_met_bin_3d(out, ctl, met, met->rwc, "RWC",
12146 ctl->met_zfp_prec[9], ctl->met_zfp_tol[9]);
12147 write_met_bin_3d(out, ctl, met, met->iwc, "IWC",
12148 ctl->met_zfp_prec[10], ctl->met_zfp_tol[10]);
12149 write_met_bin_3d(out, ctl, met, met->swc, "SWC",
12150 ctl->met_zfp_prec[11], ctl->met_zfp_tol[11]);
12151 write_met_bin_3d(out, ctl, met, met->cc, "CC",
12152 ctl->met_zfp_prec[12], ctl->met_zfp_tol[12]);
12153 if (METVAR != 13)
12154 ERRMSG("Number of meteo variables doesn't match!");
12155
12156 /* Write final flag... */
12157 int final = 999;
12158 FWRITE(&final, int,
12159 1,
12160 out);
12161
12162 /* Close file... */
12163 fclose(out);
12164}
12165
12166/*****************************************************************************/
12167
12169 FILE *out,
12170 met_t *met,
12171 float var[EX][EY],
12172 const char *varname) {
12173
12174 float *help;
12175
12176 /* Allocate... */
12177 ALLOC(help, float,
12178 EX * EY);
12179
12180 /* Copy data... */
12181 for (int ix = 0; ix < met->nx; ix++)
12182 for (int iy = 0; iy < met->ny; iy++)
12183 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
12184
12185 /* Write uncompressed data... */
12186 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
12187 FWRITE(help, float,
12188 (size_t) (met->nx * met->ny),
12189 out);
12190
12191 /* Free... */
12192 free(help);
12193}
12194
12195/*****************************************************************************/
12196
12198 FILE *out,
12199 const ctl_t *ctl,
12200 met_t *met,
12201 float var[EX][EY][EP],
12202 const char *varname,
12203 const int precision,
12204 const double tolerance) {
12205
12206 float *help;
12207
12208 /* Allocate... */
12209 ALLOC(help, float,
12210 EX * EY * EP);
12211
12212 /* Copy data... */
12213#pragma omp parallel for default(shared) collapse(2)
12214 for (int ix = 0; ix < met->nx; ix++)
12215 for (int iy = 0; iy < met->ny; iy++)
12216 for (int ip = 0; ip < met->np; ip++)
12217 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
12218
12219 /* Write uncompressed data... */
12220 if (ctl->met_type == 1) {
12221 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
12222 FWRITE(help, float,
12223 (size_t) (met->nx * met->ny * met->np),
12224 out);
12225 }
12226
12227 /* Write packed data... */
12228 else if (ctl->met_type == 2)
12229 compress_pck(varname, help, (size_t) (met->ny * met->nx),
12230 (size_t) met->np, 0, out);
12231
12232 /* Write zfp data... */
12233#ifdef ZFP
12234 else if (ctl->met_type == 3) {
12235 FWRITE(&precision, int,
12236 1,
12237 out);
12238 FWRITE(&tolerance, double,
12239 1,
12240 out);
12241 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
12242 tolerance, 0, out);
12243 }
12244#endif
12245
12246 /* Write zstd data... */
12247#ifdef ZSTD
12248 else if (ctl->met_type == 4)
12249 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
12250 ctl->met_zstd_level, out);
12251#endif
12252
12253 /* Write cmultiscale data... */
12254#ifdef CMS
12255 else if (ctl->met_type == 5) {
12256 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
12257 (size_t) met->np, 0, out);
12258 }
12259#endif
12260
12261 /* Unknown method... */
12262 else {
12263 ERRMSG("MET_TYPE not supported!");
12264 LOG(3, "%d %g", precision, tolerance);
12265 }
12266
12267 /* Free... */
12268 free(help);
12269}
12270
12271/*****************************************************************************/
12272
12274 const char *filename,
12275 const ctl_t *ctl,
12276 met_t *met) {
12277
12278 /* Create file... */
12279 int ncid, varid;
12280 size_t start[4], count[4];
12281 nc_create(filename, NC_NETCDF4, &ncid);
12282
12283 /* Define dimensions... */
12284 int tid, lonid, latid, levid;
12285 NC(nc_def_dim(ncid, "time", 1, &tid));
12286 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
12287 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
12288 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
12289
12290 /* Define grid... */
12291 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
12292 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
12293 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
12294 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
12295 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
12296
12297 /* Define surface variables... */
12298 int dimid2[2] = { latid, lonid };
12299 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
12300 ctl->met_nc_level, 0);
12301 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
12302 ctl->met_nc_level, 0);
12303 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
12304 ctl->met_nc_level, 0);
12305 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
12306 "m s**-1", ctl->met_nc_level, 0);
12307 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
12308 "m s**-1", ctl->met_nc_level, 0);
12309 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
12310 "Instantaneous eastward turbulent surface stress", "N m**-2",
12311 ctl->met_nc_level, 0);
12312 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
12313 "Instantaneous northward turbulent surface stress", "N m**-2",
12314 ctl->met_nc_level, 0);
12315 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
12316 "Instantaneous surface sensible heat flux", "W m**-1",
12317 ctl->met_nc_level, 0);
12318 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
12319 ctl->met_nc_level, 0);
12320 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
12321 ctl->met_nc_level, 0);
12322 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
12323 ctl->met_nc_level, 0);
12324 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
12325 ctl->met_nc_level, 0);
12326 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
12327 ctl->met_nc_level, 0);
12328 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
12329 ctl->met_nc_level, 0);
12330 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
12331 ctl->met_nc_level, 0);
12332 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
12333 ctl->met_nc_level, 0);
12334 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
12335 ctl->met_nc_level, 0);
12336 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water",
12337 "kg m**2", ctl->met_nc_level, 0);
12338 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
12339 "Pressure at lifted condensation level (LCL)", "Pa",
12340 ctl->met_nc_level, 0);
12341 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
12342 "Pressure at level of free convection (LFC)", "Pa",
12343 ctl->met_nc_level, 0);
12344 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2,
12345 "Pressure at equilibrium level (EL)", "Pa", ctl->met_nc_level,
12346 0);
12347 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
12348 "Convective available potential energy", "J kg**-1",
12349 ctl->met_nc_level, 0);
12350 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition",
12351 "J kg**-1", ctl->met_nc_level, 0);
12352 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
12353 ctl->met_nc_level, 0);
12354
12355 /* Define level data... */
12356 int dimid3[3] = { levid, latid, lonid };
12357 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
12358 ctl->met_nc_level, ctl->met_nc_quant);
12359 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
12360 ctl->met_nc_level, ctl->met_nc_quant);
12361 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
12362 ctl->met_nc_level, ctl->met_nc_quant);
12363 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
12364 ctl->met_nc_level, ctl->met_nc_quant);
12365 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
12366 ctl->met_nc_level, ctl->met_nc_quant);
12367 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
12368 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12369 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
12370 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12371 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
12372 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12373 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
12374 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12375 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
12376 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
12377 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
12378 ctl->met_nc_level, ctl->met_nc_quant);
12379
12380 /* End definitions... */
12381 NC(nc_enddef(ncid));
12382
12383 /* Write grid data... */
12384 NC_PUT_DOUBLE("time", &met->time, 0);
12385 NC_PUT_DOUBLE("lon", met->lon, 0);
12386 NC_PUT_DOUBLE("lat", met->lat, 0);
12387 double phelp[EP];
12388 for (int ip = 0; ip < met->np; ip++)
12389 phelp[ip] = 100. * met->p[ip];
12390 NC_PUT_DOUBLE("lev", phelp, 0);
12391
12392 /* Write surface data... */
12393 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
12394 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
12395 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
12396 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
12397 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
12398 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
12399 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
12400 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
12401 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
12402 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
12403 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
12404 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
12405 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
12406 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
12407 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
12408 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
12409 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
12410 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
12411 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
12412 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
12413 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
12414 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
12415 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
12416 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
12417
12418 /* Write level data... */
12419 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
12420 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
12421 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
12422 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
12423 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
12424 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
12425 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
12426 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
12427 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
12428 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
12429 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
12430
12431 /* Close file... */
12432 NC(nc_close(ncid));
12433}
12434
12435/*****************************************************************************/
12436
12438 const int ncid,
12439 const char *varname,
12440 met_t *met,
12441 float var[EX][EY],
12442 const float scl) {
12443
12444 int varid;
12445 size_t start[4], count[4];
12446
12447 /* Allocate... */
12448 float *help;
12449 ALLOC(help, float,
12450 EX * EY);
12451
12452 /* Copy data... */
12453 for (int ix = 0; ix < met->nx; ix++)
12454 for (int iy = 0; iy < met->ny; iy++)
12455 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
12456
12457 /* Write data... */
12458 NC_PUT_FLOAT(varname, help, 0);
12459
12460 /* Free... */
12461 free(help);
12462}
12463
12464/*****************************************************************************/
12465
12467 const int ncid,
12468 const char *varname,
12469 met_t *met,
12470 float var[EX][EY][EP],
12471 const float scl) {
12472
12473 int varid;
12474 size_t start[4], count[4];
12475
12476 /* Allocate... */
12477 float *help;
12478 ALLOC(help, float,
12479 EX * EY * EP);
12480
12481 /* Copy data... */
12482 for (int ix = 0; ix < met->nx; ix++)
12483 for (int iy = 0; iy < met->ny; iy++)
12484 for (int ip = 0; ip < met->np; ip++)
12485 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
12486
12487 /* Write data... */
12488 NC_PUT_FLOAT(varname, help, 0);
12489
12490 /* Free... */
12491 free(help);
12492}
12493
12494/*****************************************************************************/
12495
12497 const char *filename,
12498 const ctl_t *ctl,
12499 met_t *met0,
12500 met_t *met1,
12501 const atm_t *atm,
12502 const double t) {
12503
12504 static FILE *out;
12505
12506 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
12507 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
12508
12509 static int nobs, *obscount, ip, okay;
12510
12511 /* Set timer... */
12512 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
12513
12514 /* Init... */
12515 if (t == ctl->t_start) {
12516
12517 /* Check quantity index for mass... */
12518 if (ctl->qnt_m < 0)
12519 ERRMSG("Need quantity mass!");
12520
12521 /* Check molar mass... */
12522 if (ctl->molmass <= 0)
12523 ERRMSG("Specify molar mass!");
12524
12525 /* Allocate... */
12526 ALLOC(lon, double,
12527 ctl->prof_nx);
12528 ALLOC(lat, double,
12529 ctl->prof_ny);
12530 ALLOC(area, double,
12531 ctl->prof_ny);
12532 ALLOC(z, double,
12533 ctl->prof_nz);
12534 ALLOC(press, double,
12535 ctl->prof_nz);
12536 ALLOC(rt, double,
12537 NOBS);
12538 ALLOC(rz, double,
12539 NOBS);
12540 ALLOC(rlon, double,
12541 NOBS);
12542 ALLOC(rlat, double,
12543 NOBS);
12544 ALLOC(robs, double,
12545 NOBS);
12546
12547 /* Read observation data... */
12548 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12549
12550 /* Create new output file... */
12551 LOG(1, "Write profile data: %s", filename);
12552 if (!(out = fopen(filename, "w")))
12553 ERRMSG("Cannot create file!");
12554
12555 /* Write header... */
12556 fprintf(out,
12557 "# $1 = time [s]\n"
12558 "# $2 = altitude [km]\n"
12559 "# $3 = longitude [deg]\n"
12560 "# $4 = latitude [deg]\n"
12561 "# $5 = pressure [hPa]\n"
12562 "# $6 = temperature [K]\n"
12563 "# $7 = volume mixing ratio [ppv]\n"
12564 "# $8 = H2O volume mixing ratio [ppv]\n"
12565 "# $9 = O3 volume mixing ratio [ppv]\n"
12566 "# $10 = observed BT index [K]\n"
12567 "# $11 = number of observations\n");
12568
12569 /* Set grid box size... */
12570 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
12571 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
12572 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
12573
12574 /* Set vertical coordinates... */
12575 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12576 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
12577 press[iz] = P(z[iz]);
12578 }
12579
12580 /* Set horizontal coordinates... */
12581 for (int ix = 0; ix < ctl->prof_nx; ix++)
12582 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
12583 for (int iy = 0; iy < ctl->prof_ny; iy++) {
12584 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
12585 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
12586 }
12587 }
12588
12589 /* Set time interval... */
12590 const double t0 = t - 0.5 * ctl->dt_mod;
12591 const double t1 = t + 0.5 * ctl->dt_mod;
12592
12593 /* Allocate... */
12594 ALLOC(mass, double,
12595 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
12596 ALLOC(obsmean, double,
12597 ctl->prof_nx * ctl->prof_ny);
12598 ALLOC(obscount, int,
12599 ctl->prof_nx * ctl->prof_ny);
12600
12601 /* Loop over observations... */
12602 for (int i = 0; i < nobs; i++) {
12603
12604 /* Check time... */
12605 if (rt[i] < t0)
12606 continue;
12607 else if (rt[i] >= t1)
12608 break;
12609
12610 /* Check observation data... */
12611 if (!isfinite(robs[i]))
12612 continue;
12613
12614 /* Calculate indices... */
12615 int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
12616 int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
12617
12618 /* Check indices... */
12619 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
12620 continue;
12621
12622 /* Get mean observation index... */
12623 int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
12624 obsmean[idx] += robs[i];
12625 obscount[idx]++;
12626 }
12627
12628 /* Analyze model data... */
12629 for (ip = 0; ip < atm->np; ip++) {
12630
12631 /* Check time... */
12632 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12633 continue;
12634
12635 /* Get indices... */
12636 int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
12637 int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
12638 int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
12639
12640 /* Check indices... */
12641 if (ix < 0 || ix >= ctl->prof_nx ||
12642 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
12643 continue;
12644
12645 /* Get total mass in grid cell... */
12646 int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12647 mass[idx] += atm->q[ctl->qnt_m][ip];
12648 }
12649
12650 /* Extract profiles... */
12651 for (int ix = 0; ix < ctl->prof_nx; ix++)
12652 for (int iy = 0; iy < ctl->prof_ny; iy++) {
12653 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
12654 if (obscount[idx2] > 0) {
12655
12656 /* Check profile... */
12657 okay = 0;
12658 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12659 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12660 if (mass[idx3] > 0) {
12661 okay = 1;
12662 break;
12663 }
12664 }
12665 if (!okay)
12666 continue;
12667
12668 /* Write output... */
12669 fprintf(out, "\n");
12670
12671 /* Loop over altitudes... */
12672 for (int iz = 0; iz < ctl->prof_nz; iz++) {
12673
12674 /* Get temperature, water vapor, and ozone... */
12676 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
12677 lon[ix], lat[iy], &temp, ci, cw, 1);
12678 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
12679 lon[ix], lat[iy], &h2o, ci, cw, 0);
12680 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
12681 lon[ix], lat[iy], &o3, ci, cw, 0);
12682
12683 /* Calculate volume mixing ratio... */
12684 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
12685 vmr = MA / ctl->molmass * mass[idx3]
12686 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
12687
12688 /* Write output... */
12689 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
12690 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
12691 obsmean[idx2] / obscount[idx2], obscount[idx2]);
12692 }
12693 }
12694 }
12695
12696 /* Free... */
12697 free(mass);
12698 free(obsmean);
12699 free(obscount);
12700
12701 /* Finalize... */
12702 if (t == ctl->t_stop) {
12703
12704 /* Close output file... */
12705 fclose(out);
12706
12707 /* Free... */
12708 free(lon);
12709 free(lat);
12710 free(area);
12711 free(z);
12712 free(press);
12713 free(rt);
12714 free(rz);
12715 free(rlon);
12716 free(rlat);
12717 free(robs);
12718 }
12719}
12720
12721/*****************************************************************************/
12722
12724 const char *filename,
12725 const ctl_t *ctl,
12726 met_t *met0,
12727 met_t *met1,
12728 const atm_t *atm,
12729 const double t) {
12730
12731 static FILE *out;
12732
12733 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
12734 kw[EP];
12735
12736 static int nobs, nk;
12737
12738 /* Set timer... */
12739 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
12740
12741 /* Init... */
12742 if (t == ctl->t_start) {
12743
12744 /* Allocate... */
12745 ALLOC(rt, double,
12746 NOBS);
12747 ALLOC(rz, double,
12748 NOBS);
12749 ALLOC(rlon, double,
12750 NOBS);
12751 ALLOC(rlat, double,
12752 NOBS);
12753 ALLOC(robs, double,
12754 NOBS);
12755
12756 /* Read observation data... */
12757 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
12758
12759 /* Read kernel data... */
12760 if (ctl->sample_kernel[0] != '-')
12761 read_kernel(ctl->sample_kernel, kz, kw, &nk);
12762
12763 /* Create output file... */
12764 LOG(1, "Write sample data: %s", filename);
12765 if (!(out = fopen(filename, "w")))
12766 ERRMSG("Cannot create file!");
12767
12768 /* Write header... */
12769 fprintf(out,
12770 "# $1 = time [s]\n"
12771 "# $2 = altitude [km]\n"
12772 "# $3 = longitude [deg]\n"
12773 "# $4 = latitude [deg]\n"
12774 "# $5 = surface area [km^2]\n"
12775 "# $6 = layer depth [km]\n"
12776 "# $7 = number of particles [1]\n"
12777 "# $8 = column density [kg/m^2]\n"
12778 "# $9 = volume mixing ratio [ppv]\n"
12779 "# $10 = observed BT index [K]\n\n");
12780
12781 /* Set latitude range, squared radius, and area... */
12782 dlat = DY2DEG(ctl->sample_dx);
12783 rmax2 = SQR(ctl->sample_dx);
12784 area = M_PI * rmax2;
12785 }
12786
12787 /* Set time interval for output... */
12788 const double t0 = t - 0.5 * ctl->dt_mod;
12789 const double t1 = t + 0.5 * ctl->dt_mod;
12790
12791 /* Loop over observations... */
12792 for (int i = 0; i < nobs; i++) {
12793
12794 /* Check time... */
12795 if (rt[i] < t0)
12796 continue;
12797 else if (rt[i] >= t1)
12798 break;
12799
12800 /* Calculate Cartesian coordinates... */
12801 double x0[3];
12802 geo2cart(0, rlon[i], rlat[i], x0);
12803
12804 /* Set pressure range... */
12805 const double rp = P(rz[i]);
12806 const double ptop = P(rz[i] + ctl->sample_dz);
12807 const double pbot = P(rz[i] - ctl->sample_dz);
12808
12809 /* Init... */
12810 double mass = 0;
12811 int np = 0;
12812
12813 /* Loop over air parcels... */
12814 //#pragma omp parallel for default(shared) reduction(+:mass,np)
12815 for (int ip = 0; ip < atm->np; ip++) {
12816
12817 /* Check time... */
12818 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12819 continue;
12820
12821 /* Check latitude... */
12822 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
12823 continue;
12824
12825 /* Check horizontal distance... */
12826 double x1[3];
12827 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
12828 if (DIST2(x0, x1) > rmax2)
12829 continue;
12830
12831 /* Check pressure... */
12832 if (ctl->sample_dz > 0)
12833 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
12834 continue;
12835
12836 /* Add mass... */
12837 if (ctl->qnt_m >= 0)
12838 mass +=
12839 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
12840 np++;
12841 }
12842
12843 /* Calculate column density... */
12844 const double cd = mass / (1e6 * area);
12845
12846 /* Calculate volume mixing ratio... */
12847 double vmr = 0;
12848 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
12849 if (mass > 0) {
12850
12851 /* Get temperature... */
12852 double temp;
12854 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
12855 rlon[i], rlat[i], &temp, ci, cw, 1);
12856
12857 /* Calculate volume mixing ratio... */
12858 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
12859 }
12860 } else
12861 vmr = NAN;
12862
12863 /* Write output... */
12864 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
12865 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
12866 }
12867
12868 /* Finalize...... */
12869 if (t == ctl->t_stop) {
12870
12871 /* Close output file... */
12872 fclose(out);
12873
12874 /* Free... */
12875 free(rt);
12876 free(rz);
12877 free(rlon);
12878 free(rlat);
12879 free(robs);
12880 }
12881}
12882
12883/*****************************************************************************/
12884
12886 const char *filename,
12887 const ctl_t *ctl,
12888 atm_t *atm,
12889 const double t) {
12890
12891 static FILE *out;
12892
12893 static double rmax2, x0[3], x1[3];
12894
12895 /* Set timer... */
12896 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
12897
12898 /* Init... */
12899 if (t == ctl->t_start) {
12900
12901 /* Write info... */
12902 LOG(1, "Write station data: %s", filename);
12903
12904 /* Create new file... */
12905 if (!(out = fopen(filename, "w")))
12906 ERRMSG("Cannot create file!");
12907
12908 /* Write header... */
12909 fprintf(out,
12910 "# $1 = time [s]\n"
12911 "# $2 = altitude [km]\n"
12912 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
12913 for (int iq = 0; iq < ctl->nq; iq++)
12914 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
12915 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
12916 fprintf(out, "\n");
12917
12918 /* Set geolocation and search radius... */
12919 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
12920 rmax2 = SQR(ctl->stat_r);
12921 }
12922
12923 /* Set time interval for output... */
12924 const double t0 = t - 0.5 * ctl->dt_mod;
12925 const double t1 = t + 0.5 * ctl->dt_mod;
12926
12927 /* Loop over air parcels... */
12928 for (int ip = 0; ip < atm->np; ip++) {
12929
12930 /* Check time... */
12931 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12932 continue;
12933
12934 /* Check time range for station output... */
12935 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
12936 continue;
12937
12938 /* Check station flag... */
12939 if (ctl->qnt_stat >= 0)
12940 if ((int) atm->q[ctl->qnt_stat][ip])
12941 continue;
12942
12943 /* Get Cartesian coordinates... */
12944 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
12945
12946 /* Check horizontal distance... */
12947 if (DIST2(x0, x1) > rmax2)
12948 continue;
12949
12950 /* Set station flag... */
12951 if (ctl->qnt_stat >= 0)
12952 atm->q[ctl->qnt_stat][ip] = 1;
12953
12954 /* Write data... */
12955 fprintf(out, "%.2f %g %g %g",
12956 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
12957 for (int iq = 0; iq < ctl->nq; iq++) {
12958 fprintf(out, " ");
12959 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
12960 }
12961 fprintf(out, "\n");
12962 }
12963
12964 /* Close file... */
12965 if (t == ctl->t_stop)
12966 fclose(out);
12967}
12968
12969/*****************************************************************************/
12970
12972 const char *filename,
12973 const ctl_t *ctl,
12974 const atm_t *atm,
12975 const double t) {
12976
12977 FILE *out;
12978
12979 /* Set timer... */
12980 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
12981
12982 /* Write info... */
12983 LOG(1, "Write VTK data: %s", filename);
12984
12985 /* Set time interval for output... */
12986 const double t0 = t - 0.5 * ctl->dt_mod;
12987 const double t1 = t + 0.5 * ctl->dt_mod;
12988
12989 /* Create file... */
12990 if (!(out = fopen(filename, "w")))
12991 ERRMSG("Cannot create file!");
12992
12993 /* Count data points... */
12994 int np = 0;
12995 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
12996 if (atm->time[ip] < t0 || atm->time[ip] > t1)
12997 continue;
12998 np++;
12999 }
13000
13001 /* Write header... */
13002 fprintf(out,
13003 "# vtk DataFile Version 3.0\n"
13004 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
13005
13006 /* Write point coordinates... */
13007 fprintf(out, "POINTS %d float\n", np);
13008 if (ctl->vtk_sphere) {
13009 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13010 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13011 continue;
13012 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
13013 + ctl->vtk_offset) / RE;
13014 const double coslat = cos(DEG2RAD(atm->lat[ip]));
13015 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
13016 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
13017 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
13018 fprintf(out, "%g %g %g\n", x, y, z);
13019 }
13020 } else
13021 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13022 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13023 continue;
13024 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
13025 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
13026 }
13027
13028 /* Write point data... */
13029 fprintf(out, "POINT_DATA %d\n", np);
13030 for (int iq = 0; iq < ctl->nq; iq++) {
13031 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
13032 ctl->qnt_name[iq]);
13033 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
13034 if (atm->time[ip] < t0 || atm->time[ip] > t1)
13035 continue;
13036 fprintf(out, "%g\n", atm->q[iq][ip]);
13037 }
13038 }
13039
13040 /* Close file... */
13041 fclose(out);
13042}
13043
13044/*****************************************************************************/
13045#ifdef DD
13046void dd_atm2particles(
13047 atm_t *atm,
13048 particle_t *particles,
13049 ctl_t *ctl,
13050 int *nparticles,
13051 cache_t *cache,
13052 int rank) {
13053
13054 SELECT_TIMER("DD_ATM2PARTICLES", "DD", NVTX_READ);
13055
13056 /* Select the particles that will be send... */
13057 int npart = *nparticles;
13058#pragma acc enter data create( nparticles, particles[:DD_NPART])
13059#pragma acc update device( nparticles)
13060#pragma acc parallel loop present( atm, ctl, particles, cache, nparticles)
13061 for (int ip = atm->np; ip < atm->np + *nparticles; ip++)
13062 if (((int) (atm->q[ctl->qnt_destination][ip]) != rank)
13063 && ((int) (atm->q[ctl->qnt_destination][ip]) >= 0)
13064 && ((int) atm->q[ctl->qnt_subdomain][ip] >= 0)) {
13065
13066 particles[ip - atm->np].time = atm->time[ip];
13067 particles[ip - atm->np].lon = atm->lon[ip];
13068 particles[ip - atm->np].lat = atm->lat[ip];
13069 particles[ip - atm->np].p = atm->p[ip];
13070
13071 for (int iq = 0; iq < ctl->nq; iq++)
13072 particles[ip - atm->np].q[iq] = atm->q[iq][ip];
13073
13074 atm->q[ctl->qnt_subdomain][ip] = -1;
13075 cache->dt[ip] = 0;
13076 }
13077#pragma acc update host( particles[:npart])
13078#pragma acc exit data delete( nparticles, particles)
13079
13080}
13081#endif
13082
13083/*****************************************************************************/
13084#ifdef DD
13085void dd_particles2atm(
13086 atm_t *atm,
13087 particle_t *particles,
13088 ctl_t *ctl,
13089 int *nparticles,
13090 cache_t *cache) {
13091
13092 SELECT_TIMER("DD_PARTICLES2ATM", "DD", NVTX_CPU);
13093
13094 int npart = *nparticles;
13095#pragma acc enter data create(nparticles, particles[:DD_NPART])
13096#pragma acc update device(particles[:npart], nparticles)
13097#pragma acc data present(atm, ctl, cache, particles, nparticles)
13098#pragma acc parallel loop
13099 for (int ip = atm->np; ip < atm->np + *nparticles; ip++) {
13100
13101 atm->time[ip] = particles[ip - atm->np].time;
13102 atm->lon[ip] = particles[ip - atm->np].lon;
13103 atm->lat[ip] = particles[ip - atm->np].lat;
13104 atm->p[ip] = particles[ip - atm->np].p;
13105
13106 for (int iq = 0; iq < ctl->nq; iq++)
13107 atm->q[iq][ip] = particles[ip - atm->np].q[iq];
13108
13109 cache->dt[ip] = ctl->dt_mod;
13110
13111 }
13112#pragma acc exit data delete(nparticles, particles)
13113
13114 /* Reset size... */
13115 atm->np += *nparticles;
13116#pragma acc update device(atm->np)
13117
13118 if (atm->np > NP)
13119 ERRMSG("Number of particles to high. Increase NP!");
13120
13121}
13122#endif
13123
13124/*****************************************************************************/
13125
13126#ifdef DD
13127void dd_register_MPI_type_particle(
13128 MPI_Datatype *MPI_Particle) {
13129 MPI_Datatype types[5] = { MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE,
13130 MPI_DOUBLE, MPI_DOUBLE
13131 };
13132 int blocklengths[5] = { 1, 1, 1, 1, NQ };
13133 MPI_Aint displacements[5] = { offsetof(particle_t, time),
13134 offsetof(particle_t, p),
13135 offsetof(particle_t, lon),
13136 offsetof(particle_t, lat),
13137 offsetof(particle_t, q)
13138 };
13139 MPI_Type_create_struct(5, blocklengths, displacements, types, MPI_Particle);
13140 MPI_Type_commit(MPI_Particle);
13141}
13142#endif
13143
13144/*****************************************************************************/
13145
13146#ifdef DD
13147void dd_get_rect_neighbour(
13148 const ctl_t ctl,
13149 mpi_info_t *mpi_info) {
13150
13151 SELECT_TIMER("DD_GET_RECT_NEIGHBOUR", "DD", NVTX_GPU);
13152
13153 if (mpi_info->rank + 1 == mpi_info->size) {
13154
13155 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional;
13156 mpi_info->neighbours[1] = DD_SPOLE;
13157 mpi_info->neighbours[2] =
13158 mpi_info->rank - ctl.dd_subdomains_meridional - 1;
13159
13160 mpi_info->neighbours[3] =
13161 (mpi_info->rank + 1 + ctl.dd_subdomains_meridional) % mpi_info->size -
13162 1;
13163 mpi_info->neighbours[4] = DD_SPOLE;
13164 mpi_info->neighbours[5] =
13165 (mpi_info->rank + ctl.dd_subdomains_meridional) % mpi_info->size - 1;
13166
13167 mpi_info->neighbours[6] = mpi_info->rank - 1;
13168 mpi_info->neighbours[7] = DD_SPOLE;
13169
13170 } else if (mpi_info->rank ==
13172
13173 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional;
13174 mpi_info->neighbours[1] =
13175 mpi_info->rank - ctl.dd_subdomains_meridional + 1;
13176 mpi_info->neighbours[2] = DD_NPOLE;
13177
13178 mpi_info->neighbours[3] =
13179 (mpi_info->rank + 1 + ctl.dd_subdomains_meridional) % mpi_info->size -
13180 1;
13181 mpi_info->neighbours[4] =
13182 (mpi_info->rank + 2 + ctl.dd_subdomains_meridional) % mpi_info->size -
13183 1;
13184 mpi_info->neighbours[5] = DD_NPOLE;
13185
13186 mpi_info->neighbours[6] = DD_NPOLE;
13187 mpi_info->neighbours[7] = mpi_info->rank + 1;
13188
13189 } else if (mpi_info->rank == 0) {
13190
13191 mpi_info->neighbours[0] =
13192 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank;
13193 mpi_info->neighbours[1] =
13194 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank + 1;
13195 mpi_info->neighbours[2] = DD_NPOLE;
13196
13197 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional;
13198 mpi_info->neighbours[4] =
13199 mpi_info->rank + 1 + ctl.dd_subdomains_meridional;
13200 mpi_info->neighbours[5] = DD_NPOLE;
13201
13202 mpi_info->neighbours[6] = DD_NPOLE;
13203 mpi_info->neighbours[7] = mpi_info->rank + 1;
13204
13205 } else if (mpi_info->rank + 1 == ctl.dd_subdomains_meridional) {
13206
13207 mpi_info->neighbours[0] =
13208 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank;
13209 mpi_info->neighbours[1] = DD_SPOLE;
13210 mpi_info->neighbours[2] =
13211 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank - 1;
13212
13213 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional;
13214 mpi_info->neighbours[4] = DD_SPOLE;
13215 mpi_info->neighbours[5] =
13216 mpi_info->rank + ctl.dd_subdomains_meridional - 1;
13217
13218 mpi_info->neighbours[6] = mpi_info->rank - 1;
13219 mpi_info->neighbours[7] = DD_SPOLE;
13220
13221 } else if ((mpi_info->rank + 1) % ctl.dd_subdomains_meridional == 1) {
13222
13223 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional;
13224 mpi_info->neighbours[1] =
13225 mpi_info->rank + 1 - ctl.dd_subdomains_meridional;
13226 mpi_info->neighbours[2] = DD_NPOLE;
13227
13228 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional;
13229 mpi_info->neighbours[4] =
13230 mpi_info->rank + 1 + ctl.dd_subdomains_meridional;
13231 mpi_info->neighbours[5] = DD_NPOLE;
13232
13233 mpi_info->neighbours[6] = DD_NPOLE;
13234 mpi_info->neighbours[7] = mpi_info->rank + 1;
13235
13236 } else if ((mpi_info->rank + 1) % ctl.dd_subdomains_meridional == 0) {
13237
13238 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional;
13239 mpi_info->neighbours[1] = DD_SPOLE;
13240 mpi_info->neighbours[2] =
13241 mpi_info->rank - ctl.dd_subdomains_meridional - 1;
13242
13243 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional;
13244 mpi_info->neighbours[4] = DD_SPOLE;
13245 mpi_info->neighbours[5] =
13246 mpi_info->rank + ctl.dd_subdomains_meridional - 1;
13247
13248 mpi_info->neighbours[6] = mpi_info->rank - 1;
13249 mpi_info->neighbours[7] = DD_SPOLE;
13250
13251 } else if (mpi_info->rank + 1 <= ctl.dd_subdomains_meridional) {
13252
13253 mpi_info->neighbours[0] =
13254 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank;
13255 mpi_info->neighbours[1] =
13256 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank + 1;
13257 mpi_info->neighbours[2] =
13258 mpi_info->size - ctl.dd_subdomains_meridional + mpi_info->rank - 1;
13259
13260 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional;
13261 mpi_info->neighbours[4] =
13262 mpi_info->rank + ctl.dd_subdomains_meridional + 1;
13263 mpi_info->neighbours[5] =
13264 mpi_info->rank + ctl.dd_subdomains_meridional - 1;
13265
13266 mpi_info->neighbours[6] = mpi_info->rank - 1;
13267 mpi_info->neighbours[7] = mpi_info->rank + 1;
13268
13269 } else if (mpi_info->rank + 1 >
13270 mpi_info->size - ctl.dd_subdomains_meridional) {
13271
13272 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional;
13273 mpi_info->neighbours[1] =
13274 mpi_info->rank - ctl.dd_subdomains_meridional + 1;
13275 mpi_info->neighbours[2] =
13276 mpi_info->rank - ctl.dd_subdomains_meridional - 1;
13277
13278 mpi_info->neighbours[3] =
13279 (mpi_info->rank + 1 + ctl.dd_subdomains_meridional) % mpi_info->size -
13280 1;
13281 mpi_info->neighbours[4] =
13282 (mpi_info->rank + 2 + ctl.dd_subdomains_meridional) % mpi_info->size -
13283 1;
13284 mpi_info->neighbours[5] =
13285 (mpi_info->rank + ctl.dd_subdomains_meridional) % mpi_info->size - 1;
13286
13287 mpi_info->neighbours[6] = mpi_info->rank - 1;
13288 mpi_info->neighbours[7] = mpi_info->rank + 1;
13289
13290 } else {
13291
13292 mpi_info->neighbours[0] = mpi_info->rank - ctl.dd_subdomains_meridional; // left...
13293 mpi_info->neighbours[1] = mpi_info->rank - ctl.dd_subdomains_meridional + 1; // lower left..
13294 mpi_info->neighbours[2] = mpi_info->rank - ctl.dd_subdomains_meridional - 1; // upper left..
13295
13296 mpi_info->neighbours[3] = mpi_info->rank + ctl.dd_subdomains_meridional; // right...
13297 mpi_info->neighbours[4] = mpi_info->rank + ctl.dd_subdomains_meridional + 1; // lower right...
13298 mpi_info->neighbours[5] = mpi_info->rank + ctl.dd_subdomains_meridional - 1; // upper right...
13299
13300 mpi_info->neighbours[6] = mpi_info->rank - 1; // upper
13301 mpi_info->neighbours[7] = mpi_info->rank + 1; // lower
13302
13303 }
13304}
13305#endif
13306
13307/*****************************************************************************/
13308
13309#ifdef DD
13310void dd_communicate_particles(
13311 particle_t *particles,
13312 int *nparticles,
13313 MPI_Datatype MPI_Particle,
13314 int *neighbours,
13315 int nneighbours,
13316 ctl_t ctl) {
13317
13318 /* Initialize the buffers... */
13319 int *nbs;
13320 int *nbr;
13321 ALLOC(nbs, int,
13322 nneighbours);
13323 ALLOC(nbr, int,
13324 nneighbours);
13325 particle_t *send_buffers[DD_NNMAX] = { NULL };
13326 particle_t *recieve_buffers[DD_NNMAX] = { NULL };
13327
13328 /* Get MPI rank... */
13329 int rank;
13330 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
13331
13332 /* Infos for MPI async... */
13333 // TODO: Make this requests variable from number of neighbours...
13334 MPI_Request requests_snd_nbr[8] =
13335 { MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL,
13336 MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL
13337 };
13338 MPI_Request requests_rcv_nbr[8] =
13339 { MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL,
13340 MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL
13341 };
13342 MPI_Request requests_snd_part[8] =
13343 { MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL,
13344 MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL
13345 };
13346 MPI_Request requests_rcv_part[8] =
13347 { MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL,
13348 MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL
13349 };
13350 MPI_Status states[8];
13351
13352 /* Sending... */
13353 for (int idest = 0; idest < nneighbours; idest++) {
13354
13355 /* Ignore poles... */
13356 if (neighbours[idest] < 0)
13357 continue;
13358
13359 SELECT_TIMER("DD_COUNT_NUMBER", "DD", NVTX_CPU);
13360 /* Count number of particles in particle array that will be send... */
13361 int help_sum = 0;
13362 for (int ip = 0; ip < *nparticles; ip++)
13363 if ((int) particles[ip].q[ctl.qnt_destination] == neighbours[idest])
13364 help_sum++;
13365 nbs[idest] = help_sum;
13366
13367 SELECT_TIMER("DD_SEND_NUMBER", "DD", NVTX_CPU);
13368 /* Send buffer sizes... */
13369 MPI_Isend(&nbs[idest], 1, MPI_INT,
13370 neighbours[idest], 0, MPI_COMM_WORLD, &requests_snd_nbr[idest]);
13371
13372 /* Don't send empty signals... */
13373 if (nbs[idest] == 0)
13374 continue;
13375
13376 SELECT_TIMER("DD_PREP_BUFFER", "DD", NVTX_CPU);
13377 /* Allocate buffer for sending... */
13378 ALLOC(send_buffers[idest], particle_t, nbs[idest]);
13379
13380 /* Fill the send buffer in a sorted way... */
13381 int ibs = 0;
13382 for (int ip = 0; ip < *nparticles; ip++) {
13383 if ((int) particles[ip].q[ctl.qnt_destination] == neighbours[idest]) {
13384 memcpy(&send_buffers[idest][ibs], &particles[ip], sizeof(particle_t));
13385 ibs++;
13386 }
13387
13388 if (ibs == nbs[idest])
13389 break;
13390
13391 }
13392
13393 SELECT_TIMER("DD_SEND_PARTICLES", "DD", NVTX_CPU);
13394 /* Send the buffer... */
13395 MPI_Isend(send_buffers[idest], nbs[idest], MPI_Particle,
13396 neighbours[idest], 1, MPI_COMM_WORLD,
13397 &requests_snd_part[idest]);
13398 }
13399
13400 SELECT_TIMER("DD_RECIEVE_NUMBERS", "DD", NVTX_CPU);
13401
13402 /* Recieving... */
13403 for (int isourc = 0; isourc < nneighbours; isourc++) {
13404
13405 /* Ignore poles... */
13406 if (neighbours[isourc] < 0) {
13407 requests_rcv_nbr[isourc] = MPI_REQUEST_NULL;
13408 continue;
13409 }
13410
13411 /* Recieve buffer sizes... */
13412 MPI_Irecv(&nbr[isourc], 1, MPI_INT, neighbours[isourc], 0, MPI_COMM_WORLD,
13413 &requests_rcv_nbr[isourc]);
13414
13415 }
13416
13417 /* Wait for all particle numbers to be recieved... */
13418 MPI_Waitall(nneighbours, requests_rcv_nbr, states);
13419
13420 SELECT_TIMER("DD_RECIEVE_PARTICLES", "DD", NVTX_CPU);
13421 for (int isourc = 0; isourc < nneighbours; isourc++) {
13422
13423 /* Ignore poles, and neighbours without signal... */
13424 if ((neighbours[isourc] < 0) || (nbr[isourc] == 0)) {
13425 requests_rcv_part[isourc] = MPI_REQUEST_NULL;
13426 continue;
13427 }
13428
13429 /* Allocate buffer for recieving... */
13430 ALLOC(recieve_buffers[isourc], particle_t, nbr[isourc]);
13431
13432 MPI_Irecv(recieve_buffers[isourc], nbr[isourc], MPI_Particle,
13433 neighbours[isourc], 1, MPI_COMM_WORLD,
13434 &requests_rcv_part[isourc]);
13435
13436 }
13437
13438 /* Wait for all particles to be recieved... */
13439 MPI_Waitall(nneighbours, requests_rcv_part, states);
13440
13441 SELECT_TIMER("DD_EMPTY_BUFFER", "DD", NVTX_CPU);
13442
13443 /* Start position for different buffer ranges... */
13444 int api = 0;
13445
13446 /* Putting buffer into particle array... */
13447 for (int isourc = 0; isourc < nneighbours; isourc++) {
13448
13449 /* Ignore poles... */
13450 if (neighbours[isourc] < 0)
13451 continue;
13452
13453 /* Getting particles from buffer... */
13454 for (int ip = 0; ip < nbr[isourc]; ip++) {
13455 memcpy(&particles[ip + api], &recieve_buffers[isourc][ip],
13456 sizeof(particle_t));
13457 particles[ip + api].q[ctl.qnt_destination] = rank;
13458 particles[ip + api].q[ctl.qnt_subdomain] = rank;
13459
13460 }
13461 api += nbr[isourc];
13462 }
13463
13464 /* Set number of recieved particles... */
13465 *nparticles = api;
13466
13467 SELECT_TIMER("DD_FREE_BUFFER", "DD", NVTX_CPU);
13468
13469 /* Wait for all communication to be finished... */
13470 MPI_Waitall(nneighbours, requests_snd_part, states);
13471 MPI_Waitall(nneighbours, requests_snd_nbr, states);
13472
13473 /* Free buffers and buffersizes... */
13474 for (int i = 0; i < nneighbours; i++) {
13475
13476 if ((send_buffers[i] != NULL) && (nbs[i] != 0)) {
13477 free(send_buffers[i]);
13478 send_buffers[i] = NULL;
13479 }
13480
13481 if ((recieve_buffers[i] != NULL) && (nbr[i] != 0)) {
13482 free(recieve_buffers[i]);
13483 recieve_buffers[i] = NULL;
13484 }
13485
13486 }
13487
13488 free(nbs);
13489 free(nbr);
13490
13491}
13492#endif
13493
13494/*****************************************************************************/
13495#ifdef DD
13496void dd_assign_rect_subdomains_atm(
13497 atm_t *atm,
13498 met_t *met,
13499 ctl_t *ctl,
13500 mpi_info_t *mpi_info,
13501 int init) {
13502
13503 SELECT_TIMER("DD_ASSIGN_RECT_SUBDOMAINS", "DD", NVTX_GPU);
13504
13505 if (init) {
13506#pragma acc enter data create(mpi_info)
13507#pragma acc update device(mpi_info->rank)
13508#pragma acc data present(atm, ctl, mpi_info, met)
13509#pragma acc parallel loop independent gang vector
13510 for (int ip = 0; ip < atm->np; ip++) {
13511
13512 double lont = atm->lon[ip];
13513
13514 if (lont < 0)
13515 lont += 360;
13516
13517 if (lont >= met->subdomain_lon_min && lont < met->subdomain_lon_max
13518 && atm->lat[ip] >= met->subdomain_lat_min
13519 && atm->lat[ip] < met->subdomain_lat_max) {
13520 atm->q[ctl->qnt_subdomain][ip] = mpi_info->rank;
13521 atm->q[ctl->qnt_destination][ip] = mpi_info->rank;
13522 } else {
13523 atm->q[ctl->qnt_subdomain][ip] = -1;
13524 atm->q[ctl->qnt_destination][ip] = -1;
13525 }
13526 }
13527#pragma acc exit data delete(mpi_info)
13528 } else {
13529
13530 /* Classify air parcels into subdomain... */
13531#pragma acc enter data create(mpi_info)
13532#pragma acc update device(mpi_info->neighbours[:DD_NNMAX], mpi_info->rank, mpi_info->size)
13533#pragma acc data present(atm, met, ctl, mpi_info)
13534#pragma acc parallel loop independent gang vector
13535 for (int ip = 0; ip < atm->np; ip++) {
13536
13537 /* Skip empty places in the particle array... */
13538 if ((int) atm->q[ctl->qnt_subdomain][ip] == -1)
13539 continue;
13540
13541 double lont = atm->lon[ip];
13542 double latt = atm->lat[ip];
13543
13544 double lon_max = met->subdomain_lon_max;
13545 double lon_min = met->subdomain_lon_min;
13546 double lat_max = met->subdomain_lat_max;
13547 double lat_min = met->subdomain_lat_min;
13548
13549 if (lont < 0)
13550 lont += 360;
13551
13552 bool left = (mpi_info->rank <= ctl->dd_subdomains_meridional - 1);
13553 bool right =
13554 (mpi_info->rank >= mpi_info->size - ctl->dd_subdomains_meridional);
13555
13556 bool bound = 0;
13557 if (left)
13558 bound = (lont - lon_max > 90) ? 1 : 0;
13559 if (right)
13560 bound = (lon_min - lont > 90) ? 1 : 0;
13561
13562 if (!bound) {
13563 if ((lont >= lon_max) && (latt >= lat_max)) {
13564 // Upper right...
13565 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[5];
13566 } else if ((lont >= lon_max) && (latt <= lat_min)) {
13567 // Lower right...
13568 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[4];
13569 } else if ((lont <= lon_min) && (latt >= lat_max)) {
13570 // Upper left...
13571 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[2];
13572 } else if ((lont <= lon_min) && (latt <= lat_min)) {
13573 // Lower left...
13574 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[1];
13575 } else if (lont >= lon_max) {
13576 // Right...
13577 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[3];
13578 } else if (lont <= lon_min) {
13579 // Left...
13580 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[0];
13581 } else if (latt <= lat_min) {
13582 // Down...
13583 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[7];
13584 } else if (latt >= lat_max) {
13585 // Up...
13586 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[6];
13587 } else {
13588 // Within...
13589 atm->q[ctl->qnt_destination][ip] = mpi_info->rank;
13590 }
13591 } else {
13592 if ((lont >= lon_max) && (latt >= lat_max)) {
13593 // Upper right...
13594 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[2];
13595 } else if ((lont >= lon_max) && (latt <= lat_min)) {
13596 // Lower right...
13597 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[1];
13598 } else if ((lont <= lon_min) && (latt >= lat_max)) {
13599 // Upper left...
13600 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[5];
13601 } else if ((lont <= lon_min) && (latt <= lat_min)) {
13602 // Lower left...
13603 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[4];
13604 } else if (lont >= lon_max) {
13605 // Right...
13606 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[0];
13607 } else if (lont <= lon_min) {
13608 // Left...
13609 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[3];
13610 } else if (latt <= lat_min) {
13611 // Down...
13612 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[7];
13613 } else if (latt >= lat_max) {
13614 // Up...
13615 atm->q[ctl->qnt_destination][ip] = mpi_info->neighbours[6];
13616 } else {
13617 // Within...
13618 atm->q[ctl->qnt_destination][ip] = mpi_info->rank;
13619 }
13620 }
13621 }
13622#pragma acc exit data delete(mpi_info)
13623 }
13624}
13625#endif
13626
13627/*****************************************************************************/
13628
13629#ifdef DD
13630void dd_init(
13631 ctl_t *ctl,
13632 mpi_info_t *mpi_info,
13633 atm_t *atm,
13634 met_t **met,
13635 double t,
13636 int *dd_init_flg) {
13637
13638 /* Check if enough tasks are requested... */
13639 if (mpi_info->size !=
13641 ERRMSG("The number of tasks and subdomains is not identical.");
13642
13643 /* Register the MPI_Particle data type... */
13644 dd_register_MPI_type_particle(&mpi_info->MPI_Particle);
13645
13646 /* Define grid neighbours ... */
13647 dd_get_rect_neighbour(*ctl, mpi_info);
13648
13649 /* Check if particles are in subdomain... */
13650 dd_assign_rect_subdomains_atm(atm, *met, ctl, mpi_info, 1);
13651
13652 *dd_init_flg = 1;
13653}
13654#endif
13655
13656/*****************************************************************************/
13657#ifdef DD
13658void module_dd(
13659 ctl_t *ctl,
13660 atm_t *atm,
13661 cache_t *cache,
13662 mpi_info_t *mpi_info,
13663 met_t **met) {
13664
13665 /* Initialize particles locally... */
13666 int nparticles = 0;
13667 particle_t *particles;
13668 ALLOC(particles, particle_t, DD_NPART);
13669
13670 /* Assign particles to new subdomains... */
13671 dd_assign_rect_subdomains_atm(atm, *met, ctl, mpi_info, 0);
13672
13673 /* Sorting particles according to location and target rank... */
13674 dd_sort(ctl, *met, atm, &nparticles, &mpi_info->rank);
13675
13676 /* Transform from struct of array to array of struct... */
13677 dd_atm2particles(atm, particles, ctl, &nparticles, cache, mpi_info->rank);
13678
13679 /********************* CPU region start ***********************************/
13680
13681 /* Perform the communication... */
13682 dd_communicate_particles(particles, &nparticles, mpi_info->MPI_Particle,
13683 mpi_info->neighbours, ctl->dd_nbr_neighbours,
13684 *ctl);
13685
13686 /********************* CPU region end *************************************/
13687
13688 /* Transform from array of struct to struct of array... */
13689 dd_particles2atm(atm, particles, ctl, &nparticles, cache);
13690
13691 /* Free local particle array... */
13692 free(particles);
13693
13694}
13695#endif
13696
13697/*****************************************************************************/
13698#ifdef DD
13699void dd_sort(
13700 const ctl_t *ctl,
13701 met_t *met0,
13702 atm_t *atm,
13703 int *nparticles,
13704 int *rank) {
13705
13706 /* Set timer... */
13707 SELECT_TIMER("DD_SORT", "DD", NVTX_GPU);
13708
13709 /* Allocate... */
13710 const int np = atm->np;
13711 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
13712 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
13713 double amax = (met0->nx * met0->ny + met0->ny) * met0->np + met0->np;
13714
13715#ifdef _OPENACC
13716#pragma acc enter data create(a[0:np],p[0:np],amax, rank)
13717#pragma acc update device(rank, amax)
13718#pragma acc data present(ctl,met0,atm,a,p,amax,rank)
13719#endif
13720
13721 /* Get box index... */
13722#ifdef _OPENACC
13723#pragma acc parallel loop independent gang vector
13724#else
13725#pragma omp parallel for default(shared)
13726#endif
13727 for (int ip = 0; ip < np; ip++) {
13728 if ((int) atm->q[ctl->qnt_subdomain][ip] != -1) {
13729 if ((int) atm->q[ctl->qnt_destination][ip] == *rank)
13730 a[ip] =
13731 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) *
13732 met0->ny + locate_irr(met0->lat, met0->ny, atm->lat[ip]))
13733 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
13734 else
13735 a[ip] = amax + 1;
13736 } else {
13737 a[ip] = amax + 2;
13738 }
13739 p[ip] = ip;
13740 }
13741
13742 /* Sorting... */
13743#ifdef _OPENACC
13744#pragma acc host_data use_device(a,p)
13745#endif
13746#ifdef THRUST
13747 thrustSortWrapper(a, np, p);
13748#else
13749 ERRMSG("MPTRAC was compiled without Thrust library!");
13750#endif
13751
13752 /* Sort data... */
13753 module_sort_help(atm->time, p, np);
13754 module_sort_help(atm->p, p, np);
13755 module_sort_help(atm->lon, p, np);
13756 module_sort_help(atm->lat, p, np);
13757 for (int iq = 0; iq < ctl->nq; iq++)
13758 module_sort_help(atm->q[iq], p, np);
13759
13760
13761 /* Reset the size... */
13762 int npt = 0;
13763#pragma acc parallel loop reduction(+:npt) present(atm, rank, ctl)
13764 for (int ip = 0; ip < np; ip++)
13765 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
13766 && ((int) atm->q[ctl->qnt_destination][ip] == *rank))
13767 npt++;
13768
13769 /* Count number of particles to send... */
13770 int nparticlest = 0;
13771#pragma acc parallel loop reduction(+:nparticlest) present(atm, rank, ctl)
13772 for (int ip = npt; ip < np; ip++)
13773 if (((int) atm->q[ctl->qnt_subdomain][ip] != -1)
13774 && ((int) atm->q[ctl->qnt_destination][ip] != *rank))
13775 nparticlest++;
13776
13777 /* Reset sizes... */
13778 *nparticles = nparticlest;
13779 atm->np = npt;
13780#pragma acc update device(atm->np)
13781
13782 if (*nparticles > DD_NPART)
13783 ERRMSG
13784 ("Number of particles to send and recieve to small. Increase DD_NPART!");
13785
13786 /* Free... */
13787#ifdef _OPENACC
13788#pragma acc exit data delete(a,p,amax, rank)
13789#endif
13790 free(a);
13791 free(p);
13792
13793}
13794#endif
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:7148
void read_met_nc_surface(const int ncid, const ctl_t *ctl, met_t *met)
Reads surface meteorological data from a netCDF file and stores it in the meteorological data structu...
Definition: mptrac.c:9522
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:5828
void day2doy(const int year, const int mon, const int day, int *doy)
Get day of year from date.
Definition: mptrac.c:906
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:7108
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:11051
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:12437
void mptrac_alloc(ctl_t **ctl, cache_t **cache, clim_t **clim, met_t **met0, met_t **met1, atm_t **atm)
Allocates and initializes memory resources for MPTRAC.
Definition: mptrac.c:4212
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:10050
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:12197
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:10394
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:2094
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:3934
int mptrac_read_met(const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met)
Reads meteorological data from a file, supporting multiple formats and MPI broadcasting.
Definition: mptrac.c:5445
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:3260
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:6256
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:6947
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:2647
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:10567
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:1468
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:6223
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:9658
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:7004
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, float dest[EX][EY], const float scl, const int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:8858
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:10222
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:10438
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:2532
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:2055
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:1101
void mptrac_get_met(ctl_t *ctl, clim_t *clim, const double t, met_t **met0, met_t **met1)
Retrieves meteorological data for the specified time.
Definition: mptrac.c:4301
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:8742
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:6375
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:9795
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:3976
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:11534
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:3365
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:401
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:3436
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:6347
void read_met_ml2pl(const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname)
Reads global meteorological information from a grib file.
Definition: mptrac.c:8700
double clim_tropo(const clim_t *clim, const double t, const double lat)
Calculates the tropopause pressure based on climatological data.
Definition: mptrac.c:200
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:10466
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:6717
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:1991
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:3085
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:1781
void intpol_met_4d_coord(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:1171
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:11822
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:5716
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:10709
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:4422
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:1526
void intpol_met_space_3d_ml(const met_t *met, float zs[EX][EY][EP], float array[EX][EY][EP], const double z, const double lon, const double lat, double *var)
Interpolates meteorological data in 3D space.
Definition: mptrac.c:1401
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:955
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:4077
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:664
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:6019
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:10600
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:2370
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:149
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:6429
void read_met_nc_grid(const char *filename, const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological grid information from a NetCDF file.
Definition: mptrac.c:9174
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:3809
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:10740
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:10866
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:1343
void intpol_met_time_3d_ml(const met_t *met0, float zs0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float zs1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double p, const double lon, const double lat, double *var)
Interpolates meteorological data in both space and time.
Definition: mptrac.c:1555
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:2574
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:6528
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:2274
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:10495
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:2247
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:3898
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:10647
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:1613
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, float dest[EX][EY][EP], const float scl)
Reads a 3-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:9022
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:6746
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:2021
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:10808
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:12496
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:4512
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:10843
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:12273
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:3673
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:4441
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:5772
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:5928
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:10021
void mptrac_free(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Frees memory resources allocated for MPTRAC.
Definition: mptrac.c:4269
void clim_tropo_init(clim_t *clim)
Initializes the tropopause data in the climatology structure.
Definition: mptrac.c:228
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:3704
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:1012
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:12885
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
double sza_calc(const double sec, const double lon, const double lat)
Calculates the solar zenith angle.
Definition: mptrac.c:10668
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:925
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:1580
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:3622
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:116
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:2074
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:12168
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:9915
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:6107
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:1077
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:2686
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:3838
int read_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a NetCDF file and processes it.
Definition: mptrac.c:8827
double clim_ts(const clim_ts_t *ts, const double t)
Interpolates a time series of climatological variables.
Definition: mptrac.c:383
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:1704
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:6569
void mptrac_run_timestep(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t **met0, met_t **met1, atm_t *atm, double t)
Executes a single timestep of the MPTRAC model simulation.
Definition: mptrac.c:5571
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:10998
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:2888
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:6163
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:12971
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:4007
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:4572
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:9856
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:3003
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:11926
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:6043
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:2763
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:12466
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:3155
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:3538
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:994
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:1737
void read_met_nc_levels(const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological variables at different vertical levels from a NetCDF file.
Definition: mptrac.c:9308
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:6065
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:1144
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:12723
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:11631
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:2940
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:12056
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:10948
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:6832
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:5888
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:1763
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:11258
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:11209
MPTRAC library declarations.
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1430
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:309
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:249
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1917
#define DD_NPOLE
Constants indicating the North pole [-].
Definition: mptrac.h:264
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:459
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1472
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:224
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:184
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:219
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:229
#define METVAR
Number of 3-D meteorological variables.
Definition: mptrac.h:314
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:334
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:865
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1577
#define H0
Scale height [km].
Definition: mptrac.h:204
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1410
int read_met_nc_dd(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a NetCDF file and processes it.
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1200
int read_met_nc_3d_dd(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const ctl_t *ctl, const met_t *met, float dest[EX][EY][EP], const float scl)
Reads a 3-dimensional meteorological variable from a NetCDF file.
#define DD_SPOLE
Constants indicating the South pole [-].
Definition: mptrac.h:270
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:1038
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1214
#define ECC_READ_3D(variable, level, target, scaling_factor, found_flag)
Writes 3D data from a grib message into the met struct.
Definition: mptrac.h:800
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:244
#define EP_GLOB
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:294
#define KARMAN
Karman's constant.
Definition: mptrac.h:214
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:880
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:1185
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:2102
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1371
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 int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using a custom multiscale compression algorithm.
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:289
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:1742
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:911
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:339
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:344
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:440
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:1939
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1502
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:209
#define EY_GLOB
Maximum number of global latitudes for meteo data.
Definition: mptrac.h:304
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:199
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:359
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:324
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:845
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:593
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:529
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:284
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:194
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1550
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1842
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:254
#define NORM(a)
Compute the norm (magnitude) of a vector.
Definition: mptrac.h:1445
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:1721
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1818
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1892
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1970
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1871
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:630
void dd_atm2particles(atm_t *atm, particle_t *particles, ctl_t *ctl, int *nparticles, cache_t *cache, int rank)
Converts atmospheric data to particle data.
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:2069
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:1989
void read_met_nc_grid_dd(const char *filename, const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological grid data from NetCDF files with domain decomposition.
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1654
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:984
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:417
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1698
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:374
void read_met_nc_surface_dd(const int ncid, const ctl_t *ctl, met_t *met)
Reads and processes surface meteorological data from NetCDF files with domain decomposition.
#define ECC_READ_2D(variable, target, scaling_factor, found_flag)
Writes 2-D data from a grib message into the met struct.
Definition: mptrac.h:776
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:546
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:234
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1755
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1594
#define NC_INQ_DIM(dimname, ptr, min, max)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1301
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:319
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:2146
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:2182
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:894
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1624
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1348
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:349
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:2032
void thrustSortWrapper(double *__restrict__ c, int n, int *__restrict__ index)
Wrapper to Thrust sorting function.
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1243
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1793
int read_met_nc_2d_dd(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, float dest[EX][EY], const float scl, const int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
void read_met_nc_levels_dd(const int ncid, const ctl_t *ctl, met_t *met)
Reads and processes meteorological level data from NetCDF files with domain decomposition.
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:484
#define EX_GLOB
Maximum number of global longitudes for meteo data.
Definition: mptrac.h:299
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:329
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1273
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:279
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1526
#define DD_NPART
Maximum number of particles to send and recieve.
Definition: mptrac.h:379
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1679
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:354
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1324
#define ECC(cmd)
Execute a ECCODES command and check for errors.
Definition: mptrac.h:757
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:1057
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:662
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:508
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:189
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:364
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:611
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:1084
#define DD_NNMAX
Maximum number of neighbours to communicate with.
Definition: mptrac.h:384
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:827
Air parcel data.
Definition: mptrac.h:3371
double time[NP]
Time [s].
Definition: mptrac.h:3377
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3386
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3383
int np
Number of air parcels.
Definition: mptrac.h:3374
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3389
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3380
Cache data structure.
Definition: mptrac.h:3449
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3470
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3458
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3461
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3455
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3467
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3464
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3452
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3481
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3487
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3496
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3517
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3493
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3511
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3514
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3508
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3502
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3523
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3526
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3505
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3520
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3499
int np
Number of pressure levels.
Definition: mptrac.h:3484
int no3c
Number of total ozone columns.
Definition: mptrac.h:3490
Climatological data.
Definition: mptrac.h:3589
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3631
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3607
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3619
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3610
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3592
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3637
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3625
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3628
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3622
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3601
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3616
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3595
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3613
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3604
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3598
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3634
Climatological data in the form of time series.
Definition: mptrac.h:3537
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3546
double time[CTS]
Time [s].
Definition: mptrac.h:3543
int ntime
Number of timesteps.
Definition: mptrac.h:3540
Climatological data in the form of zonal means.
Definition: mptrac.h:3557
double time[CT]
Time [s].
Definition: mptrac.h:3569
int np
Number of pressure levels.
Definition: mptrac.h:3566
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3575
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3578
int ntime
Number of timesteps.
Definition: mptrac.h:3560
int nlat
Number of latitudes.
Definition: mptrac.h:3563
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3572
Control parameters.
Definition: mptrac.h:2356
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3239
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2468
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3200
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:3167
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2618
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:3088
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2696
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2501
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:3176
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2950
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2447
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2642
int dd_halos_size
Size of halos given in grid-points.
Definition: mptrac.h:3359
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:3128
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:3013
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:3037
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2375
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2387
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2651
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2396
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2480
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:3170
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2489
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2989
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2938
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:3191
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2456
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3317
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2998
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2849
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:3010
double stat_r
Search radius around station [km].
Definition: mptrac.h:3323
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:3082
int met_zstd_level
ZSTD compression level (from -5 to 22).
Definition: mptrac.h:2705
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3194
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3347
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:3034
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2817
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2477
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:3052
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2902
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2630
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2739
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2555
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3266
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3242
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2660
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2856
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2636
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2769
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2836
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2519
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2585
char species[LEN]
Species.
Definition: mptrac.h:2947
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:3185
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3197
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2884
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2814
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2471
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2893
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3227
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3245
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:3141
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2911
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3257
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2402
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2546
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2742
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2498
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3248
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2525
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2833
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3302
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2579
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2679
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2971
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:3055
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2805
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3218
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2730
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2878
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2390
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2423
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2567
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2926
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3329
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:3161
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2875
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3263
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:3188
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2429
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:3061
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3233
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2552
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:3043
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2944
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2537
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2802
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2775
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2399
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2866
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3269
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2853
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2932
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2405
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3272
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:3164
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2811
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:3173
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2772
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:3046
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2890
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2754
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2757
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3215
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2733
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3275
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2462
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2917
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2827
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3281
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2384
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2824
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2393
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2842
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:3001
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2588
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2522
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:3182
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3326
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:3064
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2974
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2959
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:3100
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:3007
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2543
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:3146
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2793
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:3073
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:3158
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:3109
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2420
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2411
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2615
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3335
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2666
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2908
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3305
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2513
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3212
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2693
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2441
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2561
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2760
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2923
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2820
int met_dx
Stride for longitudes.
Definition: mptrac.h:2763
int qnt_destination
Quantity array index for destination subdomain in domain decomposition.
Definition: mptrac.h:2657
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:3022
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2682
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2573
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2968
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:3076
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2669
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2869
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2603
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2597
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2444
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3344
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2459
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2540
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2920
double met_zfp_tol[METVAR]
ZFP compression tolerance.
Definition: mptrac.h:2711
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2839
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2516
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2372
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2621
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2790
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:3058
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2465
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3290
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2564
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2453
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3311
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2956
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3155
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3230
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2748
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2408
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2724
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3251
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2645
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2639
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2366
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:3125
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:3025
int nens
Number of ensembles.
Definition: mptrac.h:3203
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2432
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2492
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2859
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3278
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2796
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2450
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:3134
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:3070
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2570
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2899
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3206
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:3079
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:2686
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:3179
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2582
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3320
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2624
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3097
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3254
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2648
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2609
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2781
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2896
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2676
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2935
int dd_nbr_neighbours
Number of neighbours to communicate with.
Definition: mptrac.h:3356
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2727
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:3031
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2504
int qnt_zeta_dot
Quantity array index forvelocity of zeta vertical coordinate.
Definition: mptrac.h:2576
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2914
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:3004
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2510
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2929
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:3016
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2980
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2612
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2600
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3236
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2965
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2417
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3209
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3299
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:3137
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2808
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:3028
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:3131
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2992
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3296
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2714
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:3115
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2778
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3284
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:3040
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2486
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2534
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2549
int qnt_subdomain
Quantity array index for current subdomain in domain decomposition.
Definition: mptrac.h:2654
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2799
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3293
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2507
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:3118
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3287
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2751
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2702
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:3067
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2633
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3152
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:3106
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:3049
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2983
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2745
int met_cms_zstd
cmultiscale zstd compression (0=off, 1=on).
Definition: mptrac.h:2717
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3224
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3332
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:3112
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2435
int met_np
Number of target pressure levels.
Definition: mptrac.h:2784
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2381
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2699
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2995
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2531
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3341
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2986
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2736
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:3094
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2872
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2905
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2591
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev).
Definition: mptrac.h:2863
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2528
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2627
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2426
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:3019
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:3149
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2962
int met_cms_heur
cmultiscale coarsening heuristics (0=default, 1=mean diff, 2=median diff, 3=max diff).
Definition: mptrac.h:2721
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:3103
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2558
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2414
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:3091
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:3085
int met_dy
Stride for latitudes.
Definition: mptrac.h:2766
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2606
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2887
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2941
int dd_subdomains_zonal
Zonal subdomain number.
Definition: mptrac.h:3350
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2378
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2830
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2474
double t_start
Start time of simulation [s].
Definition: mptrac.h:2663
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2369
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2787
int nq
Number of quantities.
Definition: mptrac.h:2363
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2953
int met_zfp_prec[METVAR]
ZFP compression precision.
Definition: mptrac.h:2708
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3308
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3338
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3314
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2881
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3260
int dd_subdomains_meridional
Meridional subdomain number.
Definition: mptrac.h:3353
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2438
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:2690
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2483
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2495
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3221
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2594
Meteo data structure.
Definition: mptrac.h:3648
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3733
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3721
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3793
size_t halo_bnd_count[4]
Definition: mptrac.h:3846
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3763
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3820
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3784
double subdomain_lon_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3825
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3757
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3778
double subdomain_lat_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3834
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3739
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3691
int nx
Number of longitudes.
Definition: mptrac.h:3654
double subdomain_lon_min
Rectangular grid limit of subdomain.
Definition: mptrac.h:3828
int ny_glob
Global sizes of meteo data.
Definition: mptrac.h:3858
int ny
Number of latitudes.
Definition: mptrac.h:3657
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3715
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3694
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3790
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3703
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3814
size_t subdomain_start[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3837
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3811
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3700
int halo_offset_start
Definition: mptrac.h:3849
size_t halo_bnd_start[4]
Definition: mptrac.h:3843
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3787
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3802
int np
Number of pressure levels.
Definition: mptrac.h:3660
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3769
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3697
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3772
int halo_offset_end
Definition: mptrac.h:3852
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3709
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3808
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3742
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3754
int nx_glob
Global sizes of meteo data.
Definition: mptrac.h:3855
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3760
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3748
double lon[EX]
Longitudes [deg].
Definition: mptrac.h:3673
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3727
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3730
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3724
size_t subdomain_count[4]
Hyperslab start and count for subdomain.
Definition: mptrac.h:3840
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3706
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3766
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3775
int npl
Number of model levels.
Definition: mptrac.h:3663
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3718
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3796
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3736
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3781
double time
Time [s].
Definition: mptrac.h:3651
double subdomain_lat_max
Rectangular grid limit of subdomain.
Definition: mptrac.h:3831
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3745
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3712
int np_glob
Global sizes of meteo data.
Definition: mptrac.h:3861
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3805
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3751
double lat[EY]
Latitudes [deg].
Definition: mptrac.h:3680
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3799
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3817
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3687
MPI information data.
Definition: mptrac.h:3426
int rank
Rank of node.
Definition: mptrac.h:3428
int size
Size of node.
Definition: mptrac.h:3431
Particle data.
Definition: mptrac.h:3400
double p
Pressure [hPa].
Definition: mptrac.h:3406
double lat
Latitude [deg].
Definition: mptrac.h:3412
double time
Time [s].
Definition: mptrac.h:3403
double lon
Longitude [deg].
Definition: mptrac.h:3409
double q[NQ]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3415