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#if 0
589 /* Initialize multiscale module... */
590 cms_ptr[ip] = cms_init(cms_param);
591
592 /* Create solution pointer... */
593 cms_sol[ip] = cms_read_arr(cms_ptr[ip], tmp_arr, lon, lat, nx, ny);
594
595 /* Set eps threshold value... */
596 if (strcasecmp(varname, "Z") == 0)
597 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_z);
598 else if (strcasecmp(varname, "T") == 0)
599 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_t);
600 else if (strcasecmp(varname, "U") == 0)
601 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_u);
602 else if (strcasecmp(varname, "V") == 0)
603 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_v);
604 else if (strcasecmp(varname, "W") == 0)
605 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_w);
606 else if (strcasecmp(varname, "PV") == 0)
607 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_pv);
608 else if (strcasecmp(varname, "H2O") == 0)
609 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_h2o);
610 else if (strcasecmp(varname, "O3") == 0)
611 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_o3);
612 else if (strcasecmp(varname, "LWC") == 0)
613 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_lwc);
614 else if (strcasecmp(varname, "RWC") == 0)
615 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_rwc);
616 else if (strcasecmp(varname, "IWC") == 0)
617 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_iwc);
618 else if (strcasecmp(varname, "SWC") == 0)
619 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_swc);
620 else if (strcasecmp(varname, "CC") == 0)
621 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_cc);
622 else
623 ERRMSG("Variable name unknown!");
624
625 /* Coarsening... */
626 cms_coarsening(cms_ptr[ip], cms_sol[ip],
627 (unsigned int) ctl->met_cms_heur);
628#endif
629
630 /* Free... */
631 free(tmp_arr);
632 }
633
634 /* Measure time... */
635 t_coars += (omp_get_wtime() - t0);
636
637 /* Loop over levels... */
638 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
639
640 /* Allocate... */
641 double *tmp_cms, *tmp_org, *tmp_diff;
642 ALLOC(tmp_cms, double,
643 nxy);
644 ALLOC(tmp_org, double,
645 nxy);
646 ALLOC(tmp_diff, double,
647 nxy);
648
649 /* Measure time... */
650 t0 = omp_get_wtime();
651
652 /* Evaluate... */
653#pragma omp parallel for default(shared)
654 for (size_t ix = 0; ix < nx; ix++)
655 for (size_t iy = 0; iy < ny; iy++) {
656 const size_t idx = ARRAY_2D(ix, iy, ny);
657 const double x[] = { lon[ix], lat[iy] };
658 cms_eval(cms_ptr[ip], cms_sol[ip], x, &tmp_cms[idx]);
659 tmp_org[idx] = array[ARRAY_3D(ix, iy, ny, ip, np)];
660 tmp_diff[idx] = tmp_cms[idx] - tmp_org[idx];
661 }
662
663 /* Measure time... */
664 t_eval += (omp_get_wtime() - t0);
665
666 /* Write info... */
667 LOG(2,
668 "cmultiscale: var= %s / lev= %lu / ratio= %g / rho= %g"
669 " / mean= %g / sd= %g / min= %g / max= %g", varname, ip,
670 cms_compression_rate(cms_ptr[ip], cms_sol[ip]),
671 gsl_stats_correlation(tmp_cms, 1, tmp_org, 1, nxy),
672 gsl_stats_mean(tmp_diff, 1, nxy), gsl_stats_sd(tmp_diff, 1, nxy),
673 gsl_stats_min(tmp_diff, 1, nxy), gsl_stats_max(tmp_diff, 1, nxy));
674
675 /* Calculate mean compression ratio... */
676 cr += cms_compression_rate(cms_ptr[ip], cms_sol[ip]) / (double) np;
677
678 /* Save binary data... */
679 if (ctl->met_cms_zstd == 1)
680 cms_save_zstd_sol(cms_sol[ip], inout, 3);
681 else
682 cms_save_sol(cms_sol[ip], inout);
683
684 /* Free... */
685 cms_delete_sol(cms_sol[ip]);
686 cms_delete_module(cms_ptr[ip]);
687 free(tmp_cms);
688 free(tmp_org);
689 free(tmp_diff);
690 }
691 }
692
693 /* Write info... */
694 LOG(2, "Write 3-D variable: %s"
695 " (cms, RATIO= %g, T_COARS= %g s, T_EVAL= %g s)",
696 varname, cr, t_coars, t_eval);
697 }
698
699 /* Free... */
700 cms_delete_param(cms_param);
701}
702#endif
703
704/*****************************************************************************/
705
707 const char *varname,
708 float *array,
709 const size_t nxy,
710 const size_t nz,
711 const int decompress,
712 FILE *inout) {
713
714 double min[EP], max[EP], off[EP], scl[EP];
715
716 unsigned short *sarray;
717
718 /* Allocate... */
719 ALLOC(sarray, unsigned short,
720 nxy * nz);
721
722 /* Read compressed stream and decompress array... */
723 if (decompress) {
724
725 /* Write info... */
726 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
727 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
728
729 /* Read data... */
730 FREAD(&scl, double,
731 nz,
732 inout);
733 FREAD(&off, double,
734 nz,
735 inout);
736 FREAD(sarray, unsigned short,
737 nxy * nz,
738 inout);
739
740 /* Convert to float... */
741#pragma omp parallel for default(shared)
742 for (size_t ixy = 0; ixy < nxy; ixy++)
743 for (size_t iz = 0; iz < nz; iz++)
744 array[ixy * nz + iz]
745 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
746 }
747
748 /* Compress array and output compressed stream... */
749 else {
750
751 /* Write info... */
752 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
753 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
754
755 /* Get range... */
756 for (size_t iz = 0; iz < nz; iz++) {
757 min[iz] = array[iz];
758 max[iz] = array[iz];
759 }
760 for (size_t ixy = 1; ixy < nxy; ixy++)
761 for (size_t iz = 0; iz < nz; iz++) {
762 if (array[ixy * nz + iz] < min[iz])
763 min[iz] = array[ixy * nz + iz];
764 if (array[ixy * nz + iz] > max[iz])
765 max[iz] = array[ixy * nz + iz];
766 }
767
768 /* Get offset and scaling factor... */
769 for (size_t iz = 0; iz < nz; iz++) {
770 scl[iz] = (max[iz] - min[iz]) / 65533.;
771 off[iz] = min[iz];
772 }
773
774 /* Convert to short... */
775#pragma omp parallel for default(shared)
776 for (size_t ixy = 0; ixy < nxy; ixy++)
777 for (size_t iz = 0; iz < nz; iz++)
778 if (scl[iz] != 0)
779 sarray[ixy * nz + iz] = (unsigned short)
780 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
781 else
782 sarray[ixy * nz + iz] = 0;
783
784 /* Write data... */
785 FWRITE(&scl, double,
786 nz,
787 inout);
788 FWRITE(&off, double,
789 nz,
790 inout);
791 FWRITE(sarray, unsigned short,
792 nxy * nz,
793 inout);
794 }
795
796 /* Free... */
797 free(sarray);
798}
799
800/*****************************************************************************/
801
802#ifdef ZFP
803void compress_zfp(
804 const char *varname,
805 float *array,
806 const int nx,
807 const int ny,
808 const int nz,
809 const int precision,
810 const double tolerance,
811 const int decompress,
812 FILE *inout) {
813
814 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
815 const zfp_type type = zfp_type_float;
816 zfp_field *field =
817 zfp_field_3d(array, type, (uint) nx, (uint) ny, (uint) nz);
818
819 /* Allocate meta data for a compressed stream... */
820 zfp_stream *zfp = zfp_stream_open(NULL);
821
822 /* Set compression mode... */
823 int actual_prec = 0;
824 double actual_tol = 0;
825 if (precision > 0)
826 actual_prec = (int) zfp_stream_set_precision(zfp, (uint) precision);
827 else if (tolerance > 0)
828 actual_tol = zfp_stream_set_accuracy(zfp, tolerance);
829 else
830 ERRMSG("Set precision or tolerance!");
831
832 /* Allocate buffer for compressed data... */
833 const size_t bufsize = zfp_stream_maximum_size(zfp, field);
834 void *buffer = malloc(bufsize);
835
836 /* Associate bit stream with allocated buffer... */
837 bitstream *stream = stream_open(buffer, bufsize);
838 zfp_stream_set_bit_stream(zfp, stream);
839 zfp_stream_rewind(zfp);
840
841 /* Read compressed stream and decompress array... */
842 size_t zfpsize;
843 if (decompress) {
844 FREAD(&zfpsize, size_t,
845 1,
846 inout);
847 if (fread(buffer, 1, zfpsize, inout) != zfpsize)
848 ERRMSG("Error while reading zfp data!");
849 if (!zfp_decompress(zfp, field)) {
850 ERRMSG("Decompression failed!");
851 }
852 LOG(2, "Read 3-D variable: %s "
853 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
854 varname, actual_prec, actual_tol,
855 ((double) (nx * ny * nz)) / (double) zfpsize);
856 }
857
858 /* Compress array and output compressed stream... */
859 else {
860 zfpsize = zfp_compress(zfp, field);
861 if (!zfpsize) {
862 ERRMSG("Compression failed!");
863 } else {
864 FWRITE(&zfpsize, size_t,
865 1,
866 inout);
867 if (fwrite(buffer, 1, zfpsize, inout) != zfpsize)
868 ERRMSG("Error while writing zfp data!");
869 }
870 LOG(2, "Write 3-D variable: %s "
871 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
872 varname, actual_prec, actual_tol,
873 ((double) (nx * ny * nz)) / (double) zfpsize);
874 }
875
876 /* Free... */
877 zfp_field_free(field);
878 zfp_stream_close(zfp);
879 stream_close(stream);
880 free(buffer);
881}
882#endif
883
884/*****************************************************************************/
885
886#ifdef ZSTD
887void compress_zstd(
888 const char *varname,
889 float *array,
890 const size_t n,
891 const int decompress,
892 const int level,
893 FILE *inout) {
894
895 /* Get buffer sizes... */
896 const size_t uncomprLen = n * sizeof(float);
897 size_t comprLen = ZSTD_compressBound(uncomprLen);
898 size_t compsize;
899
900 /* Allocate... */
901 char *compr = (char *) calloc((uint) comprLen, 1);
902 char *uncompr = (char *) array;
903
904 /* Read compressed stream and decompress array... */
905 if (decompress) {
906 FREAD(&comprLen, size_t,
907 1,
908 inout);
909 if (fread(compr, 1, comprLen, inout) != comprLen)
910 ERRMSG("Error while reading zstd data!");
911 compsize = ZSTD_decompress(uncompr, uncomprLen, compr, comprLen);
912 if (ZSTD_isError(compsize)) {
913 ERRMSG("Decompression failed!");
914 }
915 LOG(2, "Read 3-D variable: %s (zstd, RATIO= %g)",
916 varname, ((double) uncomprLen) / (double) comprLen)
917 }
918
919 /* Compress array and output compressed stream... */
920 else {
921 compsize = ZSTD_compress(compr, comprLen, uncompr, uncomprLen, level);
922 if (ZSTD_isError(compsize)) {
923 ERRMSG("Compression failed!");
924 } else {
925 FWRITE(&compsize, size_t,
926 1,
927 inout);
928 if (fwrite(compr, 1, compsize, inout) != compsize)
929 ERRMSG("Error while writing zstd data!");
930 }
931 LOG(2, "Write 3-D variable: %s (zstd, RATIO= %g)",
932 varname, ((double) uncomprLen) / (double) compsize);
933 }
934
935 /* Free... */
936 free(compr);
937}
938#endif
939
940/*****************************************************************************/
941
943 const int year,
944 const int mon,
945 const int day,
946 int *doy) {
947
948 const int
949 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
950 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
951
952 /* Get day of year... */
953 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
954 *doy = d0l[mon - 1] + day - 1;
955 else
956 *doy = d0[mon - 1] + day - 1;
957}
958
959/*****************************************************************************/
960
962 const int year,
963 const int doy,
964 int *mon,
965 int *day) {
966
967 const int
968 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
969 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
970
971 int i;
972
973 /* Get month and day... */
974 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
975 for (i = 11; i > 0; i--)
976 if (d0l[i] <= doy)
977 break;
978 *mon = i + 1;
979 *day = doy - d0l[i] + 1;
980 } else {
981 for (i = 11; i > 0; i--)
982 if (d0[i] <= doy)
983 break;
984 *mon = i + 1;
985 *day = doy - d0[i] + 1;
986 }
987}
988
989/*****************************************************************************/
990
992 double *fcReal,
993 double *fcImag,
994 const int n) {
995
996 double data[2 * EX];
997
998 /* Check size... */
999 if (n > EX)
1000 ERRMSG("Too many data points!");
1001
1002 /* Allocate... */
1003 gsl_fft_complex_wavetable *wavetable =
1004 gsl_fft_complex_wavetable_alloc((size_t) n);
1005 gsl_fft_complex_workspace *workspace =
1006 gsl_fft_complex_workspace_alloc((size_t) n);
1007
1008 /* Set data (real, complex)... */
1009 for (int i = 0; i < n; i++) {
1010 data[2 * i] = fcReal[i];
1011 data[2 * i + 1] = fcImag[i];
1012 }
1013
1014 /* Calculate FFT... */
1015 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
1016
1017 /* Copy data... */
1018 for (int i = 0; i < n; i++) {
1019 fcReal[i] = data[2 * i];
1020 fcImag[i] = data[2 * i + 1];
1021 }
1022
1023 /* Free... */
1024 gsl_fft_complex_wavetable_free(wavetable);
1025 gsl_fft_complex_workspace_free(workspace);
1026}
1027
1028/*****************************************************************************/
1029
1031 const double z,
1032 const double lon,
1033 const double lat,
1034 double *x) {
1035
1036 const double radius = z + RE;
1037 const double latrad = DEG2RAD(lat);
1038 const double lonrad = DEG2RAD(lon);
1039 const double coslat = cos(latrad);
1040
1041 x[0] = radius * coslat * cos(lonrad);
1042 x[1] = radius * coslat * sin(lonrad);
1043 x[2] = radius * sin(latrad);
1044}
1045
1046/*****************************************************************************/
1047
1049 const ctl_t *ctl,
1050 const double t,
1051 const int direct,
1052 const char *metbase,
1053 const double dt_met,
1054 char *filename) {
1055
1056 char repl[LEN];
1057
1058 double t6, r;
1059
1060 int year, mon, day, hour, min, sec;
1061
1062 /* Round time to fixed intervals... */
1063 if (direct == -1)
1064 t6 = floor(t / dt_met) * dt_met;
1065 else
1066 t6 = ceil(t / dt_met) * dt_met;
1067
1068 /* Decode time... */
1069 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1070
1071 /* Set filename of MPTRAC meteo files... */
1072 if (ctl->met_clams == 0) {
1073 if (ctl->met_type == 0)
1074 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1075 else if (ctl->met_type == 1)
1076 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1077 else if (ctl->met_type == 2)
1078 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1079 else if (ctl->met_type == 3)
1080 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1081 else if (ctl->met_type == 4)
1082 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1083 else if (ctl->met_type == 5)
1084 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1085 sprintf(repl, "%d", year);
1086 get_met_replace(filename, "YYYY", repl);
1087 sprintf(repl, "%02d", mon);
1088 get_met_replace(filename, "MM", repl);
1089 sprintf(repl, "%02d", day);
1090 get_met_replace(filename, "DD", repl);
1091 sprintf(repl, "%02d", hour);
1092 get_met_replace(filename, "HH", repl);
1093 }
1094
1095 /* Set filename of CLaMS meteo files... */
1096 else {
1097 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1098 sprintf(repl, "%d", year);
1099 get_met_replace(filename, "YYYY", repl);
1100 sprintf(repl, "%02d", year % 100);
1101 get_met_replace(filename, "YY", repl);
1102 sprintf(repl, "%02d", mon);
1103 get_met_replace(filename, "MM", repl);
1104 sprintf(repl, "%02d", day);
1105 get_met_replace(filename, "DD", repl);
1106 sprintf(repl, "%02d", hour);
1107 get_met_replace(filename, "HH", repl);
1108 }
1109}
1110
1111/*****************************************************************************/
1112
1114 char *orig,
1115 char *search,
1116 char *repl) {
1117
1118 char buffer[LEN];
1119
1120 /* Iterate... */
1121 for (int i = 0; i < 3; i++) {
1122
1123 /* Replace sub-string... */
1124 char *ch;
1125 if (!(ch = strstr(orig, search)))
1126 return;
1127 strncpy(buffer, orig, (size_t) (ch - orig));
1128 buffer[ch - orig] = 0;
1129 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1130 orig[0] = 0;
1131 strcpy(orig, buffer);
1132 }
1133}
1134
1135/*****************************************************************************/
1136
1138 const int met_tropo,
1139 ctl_t *ctl,
1140 clim_t *clim,
1141 met_t *met,
1142 const double *lons,
1143 const int nx,
1144 const double *lats,
1145 const int ny,
1146 double *pt,
1147 double *zt,
1148 double *tt,
1149 double *qt,
1150 double *o3t,
1151 double *ps,
1152 double *zs) {
1153
1155
1156 ctl->met_tropo = met_tropo;
1157 read_met_tropo(ctl, clim, met);
1158#pragma omp parallel for default(shared) private(ci,cw)
1159 for (int ix = 0; ix < nx; ix++)
1160 for (int iy = 0; iy < ny; iy++) {
1161 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1162 &pt[iy * nx + ix], ci, cw, 1);
1163 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1164 &ps[iy * nx + ix], ci, cw, 0);
1165 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1166 &zs[iy * nx + ix], ci, cw, 0);
1167 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1168 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1169 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1170 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1171 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1172 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1173 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1174 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1175 }
1176}
1177
1178/*****************************************************************************/
1179
1181 const double *lons,
1182 const int nlon,
1183 const double *lats,
1184 const int nlat,
1185 const double lon,
1186 const double lat,
1187 double *lon2,
1188 double *lat2) {
1189
1190 /* Check longitude... */
1191 *lon2 = FMOD(lon, 360.);
1192 if (*lon2 < lons[0])
1193 *lon2 += 360;
1194 else if (*lon2 > lons[nlon - 1])
1195 *lon2 -= 360;
1196
1197 /* Check latitude... */
1198 *lat2 = lat;
1199 if (lats[0] < lats[nlat - 1])
1200 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
1201 else
1202 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
1203}
1204
1205/*****************************************************************************/
1206
1208 const met_t *met0,
1209 float heights0[EX][EY][EP],
1210 float array0[EX][EY][EP],
1211 const met_t *met1,
1212 float heights1[EX][EY][EP],
1213 float array1[EX][EY][EP],
1214 const double ts,
1215 const double height,
1216 const double lon,
1217 const double lat,
1218 double *var,
1219 int *ci,
1220 double *cw,
1221 const int init) {
1222
1223 if (init) {
1224
1225 /* Check longitude and latitude... */
1226 double lon2, lat2;
1227 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
1228 &lon2, &lat2);
1229
1230 /* Get horizontal indizes... */
1231 ci[0] = locate_irr(met0->lon, met0->nx, lon2);
1232 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
1233
1234 /* Locate the vertical indizes for each edge of the column... */
1235 int ind[2][4];
1236 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1237 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1238
1239 /* Find minimum and maximum indizes... */
1240 ci[2] = ind[0][0];
1241 int k_max = ind[0][0];
1242 for (int i = 0; i < 2; i++)
1243 for (int j = 0; j < 4; j++) {
1244 if (ci[2] > ind[i][j])
1245 ci[2] = ind[i][j];
1246 if (k_max < ind[i][j])
1247 k_max = ind[i][j];
1248 }
1249
1250 /* Get weighting factors for time, longitude and latitude... */
1251 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1252 cw[0] = (lon2 - met0->lon[ci[0]]) /
1253 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1254 cw[1] = (lat2 - met0->lat[ci[1]]) /
1255 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1256
1257 /* Interpolate in time at the lowest level... */
1258 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1259 - heights0[ci[0]][ci[1]][ci[2]])
1260 + heights0[ci[0]][ci[1]][ci[2]];
1261 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1262 - heights0[ci[0]][ci[1] + 1][ci[2]])
1263 + heights0[ci[0]][ci[1] + 1][ci[2]];
1264 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1265 - heights0[ci[0] + 1][ci[1]][ci[2]])
1266 + heights0[ci[0] + 1][ci[1]][ci[2]];
1267 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1268 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1269 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1270
1271 /* Interpolate in latitude direction... */
1272 double height0 = cw[1] * (height01 - height00) + height00;
1273 double height1 = cw[1] * (height11 - height10) + height10;
1274
1275 /* Interpolate in longitude direction... */
1276 double height_bot = cw[0] * (height1 - height0) + height0;
1277
1278 /* Interpolate in time at the upper level... */
1279 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1280 - heights0[ci[0]][ci[1]][ci[2] + 1])
1281 + heights0[ci[0]][ci[1]][ci[2] + 1];
1282 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1283 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1284 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1285 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1286 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1287 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1288 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1289 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1290 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1291
1292 /* Interpolate in latitude direction... */
1293 height0 = cw[1] * (height01 - height00) + height00;
1294 height1 = cw[1] * (height11 - height10) + height10;
1295
1296 /* Interpolate in longitude direction... */
1297 double height_top = cw[0] * (height1 - height0) + height0;
1298
1299 /* Search at higher levels if height is not in box... */
1300 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1301 ((height_bot <= height) || (height_top > height))
1302 && (height_bot >= height) && (ci[2] < k_max))
1303 ||
1304 ((heights0[0][0][0] < heights0[0][0][1]) &&
1305 ((height_bot >= height) || (height_top < height))
1306 && (height_bot <= height) && (ci[2] < k_max))
1307 ) {
1308
1309 ci[2]++;
1310 height_bot = height_top;
1311
1312 /* Interpolate in time at the next level... */
1313 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1314 - heights0[ci[0]][ci[1]][ci[2] + 1])
1315 + heights0[ci[0]][ci[1]][ci[2] + 1];
1316 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1317 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1318 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1319 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1320 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1321 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1322 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1323 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1324 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1325
1326 /* Interpolate in latitude direction... */
1327 height0 = cw[1] * (height01 - height00) + height00;
1328 height1 = cw[1] * (height11 - height10) + height10;
1329
1330 /* Interpolate in longitude direction... */
1331 height_top = cw[0] * (height1 - height0) + height0;
1332 }
1333
1334 /* Get vertical weighting factors... */
1335 cw[2] = (height - height_bot)
1336 / (height_top - height_bot);
1337 }
1338
1339 /* Calculate the needed array values... */
1340 double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1341 - array0[ci[0]][ci[1]][ci[2]])
1342 + array0[ci[0]][ci[1]][ci[2]];
1343 double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1344 - array0[ci[0] + 1][ci[1]][ci[2]])
1345 + array0[ci[0] + 1][ci[1]][ci[2]];
1346 double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1347 - array0[ci[0]][ci[1] + 1][ci[2]])
1348 + array0[ci[0]][ci[1] + 1][ci[2]];
1349 double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1350 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1351 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1352 double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1353 - array0[ci[0]][ci[1]][ci[2] + 1])
1354 + array0[ci[0]][ci[1]][ci[2] + 1];
1355 double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
1356 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
1357 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
1358 double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
1359 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
1360 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
1361 double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1362 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1363 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1364
1365 double array00 = cw[0] * (array100 - array000) + array000;
1366 double array10 = cw[0] * (array110 - array010) + array010;
1367 double array01 = cw[0] * (array101 - array001) + array001;
1368 double array11 = cw[0] * (array111 - array011) + array011;
1369
1370 double aux0 = cw[1] * (array10 - array00) + array00;
1371 double aux1 = cw[1] * (array11 - array01) + array01;
1372
1373 /* Interpolate vertically... */
1374 *var = cw[2] * (aux1 - aux0) + aux0;
1375}
1376
1377/*****************************************************************************/
1378
1380 const met_t *met,
1381 float array[EX][EY][EP],
1382 const double p,
1383 const double lon,
1384 const double lat,
1385 double *var,
1386 int *ci,
1387 double *cw,
1388 const int init) {
1389
1390 /* Initialize interpolation... */
1391 if (init) {
1392
1393 /* Check longitude and latitude... */
1394 double lon2, lat2;
1395 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1396 &lon2, &lat2);
1397
1398 /* Get interpolation indices... */
1399 ci[0] = locate_irr(met->p, met->np, p);
1400 ci[1] = locate_reg(met->lon, met->nx, lon2);
1401 ci[2] = locate_irr(met->lat, met->ny, lat2);
1402
1403 /* Get interpolation weights... */
1404 cw[0] = (met->p[ci[0] + 1] - p)
1405 / (met->p[ci[0] + 1] - met->p[ci[0]]);
1406 cw[1] = (met->lon[ci[1] + 1] - lon2)
1407 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1408 cw[2] = (met->lat[ci[2] + 1] - lat2)
1409 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1410 }
1411
1412 /* Interpolate vertically... */
1413 double aux00 =
1414 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
1415 + array[ci[1]][ci[2]][ci[0] + 1];
1416 double aux01 =
1417 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
1418 array[ci[1]][ci[2] + 1][ci[0] + 1])
1419 + array[ci[1]][ci[2] + 1][ci[0] + 1];
1420 double aux10 =
1421 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
1422 array[ci[1] + 1][ci[2]][ci[0] + 1])
1423 + array[ci[1] + 1][ci[2]][ci[0] + 1];
1424 double aux11 =
1425 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
1426 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
1427 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
1428
1429 /* Interpolate horizontally... */
1430 aux00 = cw[2] * (aux00 - aux01) + aux01;
1431 aux11 = cw[2] * (aux10 - aux11) + aux11;
1432 *var = cw[1] * (aux00 - aux11) + aux11;
1433}
1434
1435/*****************************************************************************/
1436
1438 const met_t *met,
1439 float zs[EX][EY][EP],
1440 float array[EX][EY][EP],
1441 const double z,
1442 const double lon,
1443 const double lat,
1444 double *var) {
1445
1446 /* Check longitude and latitude... */
1447 double lon2, lat2;
1448 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat, &lon2,
1449 &lat2);
1450
1451 /* Get horizontal indices... */
1452 const int ix = locate_reg(met->lon, met->nx, lon2);
1453 const int iy = locate_irr(met->lat, met->ny, lat2);
1454
1455 /* Interpolate vertically... */
1456 int iz = locate_irr_float(zs[ix][iy], met->npl, z, 0);
1457 double aux00;
1458 if (z >= zs[ix][iy][iz + 1])
1459 aux00 = array[ix][iy][iz + 1];
1460 else if (z <= zs[ix][iy][iz])
1461 aux00 = array[ix][iy][iz];
1462 else
1463 aux00 = LIN(zs[ix][iy][iz], array[ix][iy][iz],
1464 zs[ix][iy][iz + 1], array[ix][iy][iz + 1], z);
1465
1466 iz = locate_irr_float(zs[ix][iy + 1], met->npl, z, iz);
1467 double aux01;
1468 if (z >= zs[ix][iy + 1][iz + 1])
1469 aux01 = array[ix][iy + 1][iz + 1];
1470 else if (z <= zs[ix][iy + 1][iz])
1471 aux01 = array[ix][iy + 1][iz];
1472 else
1473 aux01 = LIN(zs[ix][iy + 1][iz], array[ix][iy + 1][iz],
1474 zs[ix][iy + 1][iz + 1], array[ix][iy + 1][iz + 1], z);
1475
1476 iz = locate_irr_float(zs[ix + 1][iy], met->npl, z, iz);
1477 double aux10;
1478 if (z >= zs[ix + 1][iy][iz + 1])
1479 aux10 = array[ix + 1][iy][iz + 1];
1480 else if (z <= zs[ix + 1][iy][iz])
1481 aux10 = array[ix + 1][iy][iz];
1482 else
1483 aux10 = LIN(zs[ix + 1][iy][iz], array[ix + 1][iy][iz],
1484 zs[ix + 1][iy][iz + 1], array[ix + 1][iy][iz + 1], z);
1485
1486 iz = locate_irr_float(zs[ix + 1][iy + 1], met->npl, z, iz);
1487 double aux11;
1488 if (z >= zs[ix + 1][iy + 1][iz + 1])
1489 aux11 = array[ix + 1][iy + 1][iz + 1];
1490 else if (z <= zs[ix + 1][iy + 1][iz])
1491 aux11 = array[ix + 1][iy + 1][iz];
1492 else
1493 aux11 = LIN(zs[ix + 1][iy + 1][iz], array[ix + 1][iy + 1][iz],
1494 zs[ix + 1][iy + 1][iz + 1], array[ix + 1][iy + 1][iz + 1], z);
1495
1496 /* Interpolate horizontally... */
1497 double aux0 = LIN(met->lat[iy], aux00, met->lat[iy + 1], aux01, lat2);
1498 double aux1 = LIN(met->lat[iy], aux10, met->lat[iy + 1], aux11, lat2);
1499 *var = LIN(met->lon[ix], aux0, met->lon[ix + 1], aux1, lon2);
1500}
1501
1502/*****************************************************************************/
1503
1505 const met_t *met,
1506 float array[EX][EY],
1507 const double lon,
1508 const double lat,
1509 double *var,
1510 int *ci,
1511 double *cw,
1512 const int init) {
1513
1514 /* Initialize interpolation... */
1515 if (init) {
1516
1517 /* Check longitude and latitude... */
1518 double lon2, lat2;
1519 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1520 &lon2, &lat2);
1521
1522 /* Get interpolation indices... */
1523 ci[1] = locate_reg(met->lon, met->nx, lon2);
1524 ci[2] = locate_irr(met->lat, met->ny, lat2);
1525
1526 /* Get interpolation weights... */
1527 cw[1] = (met->lon[ci[1] + 1] - lon2)
1528 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1529 cw[2] = (met->lat[ci[2] + 1] - lat2)
1530 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1531 }
1532
1533 /* Set variables... */
1534 double aux00 = array[ci[1]][ci[2]];
1535 double aux01 = array[ci[1]][ci[2] + 1];
1536 double aux10 = array[ci[1] + 1][ci[2]];
1537 double aux11 = array[ci[1] + 1][ci[2] + 1];
1538
1539 /* Interpolate horizontally... */
1540 if (isfinite(aux00) && isfinite(aux01)
1541 && isfinite(aux10) && isfinite(aux11)) {
1542 aux00 = cw[2] * (aux00 - aux01) + aux01;
1543 aux11 = cw[2] * (aux10 - aux11) + aux11;
1544 *var = cw[1] * (aux00 - aux11) + aux11;
1545 } else {
1546 if (cw[2] < 0.5) {
1547 if (cw[1] < 0.5)
1548 *var = aux11;
1549 else
1550 *var = aux01;
1551 } else {
1552 if (cw[1] < 0.5)
1553 *var = aux10;
1554 else
1555 *var = aux00;
1556 }
1557 }
1558}
1559
1560/*****************************************************************************/
1561
1563 const met_t *met0,
1564 float array0[EX][EY][EP],
1565 const met_t *met1,
1566 float array1[EX][EY][EP],
1567 const double ts,
1568 const double p,
1569 const double lon,
1570 const double lat,
1571 double *var,
1572 int *ci,
1573 double *cw,
1574 const int init) {
1575
1576 double var0, var1;
1577
1578 /* Spatial interpolation... */
1579 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
1580 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
1581
1582 /* Get weighting factor... */
1583 const double wt = (met1->time - ts) / (met1->time - met0->time);
1584
1585 /* Interpolate... */
1586 *var = wt * (var0 - var1) + var1;
1587}
1588
1589/*****************************************************************************/
1590
1592 const met_t *met0,
1593 float zs0[EX][EY][EP],
1594 float array0[EX][EY][EP],
1595 const met_t *met1,
1596 float zs1[EX][EY][EP],
1597 float array1[EX][EY][EP],
1598 const double ts,
1599 const double p,
1600 const double lon,
1601 const double lat,
1602 double *var) {
1603
1604 double var0, var1;
1605
1606 /* Spatial interpolation... */
1607 intpol_met_space_3d_ml(met0, zs0, array0, p, lon, lat, &var0);
1608 intpol_met_space_3d_ml(met1, zs1, array1, p, lon, lat, &var1);
1609
1610 /* Interpolate... */
1611 *var = LIN(met0->time, var0, met1->time, var1, ts);
1612}
1613
1614/*****************************************************************************/
1615
1617 const met_t *met0,
1618 float array0[EX][EY],
1619 const met_t *met1,
1620 float array1[EX][EY],
1621 const double ts,
1622 const double lon,
1623 const double lat,
1624 double *var,
1625 int *ci,
1626 double *cw,
1627 const int init) {
1628
1629 double var0, var1;
1630
1631 /* Spatial interpolation... */
1632 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
1633 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
1634
1635 /* Get weighting factor... */
1636 const double wt = (met1->time - ts) / (met1->time - met0->time);
1637
1638 /* Interpolate... */
1639 if (isfinite(var0) && isfinite(var1))
1640 *var = wt * (var0 - var1) + var1;
1641 else if (wt < 0.5)
1642 *var = var1;
1643 else
1644 *var = var0;
1645}
1646
1647/*****************************************************************************/
1648
1650 const double time0,
1651 float array0[EX][EY],
1652 const double time1,
1653 float array1[EX][EY],
1654 const double lons[EX],
1655 const double lats[EY],
1656 const int nlon,
1657 const int nlat,
1658 const double time,
1659 const double lon,
1660 const double lat,
1661 const int method,
1662 double *var,
1663 double *sigma) {
1664
1665 double aux0, aux1, aux00, aux01, aux10, aux11, mean = 0;
1666
1667 int n = 0;
1668
1669 /* Check longitude and latitude... */
1670 double lon2, lat2;
1671 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
1672
1673 /* Get indices... */
1674 const int ix = locate_reg(lons, (int) nlon, lon2);
1675 const int iy = locate_irr(lats, (int) nlat, lat2);
1676
1677 /* Calculate standard deviation... */
1678 *sigma = 0;
1679 for (int dx = 0; dx < 2; dx++)
1680 for (int dy = 0; dy < 2; dy++) {
1681 if (isfinite(array0[ix + dx][iy + dy])) {
1682 mean += array0[ix + dx][iy + dy];
1683 *sigma += SQR(array0[ix + dx][iy + dy]);
1684 n++;
1685 }
1686 if (isfinite(array1[ix + dx][iy + dy])) {
1687 mean += array1[ix + dx][iy + dy];
1688 *sigma += SQR(array1[ix + dx][iy + dy]);
1689 n++;
1690 }
1691 }
1692 if (n > 0)
1693 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
1694
1695 /* Linear interpolation... */
1696 if (method == 1 && isfinite(array0[ix][iy])
1697 && isfinite(array0[ix][iy + 1])
1698 && isfinite(array0[ix + 1][iy])
1699 && isfinite(array0[ix + 1][iy + 1])
1700 && isfinite(array1[ix][iy])
1701 && isfinite(array1[ix][iy + 1])
1702 && isfinite(array1[ix + 1][iy])
1703 && isfinite(array1[ix + 1][iy + 1])) {
1704
1705 aux00 = LIN(lons[ix], array0[ix][iy],
1706 lons[ix + 1], array0[ix + 1][iy], lon2);
1707 aux01 = LIN(lons[ix], array0[ix][iy + 1],
1708 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1709 aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1710
1711 aux10 = LIN(lons[ix], array1[ix][iy],
1712 lons[ix + 1], array1[ix + 1][iy], lon2);
1713 aux11 = LIN(lons[ix], array1[ix][iy + 1],
1714 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1715 aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1716
1717 *var = LIN(time0, aux0, time1, aux1, time);
1718 }
1719
1720 /* Nearest neighbor interpolation... */
1721 else {
1722 aux00 = NN(lons[ix], array0[ix][iy],
1723 lons[ix + 1], array0[ix + 1][iy], lon2);
1724 aux01 = NN(lons[ix], array0[ix][iy + 1],
1725 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1726 aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1727
1728 aux10 = NN(lons[ix], array1[ix][iy],
1729 lons[ix + 1], array1[ix + 1][iy], lon2);
1730 aux11 = NN(lons[ix], array1[ix][iy + 1],
1731 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1732 aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1733
1734 *var = NN(time0, aux0, time1, aux1, time);
1735 }
1736}
1737
1738/*****************************************************************************/
1739
1741 const double jsec,
1742 int *year,
1743 int *mon,
1744 int *day,
1745 int *hour,
1746 int *min,
1747 int *sec,
1748 double *remain) {
1749
1750 struct tm t0, *t1;
1751
1752 t0.tm_year = 100;
1753 t0.tm_mon = 0;
1754 t0.tm_mday = 1;
1755 t0.tm_hour = 0;
1756 t0.tm_min = 0;
1757 t0.tm_sec = 0;
1758
1759 const time_t jsec0 = (time_t) jsec + timegm(&t0);
1760 t1 = gmtime(&jsec0);
1761
1762 *year = t1->tm_year + 1900;
1763 *mon = t1->tm_mon + 1;
1764 *day = t1->tm_mday;
1765 *hour = t1->tm_hour;
1766 *min = t1->tm_min;
1767 *sec = t1->tm_sec;
1768 *remain = jsec - floor(jsec);
1769}
1770
1771/*****************************************************************************/
1772
1774 const double kz[EP],
1775 const double kw[EP],
1776 const int nk,
1777 const double p) {
1778
1779 /* Check number of data points... */
1780 if (nk < 2)
1781 return 1.0;
1782
1783 /* Get altitude... */
1784 const double z = Z(p);
1785
1786 /* Get weighting factor... */
1787 if (z < kz[0])
1788 return kw[0];
1789 else if (z > kz[nk - 1])
1790 return kw[nk - 1];
1791 else {
1792 int idx = locate_irr(kz, nk, z);
1793 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
1794 }
1795}
1796
1797/*****************************************************************************/
1798
1800 const double t,
1801 const double h2o) {
1802
1803 /*
1804 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
1805 and water vapor volume mixing ratio [1].
1806
1807 Reference: https://en.wikipedia.org/wiki/Lapse_rate
1808 */
1809
1810 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
1811
1812 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
1813}
1814
1815/*****************************************************************************/
1816
1818 ctl_t *ctl) {
1819
1820 if (0 == ctl->met_press_level_def) {
1821
1822 ctl->met_np = 138;
1823
1824 const double press[138] = {
1825 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1826 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1827 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1828 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1829 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1830 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1831 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1832 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1833 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1834 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1835 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1836 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1837 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1838 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1839 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1840 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1841 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1842 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1843 1010.8487, 1013.2500, 1044.45
1844 };
1845
1846 for (int ip = 0; ip < ctl->met_np; ip++)
1847 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1848
1849 } else if (1 == ctl->met_press_level_def) {
1850
1851 ctl->met_np = 92;
1852
1853 const double press[92] = {
1854 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1855 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1856 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1857 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1858 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1859 113.6382,
1860 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1861 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1862 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1863 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1864 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1865 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1866 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1867 1007.4431, 1010.8487, 1013.2500, 1044.45
1868 };
1869
1870 for (int ip = 0; ip < ctl->met_np; ip++)
1871 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1872
1873 } else if (2 == ctl->met_press_level_def) {
1874
1875 ctl->met_np = 60;
1876
1877 const double press[60] = {
1878 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1879 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1880 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1881 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1882 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1883 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1884 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1885 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1044.45
1886 };
1887
1888 for (int ip = 0; ip < ctl->met_np; ip++)
1889 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1890
1891 } else if (3 == ctl->met_press_level_def) {
1892
1893 ctl->met_np = 147;
1894
1895 const double press[147] = {
1896 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1897 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1898 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1899 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1900 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1901 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1902 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1903 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1904 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1905 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1906 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1907 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1908 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1909 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1910 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1911 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1912 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1913 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1914 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
1915 1031.97,
1916 1035.09, 1038.21, 1041.33, 1044.45
1917 };
1918
1919 for (int ip = 0; ip < ctl->met_np; ip++)
1920 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1921
1922 } else if (4 == ctl->met_press_level_def) {
1923
1924 ctl->met_np = 101;
1925
1926 const double press[101] = {
1927 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1928 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1929 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1930 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1931 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1932 113.6382,
1933 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1934 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1935 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1936 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1937 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1938 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1939 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1940 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
1941 1028.85, 1031.97,
1942 1035.09, 1038.21, 1041.33, 1044.45
1943 };
1944
1945 for (int ip = 0; ip < ctl->met_np; ip++)
1946 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1947
1948 } else if (5 == ctl->met_press_level_def) {
1949
1950 ctl->met_np = 62;
1951
1952 const double press[62] = {
1953 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1954 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1955 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1956 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1957 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1958 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1959 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1960 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
1961 1044.45
1962 };
1963
1964 for (int ip = 0; ip < ctl->met_np; ip++)
1965 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1966
1967 } else if (6 == ctl->met_press_level_def) {
1968
1969 ctl->met_np = 137;
1970
1971 const double press[137] = {
1972 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
1973 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
1974 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
1975 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
1976 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
1977 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1978 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
1979 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
1980 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
1981 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
1982 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
1983 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
1984 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
1985 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
1986 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
1987 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
1988 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
1989 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
1990 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
1991 1030.06, 1037.25, 1044.45
1992 };
1993
1994 for (int ip = 0; ip < ctl->met_np; ip++)
1995 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1996
1997 } else if (7 == ctl->met_press_level_def) {
1998
1999 ctl->met_np = 59;
2000
2001 const double press[59] = {
2002 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2003 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2004 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2005 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2006 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2007 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2008 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2009 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2010 1028.53, 1046.13
2011 };
2012
2013 for (int ip = 0; ip < ctl->met_np; ip++)
2014 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2015
2016 } else {
2017 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.")
2018 }
2019
2020 if (ctl->met_np > NP)
2021 ERRMSG("Recompile with larger NP to use this pressure level definition.")
2022
2023}
2024
2025/*****************************************************************************/
2026
2028 const double *xx,
2029 const int n,
2030 const double x) {
2031
2032 int ilo = 0;
2033 int ihi = n - 1;
2034 int i = (ihi + ilo) >> 1;
2035
2036 if (xx[i] < xx[i + 1])
2037 while (ihi > ilo + 1) {
2038 i = (ihi + ilo) >> 1;
2039 if (xx[i] > x)
2040 ihi = i;
2041 else
2042 ilo = i;
2043 } else
2044 while (ihi > ilo + 1) {
2045 i = (ihi + ilo) >> 1;
2046 if (xx[i] <= x)
2047 ihi = i;
2048 else
2049 ilo = i;
2050 }
2051
2052 return ilo;
2053}
2054
2055/*****************************************************************************/
2056
2058 const float *xx,
2059 const int n,
2060 const double x,
2061 const int ig) {
2062
2063 int ilo = 0;
2064 int ihi = n - 1;
2065 int i = (ihi + ilo) >> 1;
2066
2067 if (x >= xx[ig] && x < xx[ig + 1])
2068 return ig;
2069
2070 if (xx[i] < xx[i + 1])
2071 while (ihi > ilo + 1) {
2072 i = (ihi + ilo) >> 1;
2073 if (xx[i] > x)
2074 ihi = i;
2075 else
2076 ilo = i;
2077 } else
2078 while (ihi > ilo + 1) {
2079 i = (ihi + ilo) >> 1;
2080 if (xx[i] <= x)
2081 ihi = i;
2082 else
2083 ilo = i;
2084 }
2085
2086 return ilo;
2087}
2088
2089/*****************************************************************************/
2090
2092 const double *xx,
2093 const int n,
2094 const double x) {
2095
2096 /* Calculate index... */
2097 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2098
2099 /* Check range... */
2100 if (i < 0)
2101 return 0;
2102 else if (i > n - 2)
2103 return n - 2;
2104 else
2105 return i;
2106}
2107
2108/*****************************************************************************/
2109
2111 float profiles[EX][EY][EP],
2112 const int np,
2113 const int lon_ap_ind,
2114 const int lat_ap_ind,
2115 const double height_ap,
2116 int *ind) {
2117
2118 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2119 np, height_ap, 0);
2120 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2121 np, height_ap, ind[0]);
2122 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2123 np, height_ap, ind[1]);
2124 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2125 np, height_ap, ind[2]);
2126}
2127
2128/*****************************************************************************/
2129
2131 const ctl_t *ctl,
2132 const cache_t *cache,
2133 met_t *met0,
2134 met_t *met1,
2135 atm_t *atm) {
2136
2137 /* Set timer... */
2138 SELECT_TIMER("MODULE_ADVECT", "PHYSICS", NVTX_GPU);
2139
2140 /* Use omega vertical velocity... */
2141 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2142
2143 /* Loop over particles... */
2144 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2145
2146 /* Init... */
2148 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2149 x[3] = { 0, 0, 0 };
2150
2151 /* Loop over integration nodes... */
2152 for (int i = 0; i < ctl->advect; i++) {
2153
2154 /* Set position... */
2155 if (i == 0) {
2156 dts = 0.0;
2157 x[0] = atm->lon[ip];
2158 x[1] = atm->lat[ip];
2159 x[2] = atm->p[ip];
2160 } else {
2161 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2162 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2163 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2164 x[2] = atm->p[ip] + dts * w[i - 1];
2165 }
2166 const double tm = atm->time[ip] + dts;
2167
2168 /* Interpolate meteo data on pressure levels... */
2169 if (ctl->advect_vert_coord == 0) {
2170 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2171 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2172 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2173 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2174 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2175 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2176 }
2177
2178 /* Interpolate meteo data on model levels... */
2179 else {
2180 intpol_met_time_3d_ml(met0, met0->pl, met0->ul,
2181 met1, met1->pl, met1->ul,
2182 tm, x[2], x[0], x[1], &u[i]);
2183 intpol_met_time_3d_ml(met0, met0->pl, met0->vl,
2184 met1, met1->pl, met1->vl,
2185 tm, x[2], x[0], x[1], &v[i]);
2186 intpol_met_time_3d_ml(met0, met0->pl, met0->wl,
2187 met1, met1->pl, met1->wl,
2188 tm, x[2], x[0], x[1], &w[i]);
2189 }
2190
2191 /* Get mean wind... */
2192 double k = 1.0;
2193 if (ctl->advect == 2)
2194 k = (i == 0 ? 0.0 : 1.0);
2195 else if (ctl->advect == 4)
2196 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2197 um += k * u[i];
2198 vm += k * v[i];
2199 wm += k * w[i];
2200 }
2201
2202 /* Set new position... */
2203 atm->time[ip] += cache->dt[ip];
2204 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2205 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2206 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2207 atm->p[ip] += cache->dt[ip] * wm;
2208 }
2209 }
2210
2211 /* Use zetadot vertical velocity... */
2212 else if (ctl->advect_vert_coord == 1) {
2213
2214 /* Loop over particles... */
2215 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2216
2217 /* Convert pressure to zeta... */
2219 intpol_met_4d_coord(met0, met0->pl, met0->zetal, met1,
2220 met1->pl, met1->zetal, atm->time[ip], atm->p[ip],
2221 atm->lon[ip], atm->lat[ip],
2222 &atm->q[ctl->qnt_zeta][ip], ci, cw, 1);
2223
2224 /* Init... */
2225 double dts, u[4], um = 0, v[4], vm = 0, zeta_dot[4],
2226 zeta_dotm = 0, x[3] = { 0, 0, 0 };
2227
2228 /* Loop over integration nodes... */
2229 for (int i = 0; i < ctl->advect; i++) {
2230
2231 /* Set position... */
2232 if (i == 0) {
2233 dts = 0.0;
2234 x[0] = atm->lon[ip];
2235 x[1] = atm->lat[ip];
2236 x[2] = atm->q[ctl->qnt_zeta][ip];
2237 } else {
2238 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2239 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2240 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2241 x[2] = atm->q[ctl->qnt_zeta][ip] + dts * zeta_dot[i - 1];
2242 }
2243 const double tm = atm->time[ip] + dts;
2244
2245 /* Interpolate meteo data... */
2246 intpol_met_4d_coord(met0, met0->zetal, met0->ul, met1, met1->zetal,
2247 met1->ul, tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2248 intpol_met_4d_coord(met0, met0->zetal, met0->vl, met1, met1->zetal,
2249 met1->vl, tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2250 intpol_met_4d_coord(met0, met0->zetal, met0->zeta_dotl, met1,
2251 met1->zetal, met1->zeta_dotl, tm, x[2], x[0],
2252 x[1], &zeta_dot[i], ci, cw, 0);
2253
2254 /* Get mean wind... */
2255 double k = 1.0;
2256 if (ctl->advect == 2)
2257 k = (i == 0 ? 0.0 : 1.0);
2258 else if (ctl->advect == 4)
2259 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2260 um += k * u[i];
2261 vm += k * v[i];
2262 zeta_dotm += k * zeta_dot[i];
2263 }
2264
2265 /* Set new position... */
2266 atm->time[ip] += cache->dt[ip];
2267 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2268 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2269 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2270 atm->q[ctl->qnt_zeta][ip] += cache->dt[ip] * zeta_dotm;
2271
2272 /* Convert zeta to pressure... */
2273 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2274 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2275 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2276 }
2277 }
2278}
2279
2280/*****************************************************************************/
2281
2283 const ctl_t *ctl,
2284 const cache_t *cache,
2285 met_t *met0,
2286 met_t *met1,
2287 atm_t *atm) {
2288
2289 /* Check parameters... */
2290 if (ctl->advect_vert_coord != 1)
2291 return;
2292
2293 /* Set timer... */
2294 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS", NVTX_GPU);
2295
2296 /* Loop over particles... */
2297 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
2298
2299 /* Initialize pressure consistent with zeta... */
2301 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2302 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2303 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2304 }
2305}
2306
2307/*****************************************************************************/
2308
2310 const ctl_t *ctl,
2311 const cache_t *cache,
2312 const clim_t *clim,
2313 met_t *met0,
2314 met_t *met1,
2315 atm_t *atm) {
2316
2317 /* Set timer... */
2318 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS", NVTX_GPU);
2319
2320 /* Check quantity flags... */
2321 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2322 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2323 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2324 return;
2325
2326 /* Loop over particles... */
2327 PARTICLE_LOOP(0, atm->np, 1,
2328 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2329
2330 /* Check latitude and pressure range... */
2331 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2332 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2333 continue;
2334
2335 /* Check surface layer... */
2336 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2337 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2338
2339 /* Get surface pressure... */
2340 double ps;
2342 INTPOL_2D(ps, 1);
2343
2344 /* Check pressure... */
2345 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2346 continue;
2347
2348 /* Check height... */
2349 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2350 continue;
2351
2352 /* Check zeta range... */
2353 if (ctl->bound_zetas > 0) {
2354 double t;
2355 INTPOL_3D(t, 1);
2356 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2357 continue;
2358 }
2359
2360 /* Check planetary boundary layer... */
2361 if (ctl->bound_pbl) {
2362 double pbl;
2363 INTPOL_2D(pbl, 0);
2364 if (atm->p[ip] < pbl)
2365 continue;
2366 }
2367 }
2368
2369 /* Set mass and volume mixing ratio... */
2370 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2371 atm->q[ctl->qnt_m][ip] =
2372 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2373 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2374 atm->q[ctl->qnt_vmr][ip] =
2375 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2376
2377 /* Set CFC-10 volume mixing ratio... */
2378 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2379 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2380
2381 /* Set CFC-11 volume mixing ratio... */
2382 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2383 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2384
2385 /* Set CFC-12 volume mixing ratio... */
2386 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2387 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2388
2389 /* Set N2O volume mixing ratio... */
2390 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2391 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2392
2393 /* Set SF6 volume mixing ratio... */
2394 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2395 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2396
2397 /* Set age of air... */
2398 if (ctl->qnt_aoa >= 0)
2399 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2400 }
2401}
2402
2403/*****************************************************************************/
2404
2406 const ctl_t *ctl,
2407 met_t *met0,
2408 met_t *met1,
2409 atm_t *atm,
2410 const double tt) {
2411
2412 /* Check quantities... */
2413 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
2414 return;
2415 if (ctl->molmass <= 0)
2416 ERRMSG("Molar mass is not defined!");
2417
2418 /* Set timer... */
2419 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS", NVTX_GPU);
2420
2421 /* Allocate... */
2422 const int np = atm->np;
2423 const int nz = ctl->chemgrid_nz;
2424 const int nx = ctl->chemgrid_nx;
2425 const int ny = ctl->chemgrid_ny;
2426 const int ngrid = nx * ny * nz;
2427
2428 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2429 double *restrict const press =
2430 (double *) malloc((size_t) nz * sizeof(double));
2431 double *restrict const mass =
2432 (double *) calloc((size_t) ngrid, sizeof(double));
2433 double *restrict const area =
2434 (double *) malloc((size_t) ny * sizeof(double));
2435 double *restrict const lon =
2436 (double *) malloc((size_t) nx * sizeof(double));
2437 double *restrict const lat =
2438 (double *) malloc((size_t) ny * sizeof(double));
2439
2440 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2441 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2442 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2443
2444 /* Set grid box size... */
2445 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2446 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2447 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2448
2449 /* Set vertical coordinates... */
2450#ifdef _OPENACC
2451#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np],z[0:nz],press[0:nz],mass[0:ngrid],area[0:ny],lon[0:nx],lat[0:ny])
2452#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2453#pragma acc parallel loop independent gang vector
2454#else
2455#pragma omp parallel for default(shared)
2456#endif
2457 for (int iz = 0; iz < nz; iz++) {
2458 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2459 press[iz] = P(z[iz]);
2460 }
2461
2462 /* Set time interval for output... */
2463 const double t0 = tt - 0.5 * ctl->dt_mod;
2464 const double t1 = tt + 0.5 * ctl->dt_mod;
2465
2466 /* Get indices... */
2467#ifdef _OPENACC
2468#pragma acc parallel loop independent gang vector
2469#else
2470#pragma omp parallel for default(shared)
2471#endif
2472 for (int ip = 0; ip < np; ip++) {
2473 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2474 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2475 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2476 if (atm->time[ip] < t0 || atm->time[ip] > t1
2477 || ixs[ip] < 0 || ixs[ip] >= nx
2478 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2479 izs[ip] = -1;
2480 }
2481
2482 /* Set horizontal coordinates... */
2483#ifdef _OPENACC
2484#pragma acc parallel loop independent gang vector
2485#else
2486#pragma omp parallel for default(shared)
2487#endif
2488 for (int ix = 0; ix < nx; ix++)
2489 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
2490#ifdef _OPENACC
2491#pragma acc parallel loop independent gang vector
2492#else
2493#pragma omp parallel for default(shared)
2494#endif
2495 for (int iy = 0; iy < ny; iy++) {
2496 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
2497 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
2498 }
2499
2500 /* Get mass per grid box... */
2501#ifdef _OPENACC
2502#pragma acc parallel loop independent gang vector
2503#endif
2504 for (int ip = 0; ip < np; ip++)
2505 if (izs[ip] >= 0)
2506#ifdef _OPENACC
2507#pragma acc atomic update
2508#endif
2509 mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)]
2510 += atm->q[ctl->qnt_m][ip];
2511
2512 /* Assign grid data to air parcels ... */
2513#ifdef _OPENACC
2514#pragma acc parallel loop independent gang vector
2515#else
2516#pragma omp parallel for default(shared)
2517#endif
2518 for (int ip = 0; ip < np; ip++)
2519 if (izs[ip] >= 0) {
2520
2521 /* Interpolate temperature... */
2522 double temp;
2524 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt, press[izs[ip]],
2525 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
2526
2527 /* Set mass... */
2528 const double m = mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)];
2529
2530 /* Calculate volume mixing ratio... */
2531 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
2532 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
2533 }
2534#ifdef _OPENACC
2535#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
2536#endif
2537
2538 /* Free... */
2539 free(mass);
2540 free(lon);
2541 free(lat);
2542 free(area);
2543 free(z);
2544 free(press);
2545 free(ixs);
2546 free(iys);
2547 free(izs);
2548}
2549
2550/*****************************************************************************/
2551
2553 const ctl_t *ctl,
2554 const cache_t *cache,
2555 const clim_t *clim,
2556 met_t *met0,
2557 met_t *met1,
2558 atm_t *atm) {
2559
2560 /* Set timer... */
2561 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS", NVTX_GPU);
2562
2563 /* Loop over particles... */
2564 PARTICLE_LOOP(0, atm->np, 0,
2565 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2566
2567 /* Set H2O and O3 using meteo data... */
2569 if (ctl->qnt_Ch2o >= 0) {
2570 double h2o;
2571 INTPOL_3D(h2o, 1);
2572 SET_ATM(qnt_Ch2o, h2o);
2573 }
2574 if (ctl->qnt_Co3 >= 0) {
2575 double o3;
2576 INTPOL_3D(o3, 1);
2577 SET_ATM(qnt_Co3, o3);
2578 }
2579
2580 /* Set radical species... */
2581 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
2582 atm->lon[ip], atm->lat[ip], atm->p[ip]));
2583 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
2584 atm->lat[ip], atm->p[ip]));
2585 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
2586 atm->lat[ip], atm->p[ip]));
2587 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
2588 atm->lat[ip], atm->p[ip]));
2589 }
2590}
2591
2592/*****************************************************************************/
2593
2595 const ctl_t *ctl,
2596 cache_t *cache,
2597 met_t *met0,
2598 met_t *met1,
2599 atm_t *atm) {
2600
2601 /* Set timer... */
2602 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
2603
2604 /* Create random numbers... */
2605 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
2606
2607 /* Loop over particles... */
2608 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2609
2610 /* Interpolate CAPE... */
2611 double ps;
2613 INTPOL_2D(ps, 1);
2614
2615 /* Initialize pressure range for vertical mixing... */
2616 double pbot = ps, ptop = ps;
2617
2618 /* Mixing in the PBL... */
2619 if (ctl->conv_mix_pbl) {
2620
2621 /* Interpolate PBL... */
2622 double pbl;
2623 INTPOL_2D(pbl, 0);
2624
2625 /* Set pressure range... */
2626 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
2627 }
2628
2629 /* Convective mixing... */
2630 if (ctl->conv_cape >= 0) {
2631
2632 /* Interpolate CAPE, CIN, and equilibrium level... */
2633 double cape, cin, pel;
2634 INTPOL_2D(cape, 0);
2635 INTPOL_2D(cin, 0);
2636 INTPOL_2D(pel, 0);
2637
2638 /* Set pressure range... */
2639 if (isfinite(cape) && cape >= ctl->conv_cape
2640 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
2641 ptop = GSL_MIN(ptop, pel);
2642 }
2643
2644 /* Apply vertical mixing... */
2645 if (ptop != pbot && atm->p[ip] >= ptop) {
2646
2647 /* Get density range... */
2648 double tbot, ttop;
2649 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2650 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
2651 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2652 ptop, atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
2653 const double rhobot = pbot / tbot;
2654 const double rhotop = ptop / ttop;
2655
2656 /* Get new density... */
2657 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
2658
2659 /* Get pressure... */
2660 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
2661 }
2662 }
2663}
2664
2665/*****************************************************************************/
2666
2668 const ctl_t *ctl,
2669 const cache_t *cache,
2670 const clim_t *clim,
2671 atm_t *atm) {
2672
2673 /* Set timer... */
2674 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
2675
2676 /* Check quantity flags... */
2677 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2678 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2679
2680 /* Loop over particles... */
2681 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
2682
2683 /* Get weighting factor... */
2684 const double w = tropo_weight(clim, atm, ip);
2685
2686 /* Set lifetime... */
2687 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
2688
2689 /* Calculate exponential decay... */
2690 const double aux = exp(-cache->dt[ip] / tdec);
2691 if (ctl->qnt_m >= 0) {
2692 if (ctl->qnt_mloss_decay >= 0)
2693 atm->q[ctl->qnt_mloss_decay][ip]
2694 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2695 atm->q[ctl->qnt_m][ip] *= aux;
2696 if (ctl->qnt_loss_rate >= 0)
2697 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
2698 }
2699 if (ctl->qnt_vmr >= 0)
2700 atm->q[ctl->qnt_vmr][ip] *= aux;
2701 }
2702}
2703
2704/*****************************************************************************/
2705
2707 const ctl_t *ctl,
2708 cache_t *cache,
2709 met_t *met0,
2710 met_t *met1,
2711 atm_t *atm) {
2712
2713 /* Set timer... */
2714 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS", NVTX_GPU);
2715
2716 /* Create random numbers... */
2717 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2718
2719 /* Loop over particles... */
2720 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2721
2722 /* Get indices... */
2723 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
2724 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
2725 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
2726
2727 /* Get standard deviations of local wind data... */
2728 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
2729 for (int i = 0; i < 2; i++)
2730 for (int j = 0; j < 2; j++)
2731 for (int k = 0; k < 2; k++) {
2732 umean += met0->u[ix + i][iy + j][iz + k];
2733 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
2734 vmean += met0->v[ix + i][iy + j][iz + k];
2735 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
2736 wmean += met0->w[ix + i][iy + j][iz + k];
2737 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
2738
2739 umean += met1->u[ix + i][iy + j][iz + k];
2740 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
2741 vmean += met1->v[ix + i][iy + j][iz + k];
2742 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
2743 wmean += met1->w[ix + i][iy + j][iz + k];
2744 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
2745 }
2746 usig = usig / 16.f - SQR(umean / 16.f);
2747 usig = (usig > 0 ? sqrtf(usig) : 0);
2748 vsig = vsig / 16.f - SQR(vmean / 16.f);
2749 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
2750 wsig = wsig / 16.f - SQR(wmean / 16.f);
2751 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
2752
2753 /* Set temporal correlations for mesoscale fluctuations... */
2754 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
2755 const double r2 = sqrt(1 - r * r);
2756
2757 /* Calculate horizontal mesoscale wind fluctuations... */
2758 if (ctl->turb_mesox > 0) {
2759 cache->uvwp[ip][0] =
2760 (float) (r * cache->uvwp[ip][0] +
2761 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
2762 atm->lon[ip] +=
2763 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2764
2765 cache->uvwp[ip][1] =
2766 (float) (r * cache->uvwp[ip][1] +
2767 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
2768 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2769 }
2770
2771 /* Calculate vertical mesoscale wind fluctuations... */
2772 if (ctl->turb_mesoz > 0) {
2773 cache->uvwp[ip][2] =
2774 (float) (r * cache->uvwp[ip][2] +
2775 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
2776 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
2777 }
2778 }
2779}
2780
2781/*****************************************************************************/
2782
2784 const ctl_t *ctl,
2785 cache_t *cache,
2786 met_t *met0,
2787 met_t *met1,
2788 atm_t *atm) {
2789
2790 /* Set timer... */
2791 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS", NVTX_GPU);
2792
2793 /* Create random numbers... */
2794 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2795
2796 /* Loop over particles... */
2797 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2798
2799 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
2800 tau_u = 300., tau_w = 100.;
2801
2802 /* Get surface and PBL pressure... */
2803 double pbl, ps;
2805 INTPOL_2D(ps, 1);
2806 INTPOL_2D(pbl, 0);
2807
2808 /* Boundary layer... */
2809 if (atm->p[ip] >= pbl) {
2810
2811 /* Calculate heights... */
2812 const double p = MIN(atm->p[ip], ps);
2813 const double zs = Z(ps);
2814 const double z = 1e3 * (Z(p) - zs);
2815 const double zi = 1e3 * (Z(pbl) - zs);
2816 const double zratio = z / zi;
2817
2818 /* Calculate friction velocity... */
2819 double ess, nss, h2o, t;
2820 INTPOL_2D(ess, 0);
2821 INTPOL_2D(nss, 0);
2822 INTPOL_3D(t, 1);
2823 INTPOL_3D(h2o, 0);
2824 const double rho = RHO(p, TVIRT(t, h2o));
2825 const double tau = sqrt(SQR(ess) + SQR(nss));
2826 const double ustar = sqrt(tau / rho);
2827
2828 /* Get surface sensible heat flux... */
2829 double shf;
2830 INTPOL_2D(shf, 1);
2831
2832 /* Stable or neutral conditions... */
2833 if (shf <= 0) {
2834
2835 /* Calcalute turbulent velocity variances... */
2836 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
2837 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
2838
2839 /* Calculate derivative dsig_w/dz... */
2840 dsigw_dz = -1.3 * ustar / zi;
2841
2842 /* Calcalute Lagrangian timescales... */
2843 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
2844 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
2845 }
2846
2847 /* Unstable conditions... */
2848 else {
2849
2850 /* Convective velocity... */
2851 const double wstar =
2852 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
2853
2854 /* Calcalute turbulent velocity variances... */
2855 sig_u = 1e-2
2856 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
2857 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
2858 * pow(zratio, 2.0 / 3.0)
2859 + (1.8 - 1.4 * zratio) * SQR(ustar));
2860
2861 /* Calculate derivative dsig_w/dz... */
2862 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
2863 * (0.8 *
2864 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
2865 - 1.8 * pow(zratio, 2.0 / 3.0)));
2866
2867 /* Calcalute Lagrangian timescales... */
2868 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
2869 const double eps =
2870 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
2871 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
2872 tau_u = 2 * SQR(sig_u) / (C0 * eps);
2873 tau_w = 2 * SQR(sig_w) / (C0 * eps);
2874 }
2875 }
2876
2877 /* Set minimum values... */
2878 sig_u = MAX(sig_u, 0.25);
2879 sig_w = MAX(sig_w, 0.1);
2880 tau_u = MAX(tau_u, 300.);
2881 tau_w = MAX(tau_w, 100.);
2882
2883 /* Update perturbations... */
2884 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
2885 const double ru2 = sqrt(1.0 - SQR(ru));
2886 cache->uvwp[ip][0]
2887 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
2888 cache->uvwp[ip][1]
2889 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
2890
2891 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
2892 const double rw2 = sqrt(1.0 - SQR(rw));
2893 cache->uvwp[ip][2]
2894 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
2895 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
2896
2897 /* Calculate new air parcel position... */
2898 atm->lon[ip] +=
2899 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2900 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2901 atm->p[ip] +=
2902 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
2903 }
2904}
2905
2906/*****************************************************************************/
2907
2909 const ctl_t *ctl,
2910 cache_t *cache,
2911 const clim_t *clim,
2912 met_t *met0,
2913 met_t *met1,
2914 atm_t *atm) {
2915
2916 /* Set timer... */
2917 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS", NVTX_GPU);
2918
2919 /* Create random numbers... */
2920 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2921
2922 /* Loop over particles... */
2923 PARTICLE_LOOP(0, atm->np, 1,
2924 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2925
2926 /* Get PBL and surface pressure... */
2927 double pbl, ps;
2929 INTPOL_2D(pbl, 1);
2930 INTPOL_2D(ps, 0);
2931
2932 /* Get weighting factors... */
2933 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
2934 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
2935 const double wstrat = 1.0 - wpbl - wtrop;
2936
2937 /* Set diffusivity... */
2938 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
2939 + wstrat * ctl->turb_dx_strat;
2940 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
2941 + wstrat * ctl->turb_dz_strat;
2942
2943 /* Horizontal turbulent diffusion... */
2944 if (dx > 0) {
2945 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
2946 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
2947 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
2948 }
2949
2950 /* Vertical turbulent diffusion... */
2951 if (dz > 0) {
2952 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
2953 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
2954 }
2955 }
2956}
2957
2958/*****************************************************************************/
2959
2961 const ctl_t *ctl,
2962 const cache_t *cache,
2963 met_t *met0,
2964 met_t *met1,
2965 atm_t *atm) {
2966
2967 /* Set timer... */
2968 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS", NVTX_GPU);
2969
2970 /* Check quantity flags... */
2971 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2972 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2973
2974 /* Loop over particles... */
2975 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2976
2977 /* Get surface pressure... */
2978 double ps;
2980 INTPOL_2D(ps, 1);
2981
2982 /* Check whether particle is above the surface layer... */
2983 if (atm->p[ip] < ps - ctl->dry_depo_dp)
2984 continue;
2985
2986 /* Set depth of surface layer... */
2987 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
2988
2989 /* Calculate sedimentation velocity for particles... */
2990 double v_dep;
2991 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
2992
2993 /* Get temperature... */
2994 double t;
2995 INTPOL_3D(t, 1);
2996
2997 /* Set deposition velocity... */
2998 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
2999 atm->q[ctl->qnt_rhop][ip]);
3000 }
3001
3002 /* Use explicit sedimentation velocity for gases... */
3003 else
3004 v_dep = ctl->dry_depo_vdep;
3005
3006 /* Calculate loss of mass based on deposition velocity... */
3007 const double aux = exp(-cache->dt[ip] * v_dep / dz);
3008 if (ctl->qnt_m >= 0) {
3009 if (ctl->qnt_mloss_dry >= 0)
3010 atm->q[ctl->qnt_mloss_dry][ip]
3011 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3012 atm->q[ctl->qnt_m][ip] *= aux;
3013 if (ctl->qnt_loss_rate >= 0)
3014 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
3015 }
3016 if (ctl->qnt_vmr >= 0)
3017 atm->q[ctl->qnt_vmr][ip] *= aux;
3018 }
3019}
3020
3021/*****************************************************************************/
3022
3024 const ctl_t *ctl,
3025 const cache_t *cache,
3026 const clim_t *clim,
3027 met_t *met0,
3028 met_t *met1,
3029 atm_t *atm) {
3030
3031 /* Set timer... */
3032 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS", NVTX_GPU);
3033
3034 /* Check quantity flags... */
3035 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3036 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3037
3038 /* Parameter of SO2 correction... */
3039 const double a = 3.12541941e-06;
3040 const double b = -5.72532259e-01;
3041 const double low = pow(1. / a, 1. / b);
3042
3043 /* Loop over particles... */
3044 PARTICLE_LOOP(0, atm->np, 1,
3045 "acc data present(ctl,cache,ctl,met0,met1,atm)") {
3046
3047 /* Check whether particle is inside cloud... */
3048 double lwc, rwc;
3050 INTPOL_3D(lwc, 1);
3051 INTPOL_3D(rwc, 0);
3052 if (!(lwc > 0 || rwc > 0))
3053 continue;
3054
3055 /* Get temperature... */
3056 double t;
3057 INTPOL_3D(t, 0);
3058
3059 /* Get molecular density... */
3060 const double M = MOLEC_DENS(atm->p[ip], t);
3061
3062 /* Reaction rate (Berglen et al., 2004)... */
3063 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3064
3065 /* Henry constant of SO2... */
3066 const double H_SO2 =
3067 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3068 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3069
3070 /* Henry constant of H2O2... */
3071 const double H_h2o2 =
3072 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3073
3074 /* Correction factor for high SO2 concentration
3075 (if qnt_Cx is defined, the correction is switched on)... */
3076 double cor = 1.0;
3077 if (ctl->qnt_Cx >= 0)
3078 cor = atm->q[ctl->qnt_Cx][ip] >
3079 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3080
3081 const double h2o2 = H_h2o2
3082 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3083 * M * cor * 1000. / AVO; /* unit: mol/L */
3084
3085 /* Volume water content in cloud [m^3 m^(-3)]... */
3086 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3087 const double CWC = (lwc + rwc) * rho_air / 1e3;
3088
3089 /* Calculate exponential decay (Rolph et al., 1992)... */
3090 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3091 const double aux = exp(-cache->dt[ip] * rate_coef);
3092 if (ctl->qnt_m >= 0) {
3093 if (ctl->qnt_mloss_h2o2 >= 0)
3094 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3095 atm->q[ctl->qnt_m][ip] *= aux;
3096 if (ctl->qnt_loss_rate >= 0)
3097 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3098 }
3099 if (ctl->qnt_vmr >= 0)
3100 atm->q[ctl->qnt_vmr][ip] *= aux;
3101 }
3102}
3103
3104/*****************************************************************************/
3105
3107 const ctl_t *ctl,
3108 cache_t *cache,
3109 met_t *met0,
3110 met_t *met1,
3111 atm_t *atm) {
3112
3113 double t;
3114
3115 /* Set timer... */
3116 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS", NVTX_GPU);
3117
3118 /* Save pressure... */
3119 if (ctl->isosurf == 1) {
3120 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
3121 cache->iso_var[ip] = atm->p[ip];
3122 }
3123 }
3124
3125 /* Save density... */
3126 else if (ctl->isosurf == 2) {
3127 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3129 INTPOL_3D(t, 1);
3130 cache->iso_var[ip] = atm->p[ip] / t;
3131 }
3132 }
3133
3134 /* Save potential temperature... */
3135 else if (ctl->isosurf == 3) {
3136 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3138 INTPOL_3D(t, 1);
3139 cache->iso_var[ip] = THETA(atm->p[ip], t);
3140 }
3141 }
3142
3143 /* Read balloon pressure data... */
3144 else if (ctl->isosurf == 4) {
3145
3146 /* Write info... */
3147 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3148
3149 /* Open file... */
3150 FILE *in;
3151 if (!(in = fopen(ctl->balloon, "r")))
3152 ERRMSG("Cannot open file!");
3153
3154 /* Read pressure time series... */
3155 char line[LEN];
3156 while (fgets(line, LEN, in))
3157 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3158 &(cache->iso_ps[cache->iso_n])) == 2)
3159 if ((++cache->iso_n) > NP)
3160 ERRMSG("Too many data points!");
3161
3162 /* Check number of points... */
3163 if (cache->iso_n < 1)
3164 ERRMSG("Could not read any data!");
3165
3166 /* Close file... */
3167 fclose(in);
3168
3169 /* Update of cache data on device... */
3170 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
3171 }
3172}
3173
3174/*****************************************************************************/
3175
3177 const ctl_t *ctl,
3178 const cache_t *cache,
3179 met_t *met0,
3180 met_t *met1,
3181 atm_t *atm) {
3182
3183 /* Set timer... */
3184 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3185
3186 /* Loop over particles... */
3187 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
3188
3189 /* Init... */
3190 double t;
3192
3193 /* Restore pressure... */
3194 if (ctl->isosurf == 1)
3195 atm->p[ip] = cache->iso_var[ip];
3196
3197 /* Restore density... */
3198 else if (ctl->isosurf == 2) {
3199 INTPOL_3D(t, 1);
3200 atm->p[ip] = cache->iso_var[ip] * t;
3201 }
3202
3203 /* Restore potential temperature... */
3204 else if (ctl->isosurf == 3) {
3205 INTPOL_3D(t, 1);
3206 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3207 }
3208
3209 /* Interpolate pressure... */
3210 else if (ctl->isosurf == 4) {
3211 if (atm->time[ip] <= cache->iso_ts[0])
3212 atm->p[ip] = cache->iso_ps[0];
3213 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3214 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3215 else {
3216 int idx = locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3217 atm->p[ip] = LIN(cache->iso_ts[idx], cache->iso_ps[idx],
3218 cache->iso_ts[idx + 1], cache->iso_ps[idx + 1],
3219 atm->time[ip]);
3220 }
3221 }
3222 }
3223}
3224
3225/*****************************************************************************/
3226
3227#ifdef KPP
3228void module_kpp_chem(
3229 ctl_t *ctl,
3230 cache_t *cache,
3231 clim_t *clim,
3232 met_t *met0,
3233 met_t *met1,
3234 atm_t *atm) {
3235
3236 /* Set timer... */
3237 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS", NVTX_GPU);
3238
3239 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
3240 double rtol[1] = { 1.0e-3 };
3241 double atol[1] = { 1.0 };
3242
3243 /* Loop over particles... */
3244#ifdef _OPENACC
3245#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
3246#endif
3247 PARTICLE_LOOP(0, atm->np, 1,
3248 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
3249
3250 /* Initialize... */
3251 double var[nvar], fix[nfix], rconst[nreact];
3252 for (int i = 0; i < nvar; i++)
3253 var[i] = 0.0;
3254 for (int i = 0; i < nfix; i++)
3255 fix[i] = 0.0;
3256 for (int i = 0; i < nreact; i++)
3257 rconst[i] = 0.0;
3258 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
3259
3260 /* Integrate... */
3261 double rpar[20];
3262 int ipar[20];
3263 for (int i = 0; i < 20; i++) {
3264 ipar[i] = 0;
3265 rpar[i] = 0.0;
3266 }
3267 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) */
3268 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
3269 ipar[3] = 4; /* choice of the method:Rodas3 */
3270 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
3271 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
3272
3273 /* Save results.. */
3274 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
3275 }
3276}
3277#endif
3278
3279/*****************************************************************************/
3280
3282 const ctl_t *ctl,
3283 const cache_t *cache,
3284 const clim_t *clim,
3285 met_t *met0,
3286 met_t *met1,
3287 atm_t *atm) {
3288
3289 /* Set timer... */
3290 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
3291
3292 /* Check quantity flags... */
3293 if (ctl->qnt_tsts >= 0)
3294 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3295 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3296
3297 /* Loop over particles... */
3298 PARTICLE_LOOP(0, atm->np, 0,
3299 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3300
3301 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb, cl,
3302 plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot, o3, lwc,
3303 rwc, iwc, swc, cc, z, zt;
3304
3305 /* Interpolate meteo data... */
3307 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3308
3309 /* Set quantities... */
3310 SET_ATM(qnt_ps, ps);
3311 SET_ATM(qnt_ts, ts);
3312 SET_ATM(qnt_zs, zs);
3313 SET_ATM(qnt_us, us);
3314 SET_ATM(qnt_vs, vs);
3315 SET_ATM(qnt_ess, ess);
3316 SET_ATM(qnt_nss, nss);
3317 SET_ATM(qnt_shf, shf);
3318 SET_ATM(qnt_lsm, lsm);
3319 SET_ATM(qnt_sst, sst);
3320 SET_ATM(qnt_pbl, pbl);
3321 SET_ATM(qnt_pt, pt);
3322 SET_ATM(qnt_tt, tt);
3323 SET_ATM(qnt_zt, zt);
3324 SET_ATM(qnt_h2ot, h2ot);
3325 SET_ATM(qnt_zg, z);
3326 SET_ATM(qnt_p, atm->p[ip]);
3327 SET_ATM(qnt_t, t);
3328 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3329 SET_ATM(qnt_u, u);
3330 SET_ATM(qnt_v, v);
3331 SET_ATM(qnt_w, w);
3332 SET_ATM(qnt_h2o, h2o);
3333 SET_ATM(qnt_o3, o3);
3334 SET_ATM(qnt_lwc, lwc);
3335 SET_ATM(qnt_rwc, rwc);
3336 SET_ATM(qnt_iwc, iwc);
3337 SET_ATM(qnt_swc, swc);
3338 SET_ATM(qnt_cc, cc);
3339 SET_ATM(qnt_pct, pct);
3340 SET_ATM(qnt_pcb, pcb);
3341 SET_ATM(qnt_cl, cl);
3342 SET_ATM(qnt_plcl, plcl);
3343 SET_ATM(qnt_plfc, plfc);
3344 SET_ATM(qnt_pel, pel);
3345 SET_ATM(qnt_cape, cape);
3346 SET_ATM(qnt_cin, cin);
3347 SET_ATM(qnt_o3c, o3c);
3348 SET_ATM(qnt_hno3,
3349 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3350 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3351 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3352 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3353 atm->lat[ip], atm->p[ip]));
3354 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3355 atm->lat[ip], atm->p[ip]));
3356 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3357 atm->lat[ip], atm->p[ip]));
3358 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3359 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3360 SET_ATM(qnt_psat, PSAT(t));
3361 SET_ATM(qnt_psice, PSICE(t));
3362 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3363 SET_ATM(qnt_sh, SH(h2o));
3364 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3365 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3366 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3367 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3368 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3369 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3370 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3371 SET_ATM(qnt_pv, pv);
3372 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3373 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3374 SET_ATM(qnt_tnat,
3375 nat_temperature(atm->p[ip], h2o,
3376 clim_zm(&clim->hno3, atm->time[ip],
3377 atm->lat[ip], atm->p[ip])));
3378 SET_ATM(qnt_tsts,
3379 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3380 }
3381}
3382
3383/*****************************************************************************/
3384
3386 const ctl_t *ctl,
3387 const clim_t *clim,
3388 atm_t *atm,
3389 const double t) {
3390
3391 /* Set timer... */
3392 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
3393
3394 /* Allocate... */
3395 const int np = atm->np;
3396 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3397 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3398 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3399
3400 /* Set grid box size... */
3401 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3402 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3403 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3404
3405 /* Set time interval... */
3406 const double t0 = t - 0.5 * ctl->dt_mod;
3407 const double t1 = t + 0.5 * ctl->dt_mod;
3408
3409 /* Get indices... */
3410#ifdef _OPENACC
3411#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3412#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3413#pragma acc parallel loop independent gang vector
3414#else
3415#pragma omp parallel for default(shared)
3416#endif
3417 for (int ip = 0; ip < np; ip++) {
3418 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3419 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3420 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3421 if (atm->time[ip] < t0 || atm->time[ip] > t1
3422 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3423 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3424 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3425 izs[ip] = -1;
3426 }
3427
3428 /* Calculate interparcel mixing... */
3429 if (ctl->qnt_m >= 0)
3430 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_m);
3431 if (ctl->qnt_vmr >= 0)
3432 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_vmr);
3433 if (ctl->qnt_Ch2o >= 0)
3434 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o);
3435 if (ctl->qnt_Co3 >= 0)
3436 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3);
3437 if (ctl->qnt_Cco >= 0)
3438 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cco);
3439 if (ctl->qnt_Coh >= 0)
3440 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Coh);
3441 if (ctl->qnt_Ch >= 0)
3442 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch);
3443 if (ctl->qnt_Cho2 >= 0)
3444 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cho2);
3445 if (ctl->qnt_Ch2o2 >= 0)
3446 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o2);
3447 if (ctl->qnt_Co1d >= 0)
3448 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co1d);
3449 if (ctl->qnt_Co3p >= 0)
3450 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3p);
3451 if (ctl->qnt_Cccl4 >= 0)
3452 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl4);
3453 if (ctl->qnt_Cccl3f >= 0)
3454 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl3f);
3455 if (ctl->qnt_Cccl2f2 >= 0)
3456 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl2f2);
3457 if (ctl->qnt_Cn2o >= 0)
3458 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cn2o);
3459 if (ctl->qnt_Csf6 >= 0)
3460 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Csf6);
3461 if (ctl->qnt_aoa >= 0)
3462 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_aoa);
3463
3464 /* Free... */
3465#ifdef _OPENACC
3466#pragma acc exit data delete(ixs,iys,izs)
3467#endif
3468 free(ixs);
3469 free(iys);
3470 free(izs);
3471}
3472
3473/*****************************************************************************/
3474
3476 const ctl_t *ctl,
3477 const clim_t *clim,
3478 atm_t *atm,
3479 const int *ixs,
3480 const int *iys,
3481 const int *izs,
3482 const int qnt_idx) {
3483
3484 /* Allocate... */
3485 const int np = atm->np;
3486 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
3487 double *restrict const cmean =
3488 (double *) malloc((size_t) ngrid * sizeof(double));
3489 int *restrict const count = (int *) malloc((size_t) ngrid * sizeof(int));
3490
3491 /* Init... */
3492#ifdef _OPENACC
3493#pragma acc enter data create(cmean[0:ngrid],count[0:ngrid])
3494#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
3495#pragma acc parallel loop independent gang vector
3496#else
3497#ifdef __NVCOMPILER
3498#pragma novector
3499#endif
3500#pragma omp parallel for
3501#endif
3502 for (int i = 0; i < ngrid; i++) {
3503 count[i] = 0;
3504 cmean[i] = 0;
3505 }
3506
3507 /* Loop over particles... */
3508#ifdef _OPENACC
3509#pragma acc parallel loop independent gang vector
3510#endif
3511 for (int ip = 0; ip < np; ip++)
3512 if (izs[ip] >= 0) {
3513 int idx = ARRAY_3D
3514 (ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz);
3515#ifdef _OPENACC
3516#pragma acc atomic update
3517#endif
3518 cmean[idx] += atm->q[qnt_idx][ip];
3519#ifdef _OPENACC
3520#pragma acc atomic update
3521#endif
3522 count[idx]++;
3523 }
3524#ifdef _OPENACC
3525#pragma acc parallel loop independent gang vector
3526#else
3527#ifdef __NVCOMPILER
3528#pragma novector
3529#endif
3530#pragma omp parallel for
3531#endif
3532 for (int i = 0; i < ngrid; i++)
3533 if (count[i] > 0)
3534 cmean[i] /= count[i];
3535
3536 /* Calculate interparcel mixing... */
3537#ifdef _OPENACC
3538#pragma acc parallel loop independent gang vector
3539#else
3540#pragma omp parallel for
3541#endif
3542 for (int ip = 0; ip < np; ip++)
3543 if (izs[ip] >= 0) {
3544
3545 /* Set mixing parameter... */
3546 double mixparam = 1.0;
3547 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
3548 double w = tropo_weight(clim, atm, ip);
3549 mixparam = w * ctl->mixing_trop + (1 - w) * ctl->mixing_strat;
3550 }
3551
3552 /* Adjust quantity... */
3553 atm->q[qnt_idx][ip] +=
3554 (cmean
3555 [ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz)]
3556 - atm->q[qnt_idx][ip]) * mixparam;
3557 }
3558
3559 /* Free... */
3560#ifdef _OPENACC
3561#pragma acc exit data delete(cmean,count)
3562#endif
3563 free(cmean);
3564 free(count);
3565}
3566
3567/*****************************************************************************/
3568
3570 const ctl_t *ctl,
3571 const cache_t *cache,
3572 const clim_t *clim,
3573 met_t *met0,
3574 met_t *met1,
3575 atm_t *atm) {
3576
3577 /* Set timer... */
3578 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS", NVTX_GPU);
3579
3580 /* Check quantity flags... */
3581 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3582 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3583
3584 /* Parameter of SO2 correction... */
3585 const double a = 4.71572206e-08;
3586 const double b = -8.28782867e-01;
3587 const double low = pow(1. / a, 1. / b);
3588
3589 /* Loop over particles... */
3590 PARTICLE_LOOP(0, atm->np, 1,
3591 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3592
3593 /* Get temperature... */
3594 double t;
3596 INTPOL_3D(t, 1);
3597
3598 /* Calculate molecular density... */
3599 const double M = MOLEC_DENS(atm->p[ip], t);
3600
3601 /* Use constant reaction rate... */
3602 double k = NAN;
3603 if (ctl->oh_chem_reaction == 1)
3604 k = ctl->oh_chem[0];
3605
3606 /* Calculate bimolecular reaction rate... */
3607 else if (ctl->oh_chem_reaction == 2)
3608 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
3609
3610 /* Calculate termolecular reaction rate... */
3611 if (ctl->oh_chem_reaction == 3) {
3612
3613 /* Calculate rate coefficient for X + OH + M -> XOH + M
3614 (JPL Publication 19-05) ... */
3615 const double k0 =
3616 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
3617 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
3618 const double ki =
3619 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
3620 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
3621 const double c = log10(k0 * M / ki);
3622 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
3623 }
3624
3625 /* Correction factor for high SO2 concentration
3626 (if qnt_Cx is defined, the correction is switched on)... */
3627 double cor = 1;
3628 if (ctl->qnt_Cx >= 0)
3629 cor =
3630 atm->q[ctl->qnt_Cx][ip] >
3631 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3632
3633 /* Calculate exponential decay... */
3634 const double rate_coef =
3635 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
3636 atm->lat[ip], atm->p[ip]) * M * cor;
3637 const double aux = exp(-cache->dt[ip] * rate_coef);
3638 if (ctl->qnt_m >= 0) {
3639 if (ctl->qnt_mloss_oh >= 0)
3640 atm->q[ctl->qnt_mloss_oh][ip]
3641 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3642 atm->q[ctl->qnt_m][ip] *= aux;
3643 if (ctl->qnt_loss_rate >= 0)
3644 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3645 }
3646 if (ctl->qnt_vmr >= 0)
3647 atm->q[ctl->qnt_vmr][ip] *= aux;
3648 }
3649}
3650
3651/*****************************************************************************/
3652
3654 const cache_t *cache,
3655 met_t *met0,
3656 met_t *met1,
3657 atm_t *atm) {
3658
3659 /* Set timer... */
3660 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
3661
3662 /* Loop over particles... */
3663 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
3664
3665 /* Init... */
3666 double ps;
3668
3669 /* Calculate modulo... */
3670 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
3671 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
3672
3673 /* Check latitude... */
3674 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
3675 if (atm->lat[ip] > 90) {
3676 atm->lat[ip] = 180 - atm->lat[ip];
3677 atm->lon[ip] += 180;
3678 }
3679 if (atm->lat[ip] < -90) {
3680 atm->lat[ip] = -180 - atm->lat[ip];
3681 atm->lon[ip] += 180;
3682 }
3683 }
3684
3685 /* Check longitude... */
3686 while (atm->lon[ip] < -180)
3687 atm->lon[ip] += 360;
3688 while (atm->lon[ip] >= 180)
3689 atm->lon[ip] -= 360;
3690
3691 /* Check pressure... */
3692 if (atm->p[ip] < met0->p[met0->np - 1]) {
3693 atm->p[ip] = met0->p[met0->np - 1];
3694 } else if (atm->p[ip] > 300.) {
3695 INTPOL_2D(ps, 1);
3696 if (atm->p[ip] > ps)
3697 atm->p[ip] = ps;
3698 }
3699 }
3700}
3701
3702/*****************************************************************************/
3703
3705 const int ntask) {
3706
3707 /* Initialize GSL random number generators... */
3708 gsl_rng_env_setup();
3709 if (omp_get_max_threads() > NTHREADS)
3710 ERRMSG("Too many threads!");
3711 for (int i = 0; i < NTHREADS; i++) {
3712 rng[i] = gsl_rng_alloc(gsl_rng_default);
3713 gsl_rng_set(rng[i], gsl_rng_default_seed
3714 + (long unsigned) (ntask * NTHREADS + i));
3715 }
3716
3717 /* Initialize cuRAND random number generators... */
3718#ifdef CURAND
3719 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
3720 CURAND_STATUS_SUCCESS)
3721 ERRMSG("Cannot create random number generator!");
3722 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
3723 CURAND_STATUS_SUCCESS)
3724 ERRMSG("Cannot set seed for random number generator!");
3725 if (curandSetStream
3726 (rng_curand,
3727 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
3728 CURAND_STATUS_SUCCESS)
3729 ERRMSG("Cannot set stream for random number generator!");
3730#endif
3731}
3732
3733/*****************************************************************************/
3734
3736 const ctl_t *ctl,
3737 double *rs,
3738 const size_t n,
3739 const int method) {
3740
3741 /* Use GSL random number generators... */
3742 if (ctl->rng_type == 0) {
3743
3744 /* Uniform distribution... */
3745 if (method == 0) {
3746#pragma omp parallel for default(shared)
3747 for (size_t i = 0; i < n; ++i)
3748 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
3749 }
3750
3751 /* Normal distribution... */
3752 else if (method == 1) {
3753#pragma omp parallel for default(shared)
3754 for (size_t i = 0; i < n; ++i)
3755 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
3756 }
3757
3758 /* Update of random numbers on device... */
3759#ifdef _OPENACC
3760 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
3761#pragma acc update device(rs[:n])
3762#endif
3763 }
3764
3765 /* Use Squares random number generator (Widynski, 2022)... */
3766 else if (ctl->rng_type == 1) {
3767
3768 /* Set key (don't change this!)... */
3769 const uint64_t key = 0xc8e4fd154ce32f6d;
3770
3771 /* Uniform distribution... */
3772#ifdef _OPENACC
3773#pragma acc data present(rs)
3774#pragma acc parallel loop independent gang vector
3775#else
3776#pragma omp parallel for default(shared)
3777#endif
3778 for (size_t i = 0; i < n + 1; ++i) {
3779 uint64_t r, t, x, y, z;
3780 y = x = (rng_ctr + i) * key;
3781 z = y + key;
3782 x = x * x + y;
3783 x = (x >> 32) | (x << 32);
3784 x = x * x + z;
3785 x = (x >> 32) | (x << 32);
3786 x = x * x + y;
3787 x = (x >> 32) | (x << 32);
3788 t = x = x * x + z;
3789 x = (x >> 32) | (x << 32);
3790 r = t ^ ((x * x + y) >> 32);
3791 rs[i] = (double) r / (double) UINT64_MAX;
3792 }
3793 rng_ctr += n + 1;
3794
3795 /* Normal distribution... */
3796 if (method == 1) {
3797#ifdef _OPENACC
3798#pragma acc parallel loop independent gang vector
3799#else
3800#pragma omp parallel for default(shared)
3801#endif
3802 for (size_t i = 0; i < n; i += 2) {
3803 const double r = sqrt(-2.0 * log(rs[i]));
3804 const double phi = 2.0 * M_PI * rs[i + 1];
3805 rs[i] = r * cosf((float) phi);
3806 rs[i + 1] = r * sinf((float) phi);
3807 }
3808 }
3809 }
3810
3811 /* Use cuRAND random number generators... */
3812 else if (ctl->rng_type == 2) {
3813#ifdef CURAND
3814#pragma acc host_data use_device(rs)
3815 {
3816
3817 /* Uniform distribution... */
3818 if (method == 0) {
3819 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
3820 CURAND_STATUS_SUCCESS)
3821 ERRMSG("Cannot create random numbers!");
3822 }
3823
3824 /* Normal distribution... */
3825 else if (method == 1) {
3826 if (curandGenerateNormalDouble
3827 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
3828 1.0) != CURAND_STATUS_SUCCESS)
3829 ERRMSG("Cannot create random numbers!");
3830 }
3831 }
3832#else
3833 ERRMSG("MPTRAC was compiled without cuRAND!");
3834#endif
3835 }
3836}
3837
3838/*****************************************************************************/
3839
3841 const ctl_t *ctl,
3842 const cache_t *cache,
3843 met_t *met0,
3844 met_t *met1,
3845 atm_t *atm) {
3846
3847 /* Set timer... */
3848 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
3849
3850 /* Loop over particles... */
3851 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3852
3853 /* Get temperature... */
3854 double t;
3856 INTPOL_3D(t, 1);
3857
3858 /* Sedimentation velocity... */
3859 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3860 atm->q[ctl->qnt_rhop][ip]);
3861
3862 /* Calculate pressure change... */
3863 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
3864 }
3865}
3866
3867/*****************************************************************************/
3868
3870 const ctl_t *ctl,
3871 met_t *met0,
3872 atm_t *atm) {
3873
3874 /* Set timer... */
3875 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
3876
3877 /* Allocate... */
3878 const int np = atm->np;
3879 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
3880 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
3881
3882#ifdef _OPENACC
3883#pragma acc enter data create(a[0:np],p[0:np])
3884#pragma acc data present(ctl,met0,atm,a,p)
3885#endif
3886
3887 /* Get box index... */
3888#ifdef _OPENACC
3889#pragma acc parallel loop independent gang vector
3890#else
3891#pragma omp parallel for default(shared)
3892#endif
3893 for (int ip = 0; ip < np; ip++) {
3894 a[ip] =
3895 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
3896 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
3897 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
3898 p[ip] = ip;
3899 }
3900
3901 /* Sorting... */
3902#ifdef _OPENACC
3903#pragma acc host_data use_device(a,p)
3904#endif
3905#ifdef THRUST
3906 thrustSortWrapper(a, np, p);
3907#else
3908 ERRMSG("MPTRAC was compiled without Thrust library!");
3909#endif
3910
3911 /* Sort data... */
3912 module_sort_help(atm->time, p, np);
3913 module_sort_help(atm->p, p, np);
3914 module_sort_help(atm->lon, p, np);
3915 module_sort_help(atm->lat, p, np);
3916 for (int iq = 0; iq < ctl->nq; iq++)
3917 module_sort_help(atm->q[iq], p, np);
3918
3919 /* Free... */
3920#ifdef _OPENACC
3921#pragma acc exit data delete(a,p)
3922#endif
3923 free(a);
3924 free(p);
3925}
3926
3927/*****************************************************************************/
3928
3930 double *a,
3931 const int *p,
3932 const int np) {
3933
3934 /* Allocate... */
3935 double *restrict const help =
3936 (double *) malloc((size_t) np * sizeof(double));
3937
3938 /* Reordering of array... */
3939#ifdef _OPENACC
3940#pragma acc enter data create(help[0:np])
3941#pragma acc data present(a,p,help)
3942#pragma acc parallel loop independent gang vector
3943#else
3944#pragma omp parallel for default(shared)
3945#endif
3946 for (int ip = 0; ip < np; ip++)
3947 help[ip] = a[p[ip]];
3948#ifdef _OPENACC
3949#pragma acc parallel loop independent gang vector
3950#else
3951#pragma omp parallel for default(shared)
3952#endif
3953 for (int ip = 0; ip < np; ip++)
3954 a[ip] = help[ip];
3955
3956 /* Free... */
3957#ifdef _OPENACC
3958#pragma acc exit data delete(help)
3959#endif
3960 free(help);
3961}
3962
3963/*****************************************************************************/
3964
3966 const ctl_t *ctl,
3967 cache_t *cache,
3968 met_t *met0,
3969 atm_t *atm,
3970 const double t) {
3971
3972 /* Set timer... */
3973 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
3974
3975 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
3976 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
3977
3978 const int local =
3979 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
3980
3981 /* Loop over particles... */
3982 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
3983
3984 /* Set time step for each air parcel... */
3985 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
3986 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
3987 && ctl->direction * (atm->time[ip] - t) < 0))
3988 cache->dt[ip] = t - atm->time[ip];
3989 else
3990 cache->dt[ip] = 0.0;
3991
3992 /* Check horizontal boundaries of local meteo data... */
3993 if (local && (atm->lon[ip] <= met0->lon[0]
3994 || atm->lon[ip] >= met0->lon[met0->nx - 1]
3995 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
3996 cache->dt[ip] = 0.0;
3997 }
3998}
3999
4000/*****************************************************************************/
4001
4003 ctl_t *ctl,
4004 const atm_t *atm) {
4005
4006 /* Set timer... */
4007 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS", NVTX_GPU);
4008
4009 /* Set start time... */
4010 if (ctl->direction == 1) {
4011 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4012 if (ctl->t_stop > 1e99)
4013 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4014 } else {
4015 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4016 if (ctl->t_stop > 1e99)
4017 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4018 }
4019
4020 /* Check time interval... */
4021 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
4022 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
4023
4024 /* Round start time... */
4025 if (ctl->direction == 1)
4026 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4027 else
4028 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4029}
4030
4031/*****************************************************************************/
4032
4034 const ctl_t *ctl,
4035 const cache_t *cache,
4036 const clim_t *clim,
4037 met_t *met0,
4038 met_t *met1,
4039 atm_t *atm) {
4040
4041 /* Set timer... */
4042 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS", NVTX_GPU);
4043
4044 /* Loop over particles... */
4045 PARTICLE_LOOP(0, atm->np, 1,
4046 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4047
4048 /* Get temperature... */
4049 double t;
4051 INTPOL_3D(t, 1);
4052
4053 /* Get molecular density... */
4054 const double M = MOLEC_DENS(atm->p[ip], t);
4055
4056 /* Get total column ozone... */
4057 double o3c;
4058 INTPOL_2D(o3c, 1);
4059
4060 /* Get solar zenith angle... */
4061 const double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
4062
4063 /* Get O(1D) volume mixing ratio... */
4064 const double o1d =
4065 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4066
4067 /* Reactions for CFC-10... */
4068 if (ctl->qnt_Cccl4 >= 0) {
4069 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4070 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4071 atm->p[ip], sza, o3c);
4072 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4073 }
4074
4075 /* Reactions for CFC-11... */
4076 if (ctl->qnt_Cccl3f >= 0) {
4077 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4078 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4079 atm->p[ip], sza, o3c);
4080 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4081 }
4082
4083 /* Reactions for CFC-12... */
4084 if (ctl->qnt_Cccl2f2 >= 0) {
4085 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4086 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4087 atm->p[ip], sza, o3c);
4088 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4089 }
4090
4091 /* Reactions for N2O... */
4092 if (ctl->qnt_Cn2o >= 0) {
4093 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4094 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4095 atm->p[ip], sza, o3c);
4096 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4097 }
4098 }
4099}
4100
4101/*****************************************************************************/
4102
4104 const ctl_t *ctl,
4105 const cache_t *cache,
4106 met_t *met0,
4107 met_t *met1,
4108 atm_t *atm) {
4109
4110 /* Set timer... */
4111 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS", NVTX_GPU);
4112
4113 /* Check quantity flags... */
4114 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4115 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4116
4117 /* Loop over particles... */
4118 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4119
4120 /* Check whether particle is below cloud top... */
4121 double pct;
4123 INTPOL_2D(pct, 1);
4124 if (!isfinite(pct) || atm->p[ip] <= pct)
4125 continue;
4126
4127 /* Get cloud bottom pressure... */
4128 double pcb;
4129 INTPOL_2D(pcb, 0);
4130
4131 /* Estimate precipitation rate (Pisso et al., 2019)... */
4132 double cl;
4133 INTPOL_2D(cl, 0);
4134 const double Is =
4135 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4136 if (Is < 0.01)
4137 continue;
4138
4139 /* Check whether particle is inside or below cloud... */
4140 double lwc, rwc, iwc, swc;
4141 INTPOL_3D(lwc, 1);
4142 INTPOL_3D(rwc, 0);
4143 INTPOL_3D(iwc, 0);
4144 INTPOL_3D(swc, 0);
4145 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4146
4147 /* Get temperature... */
4148 double t;
4149 INTPOL_3D(t, 0);
4150
4151 /* Calculate in-cloud scavenging coefficient... */
4152 double lambda = 0;
4153 if (inside) {
4154
4155 /* Calculate retention factor... */
4156 double eta;
4157 if (t > 273.15)
4158 eta = 1;
4159 else if (t <= 238.15)
4160 eta = ctl->wet_depo_ic_ret_ratio;
4161 else
4162 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4163
4164 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4165 if (ctl->wet_depo_ic_a > 0)
4166 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4167
4168 /* Use Henry's law for gases... */
4169 else if (ctl->wet_depo_ic_h[0] > 0) {
4170
4171 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4172 double h = ctl->wet_depo_ic_h[0]
4173 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4174
4175 /* Use effective Henry's constant for SO2
4176 (Berglen, 2004; Simpson, 2012)... */
4177 if (ctl->wet_depo_so2_ph > 0) {
4178 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
4179 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4180 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4181 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
4182 }
4183
4184 /* Estimate depth of cloud layer... */
4185 const double dz = 1e3 * (Z(pct) - Z(pcb));
4186
4187 /* Calculate scavenging coefficient... */
4188 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4189 }
4190 }
4191
4192 /* Calculate below-cloud scavenging coefficient... */
4193 else {
4194
4195 /* Calculate retention factor... */
4196 double eta;
4197 if (t > 270)
4198 eta = 1;
4199 else
4200 eta = ctl->wet_depo_bc_ret_ratio;
4201
4202 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4203 if (ctl->wet_depo_bc_a > 0)
4204 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4205
4206 /* Use Henry's law for gases... */
4207 else if (ctl->wet_depo_bc_h[0] > 0) {
4208
4209 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4210 const double h = ctl->wet_depo_bc_h[0]
4211 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4212
4213 /* Estimate depth of cloud layer... */
4214 const double dz = 1e3 * (Z(pct) - Z(pcb));
4215
4216 /* Calculate scavenging coefficient... */
4217 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4218 }
4219 }
4220
4221 /* Calculate exponential decay of mass... */
4222 const double aux = exp(-cache->dt[ip] * lambda);
4223 if (ctl->qnt_m >= 0) {
4224 if (ctl->qnt_mloss_wet >= 0)
4225 atm->q[ctl->qnt_mloss_wet][ip]
4226 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4227 atm->q[ctl->qnt_m][ip] *= aux;
4228 if (ctl->qnt_loss_rate >= 0)
4229 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4230 }
4231 if (ctl->qnt_vmr >= 0)
4232 atm->q[ctl->qnt_vmr][ip] *= aux;
4233 }
4234}
4235
4236/*****************************************************************************/
4237
4239 ctl_t **ctl,
4240 cache_t **cache,
4241 clim_t **clim,
4242 met_t **met0,
4243 met_t **met1,
4244 atm_t **atm) {
4245
4246 /* Initialize GPU... */
4247#ifdef _OPENACC
4248 SELECT_TIMER("ACC_INIT", "INIT", NVTX_GPU);
4249 int rank = 0;
4250#ifdef MPI
4251 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
4252#endif
4253 if (acc_get_num_devices(acc_device_nvidia) <= 0)
4254 ERRMSG("Not running on a GPU device!");
4255 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
4256 acc_device_nvidia);
4257 acc_device_t device_type = acc_get_device_type();
4258 acc_init(device_type);
4259#endif
4260
4261 /* Allocate... */
4262 SELECT_TIMER("ALLOC", "MEMORY", NVTX_CPU);
4263 ALLOC(*ctl, ctl_t, 1);
4264 ALLOC(*cache, cache_t, 1);
4265 ALLOC(*clim, clim_t, 1);
4266 ALLOC(*met0, met_t, 1);
4267 ALLOC(*met1, met_t, 1);
4268 ALLOC(*atm, atm_t, 1);
4269
4270 /* Create data region on GPU... */
4271#ifdef _OPENACC
4272 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY", NVTX_GPU);
4273 ctl_t *ctlup = *ctl;
4274 cache_t *cacheup = *cache;
4275 clim_t *climup = *clim;
4276 met_t *met0up = *met0;
4277 met_t *met1up = *met1;
4278 atm_t *atmup = *atm;
4279#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
4280#endif
4281}
4282
4283/*****************************************************************************/
4284
4286 ctl_t *ctl,
4287 cache_t *cache,
4288 clim_t *clim,
4289 met_t *met0,
4290 met_t *met1,
4291 atm_t *atm) {
4292
4293 /* Delete data region on GPU... */
4294#ifdef _OPENACC
4295 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY", NVTX_GPU);
4296#pragma acc exit data delete (ctl,cache,clim,met0,met1,atm)
4297#endif
4298
4299 /* Free... */
4300 SELECT_TIMER("FREE", "MEMORY", NVTX_CPU);
4301 free(atm);
4302 free(ctl);
4303 free(cache);
4304 free(clim);
4305 free(met0);
4306 free(met1);
4307}
4308
4309/*****************************************************************************/
4310
4312 ctl_t *ctl,
4313 clim_t *clim,
4314 const double t,
4315 met_t **met0,
4316 met_t **met1) {
4317
4318 static int init;
4319
4320 met_t *mets;
4321
4322 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
4323
4324 /* Set timer... */
4325 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4326
4327 /* Init... */
4328 if (t == ctl->t_start || !init) {
4329 init = 1;
4330
4331 /* Read meteo data... */
4332 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
4333 ctl->metbase, ctl->dt_met, filename);
4334 if (!mptrac_read_met(filename, ctl, clim, *met0))
4335 ERRMSG("Cannot open file!");
4336
4337 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
4338 ctl->metbase, ctl->dt_met, filename);
4339 if (!mptrac_read_met(filename, ctl, clim, *met1))
4340 ERRMSG("Cannot open file!");
4341
4342 /* Update GPU... */
4343 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
4344 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4345
4346 /* Caching... */
4347 if (ctl->met_cache && t != ctl->t_stop) {
4348 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
4349 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
4350 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4351 LOG(1, "Caching: %s", cachefile);
4352 if (system(cmd) != 0)
4353 WARN("Caching command failed!");
4354 }
4355 }
4356
4357 /* Read new data for forward trajectories... */
4358 if (t > (*met1)->time) {
4359
4360 /* Pointer swap... */
4361 mets = *met1;
4362 *met1 = *met0;
4363 *met0 = mets;
4364
4365 /* Read new meteo data... */
4366 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
4367 if (!mptrac_read_met(filename, ctl, clim, *met1))
4368 ERRMSG("Cannot open file!");
4369
4370 /* Update GPU... */
4371 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
4372 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4373
4374 /* Caching... */
4375 if (ctl->met_cache && t != ctl->t_stop) {
4376 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
4377 cachefile);
4378 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4379 LOG(1, "Caching: %s", cachefile);
4380 if (system(cmd) != 0)
4381 WARN("Caching command failed!");
4382 }
4383 }
4384
4385 /* Read new data for backward trajectories... */
4386 if (t < (*met0)->time) {
4387
4388 /* Pointer swap... */
4389 mets = *met1;
4390 *met1 = *met0;
4391 *met0 = mets;
4392
4393 /* Read new meteo data... */
4394 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
4395 if (!mptrac_read_met(filename, ctl, clim, *met0))
4396 ERRMSG("Cannot open file!");
4397
4398 /* Update GPU... */
4399 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
4400 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4401
4402 /* Caching... */
4403 if (ctl->met_cache && t != ctl->t_stop) {
4404 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
4405 cachefile);
4406 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4407 LOG(1, "Caching: %s", cachefile);
4408 if (system(cmd) != 0)
4409 WARN("Caching command failed!");
4410 }
4411 }
4412
4413 /* Check that grids are consistent... */
4414 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
4415 if ((*met0)->nx != (*met1)->nx
4416 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
4417 ERRMSG("Meteo grid dimensions do not match!");
4418 for (int ix = 0; ix < (*met0)->nx; ix++)
4419 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
4420 ERRMSG("Meteo grid longitudes do not match!");
4421 for (int iy = 0; iy < (*met0)->ny; iy++)
4422 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
4423 ERRMSG("Meteo grid latitudes do not match!");
4424 for (int ip = 0; ip < (*met0)->np; ip++)
4425 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
4426 ERRMSG("Meteo grid pressure levels do not match!");
4427 }
4428}
4429
4430/*****************************************************************************/
4431
4433 ctl_t *ctl,
4434 cache_t *cache,
4435 clim_t *clim,
4436 atm_t *atm,
4437 const int ntask) {
4438
4439 /* Initialize timesteps... */
4440 module_timesteps_init(ctl, atm);
4441
4442 /* Initialize random number generator... */
4443 module_rng_init(ntask);
4444
4445 /* Update GPU memory... */
4446 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
4447}
4448
4449/*****************************************************************************/
4450
4452 const char *filename,
4453 const ctl_t *ctl,
4454 atm_t *atm) {
4455
4456 int result;
4457
4458 /* Set timer... */
4459 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
4460
4461 /* Init... */
4462 atm->np = 0;
4463
4464 /* Write info... */
4465 LOG(1, "Read atmospheric data: %s", filename);
4466
4467 /* Read ASCII data... */
4468 if (ctl->atm_type == 0)
4469 result = read_atm_asc(filename, ctl, atm);
4470
4471 /* Read binary data... */
4472 else if (ctl->atm_type == 1)
4473 result = read_atm_bin(filename, ctl, atm);
4474
4475 /* Read netCDF data... */
4476 else if (ctl->atm_type == 2)
4477 result = read_atm_nc(filename, ctl, atm);
4478
4479 /* Read CLaMS data... */
4480 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
4481 result = read_atm_clams(filename, ctl, atm);
4482
4483 /* Error... */
4484 else
4485 ERRMSG("Atmospheric data type not supported!");
4486
4487 /* Check result... */
4488 if (result != 1)
4489 return 0;
4490
4491 /* Check number of air parcels... */
4492 if (atm->np < 1)
4493 ERRMSG("Can not read any data!");
4494
4495 /* Write info... */
4496 double mini, maxi;
4497 LOG(2, "Number of particles: %d", atm->np);
4498 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
4499 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
4500 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
4501 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
4502 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
4503 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
4504 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
4505 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
4506 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
4507 for (int iq = 0; iq < ctl->nq; iq++) {
4508 char msg[5 * LEN];
4509 sprintf(msg, "Quantity %s range: %s ... %s %s",
4510 ctl->qnt_name[iq], ctl->qnt_format[iq],
4511 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
4512 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
4513 LOG(2, msg, mini, maxi);
4514 }
4515
4516 /* Return success... */
4517 return 1;
4518}
4519
4520/*****************************************************************************/
4521
4523 const ctl_t *ctl,
4524 clim_t *clim) {
4525
4526 /* Set timer... */
4527 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
4528
4529 /* Init tropopause climatology... */
4530 clim_tropo_init(clim);
4531
4532 /* Read photolysis rates... */
4533 if (ctl->clim_photo[0] != '-')
4534 read_clim_photo(ctl->clim_photo, &clim->photo);
4535
4536 /* Read HNO3 climatology... */
4537 if (ctl->clim_hno3_filename[0] != '-')
4538 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
4539
4540 /* Read OH climatology... */
4541 if (ctl->clim_oh_filename[0] != '-') {
4542 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
4543 if (ctl->oh_chem_beta > 0)
4544 clim_oh_diurnal_correction(ctl, clim);
4545 }
4546
4547 /* Read H2O2 climatology... */
4548 if (ctl->clim_h2o2_filename[0] != '-')
4549 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
4550
4551 /* Read HO2 climatology... */
4552 if (ctl->clim_ho2_filename[0] != '-')
4553 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
4554
4555 /* Read O(1D) climatology... */
4556 if (ctl->clim_o1d_filename[0] != '-')
4557 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
4558
4559 /* Read CFC-10 time series... */
4560 if (ctl->clim_ccl4_timeseries[0] != '-')
4562
4563 /* Read CFC-11 time series... */
4564 if (ctl->clim_ccl3f_timeseries[0] != '-')
4566
4567 /* Read CFC-12 time series... */
4568 if (ctl->clim_ccl2f2_timeseries[0] != '-')
4570
4571 /* Read N2O time series... */
4572 if (ctl->clim_n2o_timeseries[0] != '-')
4573 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
4574
4575 /* Read SF6 time series... */
4576 if (ctl->clim_sf6_timeseries[0] != '-')
4577 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
4578}
4579
4580/*****************************************************************************/
4581
4583 const char *filename,
4584 int argc,
4585 char *argv[],
4586 ctl_t *ctl) {
4587
4588 /* Set timer... */
4589 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
4590
4591 /* Write info... */
4592 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
4593 "(executable: %s | version: %s | compiled: %s, %s)\n",
4594 argv[0], VERSION, __DATE__, __TIME__);
4595
4596 /* Initialize quantity indices... */
4597 ctl->qnt_idx = -1;
4598 ctl->qnt_ens = -1;
4599 ctl->qnt_stat = -1;
4600 ctl->qnt_m = -1;
4601 ctl->qnt_vmr = -1;
4602 ctl->qnt_rp = -1;
4603 ctl->qnt_rhop = -1;
4604 ctl->qnt_ps = -1;
4605 ctl->qnt_ts = -1;
4606 ctl->qnt_zs = -1;
4607 ctl->qnt_us = -1;
4608 ctl->qnt_vs = -1;
4609 ctl->qnt_ess = -1;
4610 ctl->qnt_nss = -1;
4611 ctl->qnt_shf = -1;
4612 ctl->qnt_lsm = -1;
4613 ctl->qnt_sst = -1;
4614 ctl->qnt_pbl = -1;
4615 ctl->qnt_pt = -1;
4616 ctl->qnt_tt = -1;
4617 ctl->qnt_zt = -1;
4618 ctl->qnt_h2ot = -1;
4619 ctl->qnt_zg = -1;
4620 ctl->qnt_p = -1;
4621 ctl->qnt_t = -1;
4622 ctl->qnt_rho = -1;
4623 ctl->qnt_u = -1;
4624 ctl->qnt_v = -1;
4625 ctl->qnt_w = -1;
4626 ctl->qnt_h2o = -1;
4627 ctl->qnt_o3 = -1;
4628 ctl->qnt_lwc = -1;
4629 ctl->qnt_rwc = -1;
4630 ctl->qnt_iwc = -1;
4631 ctl->qnt_swc = -1;
4632 ctl->qnt_cc = -1;
4633 ctl->qnt_pct = -1;
4634 ctl->qnt_pcb = -1;
4635 ctl->qnt_cl = -1;
4636 ctl->qnt_plcl = -1;
4637 ctl->qnt_plfc = -1;
4638 ctl->qnt_pel = -1;
4639 ctl->qnt_cape = -1;
4640 ctl->qnt_cin = -1;
4641 ctl->qnt_o3c = -1;
4642 ctl->qnt_hno3 = -1;
4643 ctl->qnt_oh = -1;
4644 ctl->qnt_h2o2 = -1;
4645 ctl->qnt_ho2 = -1;
4646 ctl->qnt_o1d = -1;
4647 ctl->qnt_mloss_oh = -1;
4648 ctl->qnt_mloss_h2o2 = -1;
4649 ctl->qnt_mloss_kpp = -1;
4650 ctl->qnt_mloss_wet = -1;
4651 ctl->qnt_mloss_dry = -1;
4652 ctl->qnt_mloss_decay = -1;
4653 ctl->qnt_loss_rate = -1;
4654 ctl->qnt_psat = -1;
4655 ctl->qnt_psice = -1;
4656 ctl->qnt_pw = -1;
4657 ctl->qnt_sh = -1;
4658 ctl->qnt_rh = -1;
4659 ctl->qnt_rhice = -1;
4660 ctl->qnt_theta = -1;
4661 ctl->qnt_zeta = -1;
4662 ctl->qnt_zeta_d = -1;
4663 ctl->qnt_tvirt = -1;
4664 ctl->qnt_lapse = -1;
4665 ctl->qnt_vh = -1;
4666 ctl->qnt_vz = -1;
4667 ctl->qnt_pv = -1;
4668 ctl->qnt_tdew = -1;
4669 ctl->qnt_tice = -1;
4670 ctl->qnt_tsts = -1;
4671 ctl->qnt_tnat = -1;
4672 ctl->qnt_Cx = -1;
4673 ctl->qnt_Ch2o = -1;
4674 ctl->qnt_Co3 = -1;
4675 ctl->qnt_Cco = -1;
4676 ctl->qnt_Coh = -1;
4677 ctl->qnt_Ch = -1;
4678 ctl->qnt_Cho2 = -1;
4679 ctl->qnt_Ch2o2 = -1;
4680 ctl->qnt_Co1d = -1;
4681 ctl->qnt_Co3p = -1;
4682 ctl->qnt_Cccl4 = -1;
4683 ctl->qnt_Cccl3f = -1;
4684 ctl->qnt_Cccl2f2 = -1;
4685 ctl->qnt_Cn2o = -1;
4686 ctl->qnt_Csf6 = -1;
4687 ctl->qnt_aoa = -1;
4688
4689 /* Read quantities... */
4690 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
4691 if (ctl->nq > NQ)
4692 ERRMSG("Too many quantities!");
4693 for (int iq = 0; iq < ctl->nq; iq++) {
4694
4695 /* Read quantity name and format... */
4696 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
4697 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
4698 ctl->qnt_longname[iq]);
4699 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
4700 ctl->qnt_format[iq]);
4701 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
4702 sprintf(ctl->qnt_format[iq], "%%.2f");
4703
4704 /* Try to identify quantity... */
4705 SET_QNT(qnt_idx, "idx", "particle index", "-")
4706 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
4707 SET_QNT(qnt_stat, "stat", "station flag", "-")
4708 SET_QNT(qnt_m, "m", "mass", "kg")
4709 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
4710 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
4711 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
4712 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
4713 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
4714 SET_QNT(qnt_zs, "zs", "surface height", "km")
4715 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
4716 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
4717 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
4718 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
4719 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
4720 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
4721 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
4722 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
4723 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
4724 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
4725 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
4726 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
4727 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
4728 SET_QNT(qnt_p, "p", "pressure", "hPa")
4729 SET_QNT(qnt_t, "t", "temperature", "K")
4730 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
4731 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
4732 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
4733 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
4734 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
4735 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
4736 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
4737 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
4738 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
4739 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
4740 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
4741 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
4742 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
4743 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
4744 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
4745 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
4746 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
4747 SET_QNT(qnt_cape, "cape", "convective available potential energy",
4748 "J/kg")
4749 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
4750 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
4751 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
4752 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
4753 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
4754 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
4755 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
4756 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
4757 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2", "mass loss due to H2O2 chemistry",
4758 "kg")
4759 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
4760 "kg")
4761 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
4762 "kg")
4763 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
4764 "kg")
4765 SET_QNT(qnt_mloss_decay, "mloss_decay",
4766 "mass loss due to exponential decay", "kg")
4767 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
4768 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
4769 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
4770 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
4771 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
4772 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
4773 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
4774 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
4775 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
4776 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
4777 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
4778 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
4779 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
4780 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
4781 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
4782 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
4783 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
4784 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
4785 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
4786 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
4787 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
4788 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
4789 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
4790 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
4791 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
4792 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
4793 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
4794 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
4795 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
4796 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
4797 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
4798 "ppv")
4799 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
4800 "ppv")
4801 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
4802 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
4803 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
4804 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
4805 }
4806
4807 /* Vertical coordinates and velocities... */
4808 ctl->advect_vert_coord =
4809 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
4810 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 2)
4811 ERRMSG("Set ADVECT_VERT_COORD to 0, 1, or 2!");
4812 ctl->met_vert_coord =
4813 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
4814 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
4815 ERRMSG("Set MET_VERT_COORD to 0, 1, 2, 3, or 4!");
4816 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
4817 ERRMSG("Please add zeta to your quantities for diabatic calculations!");
4818 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
4819 ERRMSG
4820 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
4821
4822 /* Time steps of simulation... */
4823 ctl->direction =
4824 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
4825 if (ctl->direction != -1 && ctl->direction != 1)
4826 ERRMSG("Set DIRECTION to -1 or 1!");
4827 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
4828 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
4829
4830 /* Meteo data... */
4831 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
4832 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
4833 ctl->met_convention =
4834 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
4835 ctl->met_type =
4836 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
4837 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
4838 ERRMSG
4839 ("Please use meteo files in netcdf format for diabatic calculations.");
4840 ctl->met_clams =
4841 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
4842 ctl->met_nc_scale =
4843 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
4844 ctl->met_nc_level =
4845 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
4846 ctl->met_nc_quant =
4847 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
4848 ctl->met_zstd_level =
4849 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
4850 ctl->met_zfp_prec =
4851 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", -1, "8", NULL);
4852 ctl->met_zfp_tol_t =
4853 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_T", -1, "5.0", NULL);
4854 ctl->met_zfp_tol_z =
4855 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_Z", -1, "0.5", NULL);
4856 ctl->met_cms_batch =
4857 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
4858 ctl->met_cms_zstd =
4859 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
4860 ctl->met_cms_heur =
4861 (int) scan_ctl(filename, argc, argv, "MET_CMS_HEUR", -1, "1", NULL);
4862 ctl->met_cms_eps_z =
4863 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
4864 ctl->met_cms_eps_t =
4865 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
4866 ctl->met_cms_eps_u =
4867 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
4868 ctl->met_cms_eps_v =
4869 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
4870 ctl->met_cms_eps_w =
4871 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
4872 ctl->met_cms_eps_pv =
4873 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
4874 ctl->met_cms_eps_h2o =
4875 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
4876 ctl->met_cms_eps_o3 =
4877 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
4878 ctl->met_cms_eps_lwc =
4879 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
4880 ctl->met_cms_eps_rwc =
4881 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
4882 ctl->met_cms_eps_iwc =
4883 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
4884 ctl->met_cms_eps_swc =
4885 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
4886 ctl->met_cms_eps_cc =
4887 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
4888 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
4889 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
4890 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
4891 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
4892 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
4893 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
4894 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
4895 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
4896 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
4897 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
4898 ctl->met_detrend =
4899 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
4900 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
4901 if (ctl->met_np > EP)
4902 ERRMSG("Too many pressure levels!");
4903 ctl->met_press_level_def =
4904 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
4905 NULL);
4906 if (ctl->met_press_level_def >= 0) {
4907 level_definitions(ctl);
4908 } else {
4909 if (ctl->met_np > 0) {
4910 for (int ip = 0; ip < ctl->met_np; ip++)
4911 ctl->met_p[ip] =
4912 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
4913 }
4914 }
4915 ctl->met_nlev =
4916 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
4917 if (ctl->met_nlev > EP)
4918 ERRMSG("Too many model levels!");
4919 for (int ip = 0; ip < ctl->met_nlev; ip++) {
4920 ctl->met_lev_hyam[ip] =
4921 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
4922 ctl->met_lev_hybm[ip] =
4923 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
4924 }
4925 ctl->met_geopot_sx =
4926 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
4927 ctl->met_geopot_sy =
4928 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
4929 ctl->met_relhum =
4930 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
4931 ctl->met_cape =
4932 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
4933 if (ctl->met_cape < 0 || ctl->met_cape > 1)
4934 ERRMSG("Set MET_CAPE to 0 or 1!");
4935 ctl->met_pbl =
4936 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
4937 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
4938 ERRMSG("Set MET_PBL to 0 ... 3!");
4939 ctl->met_pbl_min =
4940 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
4941 ctl->met_pbl_max =
4942 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
4943 ctl->met_tropo =
4944 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
4945 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
4946 ERRMSG("Set MET_TROPO to 0 ... 5!");
4947 ctl->met_tropo_pv =
4948 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
4949 ctl->met_tropo_theta =
4950 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
4951 ctl->met_tropo_spline =
4952 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
4953 ctl->met_dt_out =
4954 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
4955 ctl->met_cache =
4956 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
4957 ctl->met_mpi_share =
4958 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
4959
4960 /* Sorting... */
4961 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
4962
4963 /* Isosurface parameters... */
4964 ctl->isosurf =
4965 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
4966 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
4967
4968 /* Random number generator... */
4969 ctl->rng_type =
4970 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
4971 if (ctl->rng_type < 0 || ctl->rng_type > 2)
4972 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
4973
4974 /* Advection parameters... */
4975 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
4976 if (!(ctl->advect == 0 || ctl->advect == 1
4977 || ctl->advect == 2 || ctl->advect == 4))
4978 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
4979
4980 /* Diffusion parameters... */
4981 ctl->diffusion
4982 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
4983 if (ctl->diffusion < 0 || ctl->diffusion > 2)
4984 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
4985 ctl->turb_dx_pbl =
4986 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
4987 ctl->turb_dx_trop =
4988 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
4989 ctl->turb_dx_strat =
4990 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
4991 ctl->turb_dz_pbl =
4992 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
4993 ctl->turb_dz_trop =
4994 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
4995 ctl->turb_dz_strat =
4996 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
4997 ctl->turb_mesox =
4998 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
4999 ctl->turb_mesoz =
5000 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5001
5002 /* Convection... */
5003 ctl->conv_mix_pbl
5004 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
5005 ctl->conv_pbl_trans
5006 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
5007 ctl->conv_cape
5008 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5009 ctl->conv_cin
5010 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5011 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5012
5013 /* Boundary conditions... */
5014 ctl->bound_mass =
5015 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5016 ctl->bound_mass_trend =
5017 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5018 ctl->bound_vmr =
5019 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5020 ctl->bound_vmr_trend =
5021 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5022 ctl->bound_lat0 =
5023 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5024 ctl->bound_lat1 =
5025 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5026 ctl->bound_p0 =
5027 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5028 ctl->bound_p1 =
5029 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5030 ctl->bound_dps =
5031 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5032 ctl->bound_dzs =
5033 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
5034 ctl->bound_zetas =
5035 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
5036 ctl->bound_pbl =
5037 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
5038
5039 /* Species parameters... */
5040 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
5041 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
5042 ctl->molmass = 120.907;
5043 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
5044 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5045 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5046 ctl->molmass = 137.359;
5047 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5048 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5049 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5050 ctl->molmass = 16.043;
5051 ctl->oh_chem_reaction = 2;
5052 ctl->oh_chem[0] = 2.45e-12;
5053 ctl->oh_chem[1] = 1775;
5054 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5055 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5056 } else if (strcasecmp(ctl->species, "CO") == 0) {
5057 ctl->molmass = 28.01;
5058 ctl->oh_chem_reaction = 3;
5059 ctl->oh_chem[0] = 6.9e-33;
5060 ctl->oh_chem[1] = 2.1;
5061 ctl->oh_chem[2] = 1.1e-12;
5062 ctl->oh_chem[3] = -1.3;
5063 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5064 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5065 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5066 ctl->molmass = 44.009;
5067 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5068 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5069 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5070 ctl->molmass = 18.01528;
5071 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5072 ctl->molmass = 44.013;
5073 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5074 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5075 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5076 ctl->molmass = 17.031;
5077 ctl->oh_chem_reaction = 2;
5078 ctl->oh_chem[0] = 1.7e-12;
5079 ctl->oh_chem[1] = 710;
5080 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
5081 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
5082 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
5083 ctl->molmass = 63.012;
5084 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
5085 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
5086 } else if (strcasecmp(ctl->species, "NO") == 0) {
5087 ctl->molmass = 30.006;
5088 ctl->oh_chem_reaction = 3;
5089 ctl->oh_chem[0] = 7.1e-31;
5090 ctl->oh_chem[1] = 2.6;
5091 ctl->oh_chem[2] = 3.6e-11;
5092 ctl->oh_chem[3] = 0.1;
5093 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
5094 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5095 } else if (strcasecmp(ctl->species, "NO2") == 0) {
5096 ctl->molmass = 46.005;
5097 ctl->oh_chem_reaction = 3;
5098 ctl->oh_chem[0] = 1.8e-30;
5099 ctl->oh_chem[1] = 3.0;
5100 ctl->oh_chem[2] = 2.8e-11;
5101 ctl->oh_chem[3] = 0.0;
5102 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
5103 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5104 } else if (strcasecmp(ctl->species, "O3") == 0) {
5105 ctl->molmass = 47.997;
5106 ctl->oh_chem_reaction = 2;
5107 ctl->oh_chem[0] = 1.7e-12;
5108 ctl->oh_chem[1] = 940;
5109 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
5110 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
5111 } else if (strcasecmp(ctl->species, "SF6") == 0) {
5112 ctl->molmass = 146.048;
5113 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
5114 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
5115 } else if (strcasecmp(ctl->species, "SO2") == 0) {
5116 ctl->molmass = 64.066;
5117 ctl->oh_chem_reaction = 3;
5118 ctl->oh_chem[0] = 2.9e-31;
5119 ctl->oh_chem[1] = 4.1;
5120 ctl->oh_chem[2] = 1.7e-12;
5121 ctl->oh_chem[3] = -0.2;
5122 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
5123 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
5124 }
5125
5126 /* Molar mass... */
5127 char defstr[LEN];
5128 sprintf(defstr, "%g", ctl->molmass);
5129 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
5130
5131 /* OH chemistry... */
5132 sprintf(defstr, "%d", ctl->oh_chem_reaction);
5133 ctl->oh_chem_reaction =
5134 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
5135 NULL);
5136 for (int ip = 0; ip < 4; ip++) {
5137 sprintf(defstr, "%g", ctl->oh_chem[ip]);
5138 ctl->oh_chem[ip] =
5139 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
5140 }
5141 ctl->oh_chem_beta =
5142 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
5143
5144 /* H2O2 chemistry... */
5145 ctl->h2o2_chem_reaction =
5146 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
5147
5148 /* KPP chemistry... */
5149 ctl->kpp_chem =
5150 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
5151 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
5152
5153 /* First order tracer chemistry... */
5154 ctl->tracer_chem =
5155 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
5156
5157 /* Wet deposition... */
5158 for (int ip = 0; ip < 2; ip++) {
5159 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
5160 ctl->wet_depo_ic_h[ip] =
5161 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
5162 }
5163 for (int ip = 0; ip < 1; ip++) {
5164 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
5165 ctl->wet_depo_bc_h[ip] =
5166 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
5167 }
5168 ctl->wet_depo_so2_ph =
5169 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
5170 ctl->wet_depo_ic_a =
5171 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
5172 ctl->wet_depo_ic_b =
5173 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
5174 ctl->wet_depo_bc_a =
5175 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
5176 ctl->wet_depo_bc_b =
5177 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
5178 ctl->wet_depo_pre[0] =
5179 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
5180 ctl->wet_depo_pre[1] =
5181 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
5183 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
5185 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
5186
5187 /* Dry deposition... */
5188 ctl->dry_depo_vdep =
5189 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
5190 ctl->dry_depo_dp =
5191 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
5192
5193 /* Climatological data... */
5194 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
5195 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
5196 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
5197 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
5198 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
5199 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
5200 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
5201 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
5202 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
5203 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
5204 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
5205 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
5206 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
5207 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
5208 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
5209 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
5210 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
5211 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
5212 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
5213 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
5214 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
5215 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
5216
5217 /* Mixing... */
5218 ctl->mixing_dt =
5219 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
5220 ctl->mixing_trop =
5221 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
5222 ctl->mixing_strat =
5223 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
5224 ctl->mixing_z0 =
5225 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
5226 ctl->mixing_z1 =
5227 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
5228 ctl->mixing_nz =
5229 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
5230 ctl->mixing_lon0 =
5231 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
5232 ctl->mixing_lon1 =
5233 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
5234 ctl->mixing_nx =
5235 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
5236 ctl->mixing_lat0 =
5237 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
5238 ctl->mixing_lat1 =
5239 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
5240 ctl->mixing_ny =
5241 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
5242
5243 /* Chemistry grid... */
5244 ctl->chemgrid_z0 =
5245 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
5246 ctl->chemgrid_z1 =
5247 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
5248 ctl->chemgrid_nz =
5249 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
5250 ctl->chemgrid_lon0 =
5251 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
5252 ctl->chemgrid_lon1 =
5253 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
5254 ctl->chemgrid_nx =
5255 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
5256 ctl->chemgrid_lat0 =
5257 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
5258 ctl->chemgrid_lat1 =
5259 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
5260 ctl->chemgrid_ny =
5261 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
5262
5263 /* Exponential decay... */
5264 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
5265 ctl->tdec_strat
5266 = scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
5267
5268 /* PSC analysis... */
5269 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
5270 ctl->psc_hno3 =
5271 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
5272
5273 /* Output of atmospheric data... */
5274 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
5275 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
5276 ctl->atm_dt_out =
5277 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
5278 ctl->atm_filter =
5279 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
5280 ctl->atm_stride =
5281 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
5282 ctl->atm_type =
5283 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
5284 ctl->atm_type_out =
5285 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
5286 if (ctl->atm_type_out == -1)
5287 ctl->atm_type_out = ctl->atm_type;
5288 ctl->atm_nc_level =
5289 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
5290 for (int iq = 0; iq < ctl->nq; iq++)
5291 ctl->atm_nc_quant[iq] =
5292 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
5293 ctl->obs_type =
5294 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
5295
5296 /* Output of CSI data... */
5297 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
5298 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
5299 ctl->csi_dt_out =
5300 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
5301 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
5302 ctl->csi_obsmin =
5303 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
5304 ctl->csi_modmin =
5305 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
5306 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
5307 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
5308 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
5309 ctl->csi_lon0 =
5310 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
5311 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
5312 ctl->csi_nx =
5313 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
5314 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
5315 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
5316 ctl->csi_ny =
5317 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
5318
5319 /* Output of ensemble data... */
5320 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
5321 ctl->ens_dt_out =
5322 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
5323
5324 /* Output of grid data... */
5325 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
5326 ctl->grid_basename);
5327 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
5328 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
5329 ctl->grid_dt_out =
5330 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
5331 ctl->grid_sparse =
5332 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
5333 ctl->grid_nc_level =
5334 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
5335 for (int iq = 0; iq < ctl->nq; iq++)
5336 ctl->grid_nc_quant[iq] =
5337 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
5338 ctl->grid_stddev =
5339 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
5340 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
5341 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
5342 ctl->grid_nz =
5343 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
5344 ctl->grid_lon0 =
5345 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
5346 ctl->grid_lon1 =
5347 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
5348 ctl->grid_nx =
5349 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
5350 ctl->grid_lat0 =
5351 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
5352 ctl->grid_lat1 =
5353 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
5354 ctl->grid_ny =
5355 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
5356 ctl->grid_type =
5357 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
5358
5359 /* Output of profile data... */
5360 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
5361 ctl->prof_basename);
5362 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
5363 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
5364 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
5365 ctl->prof_nz =
5366 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
5367 ctl->prof_lon0 =
5368 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
5369 ctl->prof_lon1 =
5370 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
5371 ctl->prof_nx =
5372 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
5373 ctl->prof_lat0 =
5374 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
5375 ctl->prof_lat1 =
5376 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
5377 ctl->prof_ny =
5378 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
5379
5380 /* Output of sample data... */
5381 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
5382 ctl->sample_basename);
5383 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
5384 ctl->sample_kernel);
5385 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
5386 ctl->sample_obsfile);
5387 ctl->sample_dx =
5388 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
5389 ctl->sample_dz =
5390 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
5391
5392 /* Output of station data... */
5393 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
5394 ctl->stat_basename);
5395 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
5396 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
5397 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
5398 ctl->stat_t0 =
5399 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
5400 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
5401
5402 /* Output of VTK data... */
5403 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
5404 ctl->vtk_dt_out =
5405 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
5406 ctl->vtk_stride =
5407 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
5408 ctl->vtk_scale =
5409 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
5410 ctl->vtk_offset =
5411 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
5412 ctl->vtk_sphere =
5413 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
5414}
5415
5416/*****************************************************************************/
5417
5419 const char *filename,
5420 const ctl_t *ctl,
5421 const clim_t *clim,
5422 met_t *met) {
5423
5424 /* Write info... */
5425 LOG(1, "Read meteo data: %s", filename);
5426
5427 /* Set rank... */
5428 int rank = 0;
5429#ifdef MPI
5430 if (ctl->met_mpi_share)
5431 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5432#endif
5433
5434 /* Check rank... */
5435 if (!ctl->met_mpi_share || rank == 0) {
5436
5437 /* Read netCDF data... */
5438 if (ctl->met_type == 0) {
5439 if (read_met_nc(filename, ctl, clim, met) != 1)
5440 return 0;
5441 }
5442
5443 /* Read binary data... */
5444 else if (ctl->met_type >= 1 && ctl->met_type <= 5) {
5445 if (read_met_bin(filename, ctl, met) != 1)
5446 return 0;
5447 }
5448
5449 /* Not implemented... */
5450 else
5451 ERRMSG("MET_TYPE not implemented!");
5452 }
5453
5454 /* Broadcast data via MPI... */
5455#ifdef MPI
5456 if (ctl->met_mpi_share) {
5457
5458 /* Set timer... */
5459 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
5460 LOG(2, "Broadcast data on rank %d...", rank);
5461
5462 /* Broadcast... */
5463 broadcast_large_data(met, sizeof(met_t));
5464 }
5465#endif
5466
5467 /* Return success... */
5468 return 1;
5469}
5470
5471/*****************************************************************************/
5472
5474 ctl_t *ctl,
5475 cache_t *cache,
5476 clim_t *clim,
5477 met_t **met0,
5478 met_t **met1,
5479 atm_t *atm,
5480 double t) {
5481
5482 /* Initialize modules... */
5483 if (t == ctl->t_start) {
5484
5485 /* Initialize isosurface data... */
5486 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5487 module_isosurf_init(ctl, cache, *met0, *met1, atm);
5488
5489 /* Initialize advection... */
5490 module_advect_init(ctl, cache, *met0, *met1, atm);
5491
5492 /* Initialize chemistry... */
5493 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
5494 }
5495
5496 /* Set time steps of air parcels... */
5497 module_timesteps(ctl, cache, *met0, atm, t);
5498
5499 /* Sort particles... */
5500 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
5501 module_sort(ctl, *met0, atm);
5502
5503 /* Check positions (initial)... */
5504 module_position(cache, *met0, *met1, atm);
5505
5506 /* Advection... */
5507 if (ctl->advect > 0)
5508 module_advect(ctl, cache, *met0, *met1, atm);
5509
5510 /* Turbulent diffusion... */
5511 if (ctl->diffusion == 1
5512 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
5513 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
5514 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
5515 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
5516
5517 /* Mesoscale diffusion... */
5518 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
5519 module_diff_meso(ctl, cache, *met0, *met1, atm);
5520
5521 /* Diffusion... */
5522 if (ctl->diffusion == 2)
5523 module_diff_pbl(ctl, cache, *met0, *met1, atm);
5524
5525 /* Convection... */
5526 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
5527 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
5528 module_convection(ctl, cache, *met0, *met1, atm);
5529
5530 /* Sedimentation... */
5531 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
5532 module_sedi(ctl, cache, *met0, *met1, atm);
5533
5534 /* Isosurface... */
5535 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5536 module_isosurf(ctl, cache, *met0, *met1, atm);
5537
5538 /* Check positions (final)... */
5539 module_position(cache, *met0, *met1, atm);
5540
5541 /* Interpolate meteo data... */
5542 if (ctl->met_dt_out > 0
5543 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
5544 module_meteo(ctl, cache, clim, *met0, *met1, atm);
5545
5546 /* Check boundary conditions (initial)... */
5547 if ((ctl->bound_lat0 < ctl->bound_lat1)
5548 && (ctl->bound_p0 > ctl->bound_p1))
5549 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5550
5551 /* Initialize quantity of total loss rate... */
5552 if (ctl->qnt_loss_rate >= 0) {
5553 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
5554 atm->q[ctl->qnt_loss_rate][ip] = 0;
5555 }
5556 }
5557
5558 /* Decay of particle mass... */
5559 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
5560 module_decay(ctl, cache, clim, atm);
5561
5562 /* Interparcel mixing... */
5563 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
5564 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
5565 module_mixing(ctl, clim, atm, t);
5566
5567 /* Calculate the tracer vmr in the chemistry grid... */
5568 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
5569 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
5570 module_chem_grid(ctl, *met0, *met1, atm, t);
5571
5572 /* OH chemistry... */
5573 if (ctl->oh_chem_reaction != 0)
5574 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
5575
5576 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
5577 if (ctl->h2o2_chem_reaction != 0)
5578 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
5579
5580 /* First-order tracer chemistry... */
5581 if (ctl->tracer_chem)
5582 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
5583
5584 /* KPP chemistry... */
5585 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
5586#ifdef KPP
5587 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
5588#else
5589 ERRMSG("Code was compiled without KPP!");
5590#endif
5591 }
5592
5593 /* Wet deposition... */
5594 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
5595 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
5596 module_wet_depo(ctl, cache, *met0, *met1, atm);
5597
5598 /* Dry deposition... */
5599 if (ctl->dry_depo_vdep > 0)
5600 module_dry_depo(ctl, cache, *met0, *met1, atm);
5601
5602 /* Check boundary conditions (final)... */
5603 if ((ctl->bound_lat0 < ctl->bound_lat1)
5604 && (ctl->bound_p0 > ctl->bound_p1))
5605 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5606}
5607
5608/*****************************************************************************/
5609
5611 const ctl_t *ctl,
5612 const cache_t *cache,
5613 const clim_t *clim,
5614 met_t **met0,
5615 met_t **met1,
5616 const atm_t *atm) {
5617
5618 /* Update GPU... */
5619 if (ctl != NULL) {
5620#ifdef _OPENACC
5621 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5622#pragma acc update device(ctl[:1])
5623#endif
5624 }
5625
5626 if (cache != NULL) {
5627#ifdef _OPENACC
5628 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5629#pragma acc update device(cache[:1])
5630#endif
5631 }
5632
5633 if (clim != NULL) {
5634#ifdef _OPENACC
5635 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5636#pragma acc update device(clim[:1])
5637#endif
5638 }
5639
5640 if (met0 != NULL) {
5641#ifdef _OPENACC
5642 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5643 met_t *met0up = *met0;
5644#pragma acc update device(met0up[:1])
5645#endif
5646 }
5647
5648 if (met1 != NULL) {
5649#ifdef _OPENACC
5650 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5651 met_t *met1up = *met1;
5652#pragma acc update device(met1up[:1])
5653#endif
5654 }
5655
5656 if (atm != NULL) {
5657#ifdef _OPENACC
5658 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5659#pragma acc update device(atm[:1])
5660#endif
5661 }
5662}
5663
5664/*****************************************************************************/
5665
5667 const ctl_t *ctl,
5668 const cache_t *cache,
5669 const clim_t *clim,
5670 met_t **met0,
5671 met_t **met1,
5672 const atm_t *atm) {
5673
5674 /* Update GPU... */
5675 if (ctl != NULL) {
5676#ifdef _OPENACC
5677 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5678#pragma acc update host(ctl[:1])
5679#endif
5680 }
5681
5682 if (cache != NULL) {
5683#ifdef _OPENACC
5684 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5685#pragma acc update host(cache[:1])
5686#endif
5687 }
5688
5689 if (clim != NULL) {
5690#ifdef _OPENACC
5691 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5692#pragma acc update host(clim[:1])
5693#endif
5694 }
5695
5696 if (met0 != NULL) {
5697#ifdef _OPENACC
5698 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5699 met_t *met0up = *met0;
5700#pragma acc update host(met0up[:1])
5701#endif
5702 }
5703
5704 if (met1 != NULL) {
5705#ifdef _OPENACC
5706 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5707 met_t *met1up = *met1;
5708#pragma acc update host(met1up[:1])
5709#endif
5710 }
5711
5712 if (atm != NULL) {
5713#ifdef _OPENACC
5714 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5715#pragma acc update host(atm[:1])
5716#endif
5717 }
5718}
5719
5720/*****************************************************************************/
5721
5723 const char *filename,
5724 const ctl_t *ctl,
5725 const atm_t *atm,
5726 const double t) {
5727
5728 /* Set timer... */
5729 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
5730
5731 /* Write info... */
5732 LOG(1, "Write atmospheric data: %s", filename);
5733
5734 /* Write ASCII data... */
5735 if (ctl->atm_type_out == 0)
5736 write_atm_asc(filename, ctl, atm, t);
5737
5738 /* Write binary data... */
5739 else if (ctl->atm_type_out == 1)
5740 write_atm_bin(filename, ctl, atm);
5741
5742 /* Write netCDF data... */
5743 else if (ctl->atm_type_out == 2)
5744 write_atm_nc(filename, ctl, atm);
5745
5746 /* Write CLaMS trajectory data... */
5747 else if (ctl->atm_type_out == 3)
5748 write_atm_clams_traj(filename, ctl, atm, t);
5749
5750 /* Write CLaMS pos data... */
5751 else if (ctl->atm_type_out == 4)
5752 write_atm_clams(filename, ctl, atm);
5753
5754 /* Error... */
5755 else
5756 ERRMSG("Atmospheric data type not supported!");
5757
5758 /* Write info... */
5759 double mini, maxi;
5760 LOG(2, "Number of particles: %d", atm->np);
5761 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5762 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5763 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5764 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5765 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5766 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5767 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5768 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5769 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5770 for (int iq = 0; iq < ctl->nq; iq++) {
5771 char msg[5 * LEN];
5772 sprintf(msg, "Quantity %s range: %s ... %s %s",
5773 ctl->qnt_name[iq], ctl->qnt_format[iq],
5774 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5775 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5776 LOG(2, msg, mini, maxi);
5777 }
5778}
5779
5780/*****************************************************************************/
5781
5783 const char *filename,
5784 const ctl_t *ctl,
5785 met_t *met) {
5786
5787 /* Set timer... */
5788 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
5789
5790 /* Write info... */
5791 LOG(1, "Write meteo data: %s", filename);
5792
5793 /* Check compression flags... */
5794#ifndef ZFP
5795 if (ctl->met_type == 3)
5796 ERRMSG("MPTRAC was compiled without zfp compression!");
5797#endif
5798#ifndef ZSTD
5799 if (ctl->met_type == 4)
5800 ERRMSG("MPTRAC was compiled without zstd compression!");
5801#endif
5802#ifndef CMS
5803 if (ctl->met_type == 5)
5804 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
5805#endif
5806
5807 /* Write netCDF data... */
5808 if (ctl->met_type == 0)
5809 write_met_nc(filename, ctl, met);
5810
5811 /* Write binary data... */
5812 else if (ctl->met_type >= 1 && ctl->met_type <= 5)
5813 write_met_bin(filename, ctl, met);
5814
5815 /* Not implemented... */
5816 else
5817 ERRMSG("MET_TYPE not implemented!");
5818}
5819
5820/*****************************************************************************/
5821
5823 const char *dirname,
5824 const ctl_t *ctl,
5825 met_t *met0,
5826 met_t *met1,
5827 atm_t *atm,
5828 const double t) {
5829
5830 char ext[10], filename[2 * LEN];
5831
5832 double r;
5833
5834 int year, mon, day, hour, min, sec;
5835
5836 /* Get time... */
5837 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
5838
5839 /* Update host... */
5840 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
5841 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
5842 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
5843 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
5844 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
5845 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
5846 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
5847
5848 /* Write atmospheric data... */
5849 if (ctl->atm_basename[0] != '-' &&
5850 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
5851 if (ctl->atm_type_out == 0)
5852 sprintf(ext, "tab");
5853 else if (ctl->atm_type_out == 1)
5854 sprintf(ext, "bin");
5855 else if (ctl->atm_type_out == 2)
5856 sprintf(ext, "nc");
5857 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
5858 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
5859 mptrac_write_atm(filename, ctl, atm, t);
5860 }
5861
5862 /* Write gridded data... */
5863 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
5864 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
5865 dirname, ctl->grid_basename, year, mon, day, hour, min,
5866 ctl->grid_type == 0 ? "tab" : "nc");
5867 write_grid(filename, ctl, met0, met1, atm, t);
5868 }
5869
5870 /* Write CSI data... */
5871 if (ctl->csi_basename[0] != '-') {
5872 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
5873 write_csi(filename, ctl, atm, t);
5874 }
5875
5876 /* Write ensemble data... */
5877 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
5878 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
5879 dirname, ctl->ens_basename, year, mon, day, hour, min);
5880 write_ens(filename, ctl, atm, t);
5881 }
5882
5883 /* Write profile data... */
5884 if (ctl->prof_basename[0] != '-') {
5885 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
5886 write_prof(filename, ctl, met0, met1, atm, t);
5887 }
5888
5889 /* Write sample data... */
5890 if (ctl->sample_basename[0] != '-') {
5891 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
5892 write_sample(filename, ctl, met0, met1, atm, t);
5893 }
5894
5895 /* Write station data... */
5896 if (ctl->stat_basename[0] != '-') {
5897 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
5898 write_station(filename, ctl, atm, t);
5899 }
5900
5901 /* Write VTK data... */
5902 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
5903 static int nvtk;
5904 if (t == ctl->t_start)
5905 nvtk = 0;
5906 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
5907 write_vtk(filename, ctl, atm, t);
5908 }
5909}
5910
5911/*****************************************************************************/
5912
5914 const double p,
5915 const double h2o,
5916 const double hno3) {
5917
5918 /* Check water vapor volume mixing ratio... */
5919 const double h2o_help = MAX(h2o, 0.1e-6);
5920
5921 /* Calculate T_NAT... */
5922 const double p_hno3 = hno3 * p / 1.333224;
5923 const double p_h2o = h2o_help * p / 1.333224;
5924 const double a = 0.009179 - 0.00088 * log10(p_h2o);
5925 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
5926 const double c = -11397.0 / a;
5927 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
5928 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
5929 if (x2 > 0)
5930 tnat = x2;
5931
5932 return tnat;
5933}
5934
5935/*****************************************************************************/
5936
5938 const ctl_t *ctl,
5939 const atm_t *atm,
5940 const int ip,
5941 const double pbl,
5942 const double ps) {
5943
5944 /* Get pressure range... */
5945 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
5946 const double p0 = pbl;
5947
5948 /* Get weighting factor... */
5949 if (atm->p[ip] > p0)
5950 return 1;
5951 else if (atm->p[ip] < p1)
5952 return 0;
5953 else
5954 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
5955}
5956
5957/*****************************************************************************/
5958
5960 const char *filename,
5961 const ctl_t *ctl,
5962 atm_t *atm) {
5963
5964 /* Open file... */
5965 FILE *in;
5966 if (!(in = fopen(filename, "r"))) {
5967 WARN("Cannot open file!");
5968 return 0;
5969 }
5970
5971 /* Read line... */
5972 char line[LEN];
5973 while (fgets(line, LEN, in)) {
5974
5975 /* Read data... */
5976 char *tok;
5977 TOK(line, tok, "%lg", atm->time[atm->np]);
5978 TOK(NULL, tok, "%lg", atm->p[atm->np]);
5979 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
5980 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
5981 for (int iq = 0; iq < ctl->nq; iq++)
5982 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
5983
5984 /* Convert altitude to pressure... */
5985 atm->p[atm->np] = P(atm->p[atm->np]);
5986
5987 /* Increment data point counter... */
5988 if ((++atm->np) > NP)
5989 ERRMSG("Too many data points!");
5990 }
5991
5992 /* Close file... */
5993 fclose(in);
5994
5995 /* Return success... */
5996 return 1;
5997}
5998
5999/*****************************************************************************/
6000
6002 const char *filename,
6003 const ctl_t *ctl,
6004 atm_t *atm) {
6005
6006 /* Open file... */
6007 FILE *in;
6008 if (!(in = fopen(filename, "r")))
6009 return 0;
6010
6011 /* Check version of binary data... */
6012 int version;
6013 FREAD(&version, int,
6014 1,
6015 in);
6016 if (version != 100)
6017 ERRMSG("Wrong version of binary data!");
6018
6019 /* Read data... */
6020 FREAD(&atm->np, int,
6021 1,
6022 in);
6023 FREAD(atm->time, double,
6024 (size_t) atm->np,
6025 in);
6026 FREAD(atm->p, double,
6027 (size_t) atm->np,
6028 in);
6029 FREAD(atm->lon, double,
6030 (size_t) atm->np,
6031 in);
6032 FREAD(atm->lat, double,
6033 (size_t) atm->np,
6034 in);
6035 for (int iq = 0; iq < ctl->nq; iq++)
6036 FREAD(atm->q[iq], double,
6037 (size_t) atm->np,
6038 in);
6039
6040 /* Read final flag... */
6041 int final;
6042 FREAD(&final, int,
6043 1,
6044 in);
6045 if (final != 999)
6046 ERRMSG("Error while reading binary data!");
6047
6048 /* Close file... */
6049 fclose(in);
6050
6051 /* Return success... */
6052 return 1;
6053}
6054
6055/*****************************************************************************/
6056
6058 const char *filename,
6059 const ctl_t *ctl,
6060 atm_t *atm) {
6061
6062 int ncid, varid;
6063
6064 /* Open file... */
6065 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6066 return 0;
6067
6068 /* Get dimensions... */
6069 NC_INQ_DIM("NPARTS", &atm->np, 1, NP);
6070
6071 /* Get time... */
6072 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
6073 NC(nc_get_var_double(ncid, varid, atm->time));
6074 } else {
6075 WARN("TIME_INIT not found use time instead!");
6076 double time_init;
6077 NC_GET_DOUBLE("time", &time_init, 1);
6078 for (int ip = 0; ip < atm->np; ip++) {
6079 atm->time[ip] = time_init;
6080 }
6081 }
6082
6083 /* Read zeta coordinate, pressure is optional... */
6084 if (ctl->advect_vert_coord == 1) {
6085 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
6086 NC_GET_DOUBLE("PRESS", atm->p, 0);
6087 }
6088
6089 /* Read pressure, zeta coordinate is optional... */
6090 else {
6091 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
6092 NC(nc_get_var_double(ncid, varid, atm->p));
6093 } else {
6094 WARN("PRESS_INIT not found use PRESS instead!");
6095 nc_inq_varid(ncid, "PRESS", &varid);
6096 NC(nc_get_var_double(ncid, varid, atm->p));
6097 }
6098 }
6099
6100 /* Read longitude and latitude... */
6101 NC_GET_DOUBLE("LON", atm->lon, 1);
6102 NC_GET_DOUBLE("LAT", atm->lat, 1);
6103
6104 /* Close file... */
6105 NC(nc_close(ncid));
6106
6107 /* Return success... */
6108 return 1;
6109}
6110
6111/*****************************************************************************/
6112
6114 const char *filename,
6115 const ctl_t *ctl,
6116 atm_t *atm) {
6117
6118 int ncid, varid;
6119
6120 /* Open file... */
6121 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6122 return 0;
6123
6124 /* Get dimensions... */
6125 NC_INQ_DIM("obs", &atm->np, 1, NP);
6126
6127 /* Read geolocations... */
6128 NC_GET_DOUBLE("time", atm->time, 1);
6129 NC_GET_DOUBLE("press", atm->p, 1);
6130 NC_GET_DOUBLE("lon", atm->lon, 1);
6131 NC_GET_DOUBLE("lat", atm->lat, 1);
6132
6133 /* Read variables... */
6134 for (int iq = 0; iq < ctl->nq; iq++)
6135 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6136
6137 /* Close file... */
6138 NC(nc_close(ncid));
6139
6140 /* Return success... */
6141 return 1;
6142}
6143
6144/*****************************************************************************/
6145
6147 const char *filename,
6148 clim_photo_t *photo) {
6149
6150 int ncid, varid;
6151
6152 /* Write info... */
6153 LOG(1, "Read photolysis rates: %s", filename);
6154
6155 /* Open netCDF file... */
6156 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6157 WARN("Photolysis rate data are missing!");
6158 return;
6159 }
6160
6161 /* Read pressure data... */
6162 NC_INQ_DIM("press", &photo->np, 2, CP);
6163 NC_GET_DOUBLE("press", photo->p, 1);
6164 if (photo->p[0] < photo->p[1])
6165 ERRMSG("Pressure data are not descending!");
6166
6167 /* Read total column ozone data... */
6168 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3);
6169 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
6170 if (photo->o3c[0] > photo->o3c[1])
6171 ERRMSG("Total column ozone data are not ascending!");
6172
6173 /* Read solar zenith angle data... */
6174 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA);
6175 NC_GET_DOUBLE("sza", photo->sza, 1);
6176 if (photo->sza[0] > photo->sza[1])
6177 ERRMSG("Solar zenith angle data are not ascending!");
6178
6179 /* Read data... */
6180 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
6181 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
6182 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
6183 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
6184 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
6185 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
6186 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
6187 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
6188 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
6189
6190 /* Close netCDF file... */
6191 NC(nc_close(ncid));
6192
6193 /* Write info... */
6194 LOG(2, "Number of pressure levels: %d", photo->np);
6195 LOG(2, "Altitude levels: %g, %g ... %g km",
6196 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
6197 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6198 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
6199 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
6200 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
6201 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
6202 RAD2DEG(photo->sza[photo->nsza - 1]));
6203 LOG(2, "Number of total column ozone values: %d", photo->no3c);
6204 LOG(2, "Total column ozone: %g, %g ... %g DU",
6205 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
6206 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
6207 photo->n2o[0][0][0], photo->n2o[1][0][0],
6208 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6209 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
6210 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
6211 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6212 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
6213 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
6214 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6215 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
6216 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
6217 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6218 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
6219 photo->o2[0][0][0], photo->o2[1][0][0],
6220 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6221 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
6222 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
6223 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6224 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
6225 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
6226 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6227 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
6228 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
6229 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6230 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
6231 photo->h2o[0][0][0], photo->h2o[1][0][0],
6232 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6233}
6234
6235/*****************************************************************************/
6236
6238 const int ncid,
6239 const char *varname,
6240 const clim_photo_t *photo,
6241 double var[CP][CSZA][CO3]) {
6242
6243 /* Allocate... */
6244 double *help;
6245 ALLOC(help, double,
6246 photo->np * photo->nsza * photo->no3c);
6247
6248 /* Read varible... */
6249 int varid;
6250 NC_GET_DOUBLE(varname, help, 1);
6251
6252 /* Copy data... */
6253 for (int ip = 0; ip < photo->np; ip++)
6254 for (int is = 0; is < photo->nsza; is++)
6255 for (int io = 0; io < photo->no3c; io++)
6256 var[ip][is][io] =
6257 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
6258
6259 /* Free... */
6260 free(help);
6261}
6262
6263/*****************************************************************************/
6264
6266 const char *filename,
6267 clim_ts_t *ts) {
6268
6269 /* Write info... */
6270 LOG(1, "Read climatological time series: %s", filename);
6271
6272 /* Open file... */
6273 FILE *in;
6274 if (!(in = fopen(filename, "r"))) {
6275 WARN("Cannot open file!");
6276 return 0;
6277 }
6278
6279 /* Read data... */
6280 char line[LEN];
6281 int nh = 0;
6282 while (fgets(line, LEN, in))
6283 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
6284
6285 /* Convert years to seconds... */
6286 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
6287
6288 /* Check data... */
6289 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
6290 ERRMSG("Time series must be ascending!");
6291
6292 /* Count time steps... */
6293 if ((++nh) >= CTS)
6294 ERRMSG("Too many data points!");
6295 }
6296
6297 /* Close file... */
6298 fclose(in);
6299
6300 /* Check number of data points... */
6301 ts->ntime = nh;
6302 if (nh < 2)
6303 ERRMSG("Not enough data points!");
6304
6305 /* Write info... */
6306 LOG(2, "Number of time steps: %d", ts->ntime);
6307 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
6308 ts->time[nh - 1]);
6309 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
6310 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
6311 (size_t) nh));
6312
6313 /* Exit success... */
6314 return 1;
6315}
6316
6317/*****************************************************************************/
6318
6320 const char *filename,
6321 const char *varname,
6322 clim_zm_t *zm) {
6323
6324 int ncid, varid, it, iy, iz, iz2, nt;
6325
6326 double *help, varmin = 1e99, varmax = -1e99;
6327
6328 /* Write info... */
6329 LOG(1, "Read %s data: %s", varname, filename);
6330
6331 /* Open netCDF file... */
6332 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6333 WARN("%s climatology data are missing!", varname);
6334 return;
6335 }
6336
6337 /* Read pressure data... */
6338 NC_INQ_DIM("press", &zm->np, 2, CP);
6339 NC_GET_DOUBLE("press", zm->p, 1);
6340 if (zm->p[0] < zm->p[1])
6341 ERRMSG("Pressure data are not descending!");
6342
6343 /* Read latitudes... */
6344 NC_INQ_DIM("lat", &zm->nlat, 2, CY);
6345 NC_GET_DOUBLE("lat", zm->lat, 1);
6346 if (zm->lat[0] > zm->lat[1])
6347 ERRMSG("Latitude data are not ascending!");
6348
6349 /* Set time data (for monthly means)... */
6350 zm->ntime = 12;
6351 zm->time[0] = 1209600.00;
6352 zm->time[1] = 3888000.00;
6353 zm->time[2] = 6393600.00;
6354 zm->time[3] = 9072000.00;
6355 zm->time[4] = 11664000.00;
6356 zm->time[5] = 14342400.00;
6357 zm->time[6] = 16934400.00;
6358 zm->time[7] = 19612800.00;
6359 zm->time[8] = 22291200.00;
6360 zm->time[9] = 24883200.00;
6361 zm->time[10] = 27561600.00;
6362 zm->time[11] = 30153600.00;
6363
6364 /* Check number of timesteps... */
6365 NC_INQ_DIM("time", &nt, 12, 12);
6366
6367 /* Read data... */
6368 ALLOC(help, double,
6369 zm->nlat * zm->np * zm->ntime);
6370 NC_GET_DOUBLE(varname, help, 1);
6371 for (it = 0; it < zm->ntime; it++)
6372 for (iz = 0; iz < zm->np; iz++)
6373 for (iy = 0; iy < zm->nlat; iy++)
6374 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
6375 free(help);
6376
6377 /* Fix data gaps... */
6378 for (it = 0; it < zm->ntime; it++)
6379 for (iy = 0; iy < zm->nlat; iy++)
6380 for (iz = 0; iz < zm->np; iz++) {
6381 if (zm->vmr[it][iz][iy] < 0) {
6382 for (iz2 = 0; iz2 < zm->np; iz2++)
6383 if (zm->vmr[it][iz2][iy] >= 0) {
6384 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6385 break;
6386 }
6387 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
6388 if (zm->vmr[it][iz2][iy] >= 0) {
6389 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6390 break;
6391 }
6392 }
6393 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
6394 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
6395 }
6396
6397 /* Close netCDF file... */
6398 NC(nc_close(ncid));
6399
6400 /* Write info... */
6401 LOG(2, "Number of time steps: %d", zm->ntime);
6402 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
6403 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
6404 LOG(2, "Number of pressure levels: %d", zm->np);
6405 LOG(2, "Altitude levels: %g, %g ... %g km",
6406 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
6407 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
6408 zm->p[1], zm->p[zm->np - 1]);
6409 LOG(2, "Number of latitudes: %d", zm->nlat);
6410 LOG(2, "Latitudes: %g, %g ... %g deg",
6411 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
6412 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
6413 varmax);
6414}
6415
6416/*****************************************************************************/
6417
6419 const char *filename,
6420 double kz[EP],
6421 double kw[EP],
6422 int *nk) {
6423
6424 /* Write info... */
6425 LOG(1, "Read kernel function: %s", filename);
6426
6427 /* Open file... */
6428 FILE *in;
6429 if (!(in = fopen(filename, "r")))
6430 ERRMSG("Cannot open file!");
6431
6432 /* Read data... */
6433 char line[LEN];
6434 int n = 0;
6435 while (fgets(line, LEN, in))
6436 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
6437 if (n > 0 && kz[n] < kz[n - 1])
6438 ERRMSG("Height levels must be ascending!");
6439 if ((++n) >= EP)
6440 ERRMSG("Too many height levels!");
6441 }
6442
6443 /* Close file... */
6444 fclose(in);
6445
6446 /* Check number of data points... */
6447 *nk = n;
6448 if (n < 2)
6449 ERRMSG("Not enough height levels!");
6450
6451 /* Normalize kernel function... */
6452 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
6453 for (int iz = 0; iz < n; iz++)
6454 kw[iz] /= kmax;
6455}
6456
6457/*****************************************************************************/
6458
6460 const char *filename,
6461 const ctl_t *ctl,
6462 met_t *met) {
6463
6464 FILE *in;
6465
6466 double r;
6467
6468 int year, mon, day, hour, min, sec;
6469
6470 /* Set timer... */
6471 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
6472
6473 /* Open file... */
6474 if (!(in = fopen(filename, "r"))) {
6475 WARN("Cannot open file!");
6476 return 0;
6477 }
6478
6479 /* Check type of binary data... */
6480 int met_type;
6481 FREAD(&met_type, int,
6482 1,
6483 in);
6484 if (met_type != ctl->met_type)
6485 ERRMSG("Wrong MET_TYPE of binary data!");
6486
6487 /* Check version of binary data... */
6488 int version;
6489 FREAD(&version, int,
6490 1,
6491 in);
6492 if (version != 103)
6493 ERRMSG("Wrong version of binary data!");
6494
6495 /* Read time... */
6496 FREAD(&met->time, double,
6497 1,
6498 in);
6499 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
6500 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
6501 met->time, year, mon, day, hour, min);
6502 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
6503 || day < 1 || day > 31 || hour < 0 || hour > 23)
6504 ERRMSG("Error while reading time!");
6505
6506 /* Read dimensions... */
6507 FREAD(&met->nx, int,
6508 1,
6509 in);
6510 LOG(2, "Number of longitudes: %d", met->nx);
6511 if (met->nx < 2 || met->nx > EX)
6512 ERRMSG("Number of longitudes out of range!");
6513
6514 FREAD(&met->ny, int,
6515 1,
6516 in);
6517 LOG(2, "Number of latitudes: %d", met->ny);
6518 if (met->ny < 2 || met->ny > EY)
6519 ERRMSG("Number of latitudes out of range!");
6520
6521 FREAD(&met->np, int,
6522 1,
6523 in);
6524 LOG(2, "Number of levels: %d", met->np);
6525 if (met->np < 2 || met->np > EP)
6526 ERRMSG("Number of levels out of range!");
6527
6528 /* Read grid... */
6529 FREAD(met->lon, double,
6530 (size_t) met->nx,
6531 in);
6532 LOG(2, "Longitudes: %g, %g ... %g deg",
6533 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
6534
6535 FREAD(met->lat, double,
6536 (size_t) met->ny,
6537 in);
6538 LOG(2, "Latitudes: %g, %g ... %g deg",
6539 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
6540
6541 FREAD(met->p, double,
6542 (size_t) met->np,
6543 in);
6544 LOG(2, "Altitude levels: %g, %g ... %g km",
6545 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
6546 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6547 met->p[0], met->p[1], met->p[met->np - 1]);
6548
6549 /* Read surface data... */
6550 read_met_bin_2d(in, met, met->ps, "PS");
6551 read_met_bin_2d(in, met, met->ts, "TS");
6552 read_met_bin_2d(in, met, met->zs, "ZS");
6553 read_met_bin_2d(in, met, met->us, "US");
6554 read_met_bin_2d(in, met, met->vs, "VS");
6555 read_met_bin_2d(in, met, met->ess, "ESS");
6556 read_met_bin_2d(in, met, met->nss, "NSS");
6557 read_met_bin_2d(in, met, met->shf, "SHF");
6558 read_met_bin_2d(in, met, met->lsm, "LSM");
6559 read_met_bin_2d(in, met, met->sst, "SST");
6560 read_met_bin_2d(in, met, met->pbl, "PBL");
6561 read_met_bin_2d(in, met, met->pt, "PT");
6562 read_met_bin_2d(in, met, met->tt, "TT");
6563 read_met_bin_2d(in, met, met->zt, "ZT");
6564 read_met_bin_2d(in, met, met->h2ot, "H2OT");
6565 read_met_bin_2d(in, met, met->pct, "PCT");
6566 read_met_bin_2d(in, met, met->pcb, "PCB");
6567 read_met_bin_2d(in, met, met->cl, "CL");
6568 read_met_bin_2d(in, met, met->plcl, "PLCL");
6569 read_met_bin_2d(in, met, met->plfc, "PLFC");
6570 read_met_bin_2d(in, met, met->pel, "PEL");
6571 read_met_bin_2d(in, met, met->cape, "CAPE");
6572 read_met_bin_2d(in, met, met->cin, "CIN");
6573 read_met_bin_2d(in, met, met->o3c, "O3C");
6574
6575 /* Read level data... */
6576 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
6577 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
6578 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
6579 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
6580 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
6581 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
6582 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
6583 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
6584 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
6585 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
6586 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
6587 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
6588 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
6589
6590 /* Read final flag... */
6591 int final;
6592 FREAD(&final, int,
6593 1,
6594 in);
6595 if (final != 999)
6596 ERRMSG("Error while reading binary data!");
6597
6598 /* Close file... */
6599 fclose(in);
6600
6601 /* Return success... */
6602 return 1;
6603}
6604
6605/*****************************************************************************/
6606
6608 FILE *in,
6609 const met_t *met,
6610 float var[EX][EY],
6611 const char *varname) {
6612
6613 float *help;
6614
6615 /* Allocate... */
6616 ALLOC(help, float,
6617 EX * EY);
6618
6619 /* Read uncompressed... */
6620 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
6621 FREAD(help, float,
6622 (size_t) (met->nx * met->ny),
6623 in);
6624
6625 /* Copy data... */
6626 for (int ix = 0; ix < met->nx; ix++)
6627 for (int iy = 0; iy < met->ny; iy++)
6628 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
6629
6630 /* Free... */
6631 free(help);
6632}
6633
6634/*****************************************************************************/
6635
6637 FILE *in,
6638 const ctl_t *ctl,
6639 const met_t *met,
6640 float var[EX][EY][EP],
6641 const char *varname,
6642 const float bound_min,
6643 const float bound_max) {
6644
6645 float *help;
6646
6647 /* Allocate... */
6648 ALLOC(help, float,
6649 EX * EY * EP);
6650
6651 /* Read uncompressed data... */
6652 if (ctl->met_type == 1) {
6653 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
6654 FREAD(help, float,
6655 (size_t) (met->nx * met->ny * met->np),
6656 in);
6657 }
6658
6659 /* Read packed data... */
6660 else if (ctl->met_type == 2)
6661 compress_pck(varname, help, (size_t) (met->ny * met->nx),
6662 (size_t) met->np, 1, in);
6663
6664 /* Read zfp data... */
6665 else if (ctl->met_type == 3) {
6666#ifdef ZFP
6667 int precision;
6668 FREAD(&precision, int,
6669 1,
6670 in);
6671
6672 double tolerance;
6673 FREAD(&tolerance, double,
6674 1,
6675 in);
6676
6677 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
6678 tolerance, 1, in);
6679#else
6680 ERRMSG("MPTRAC was compiled without zfp compression!");
6681#endif
6682 }
6683
6684 /* Read zstd data... */
6685 else if (ctl->met_type == 4) {
6686#ifdef ZSTD
6687 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
6688 ctl->met_zstd_level, in);
6689#else
6690 ERRMSG("MPTRAC was compiled without zstd compression!");
6691#endif
6692 }
6693
6694 /* Read cmultiscale data... */
6695 else if (ctl->met_type == 5) {
6696#ifdef CMS
6697 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
6698 (size_t) met->np, 1, in);
6699#else
6700 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6701#endif
6702 }
6703
6704 /* Copy data... */
6705#pragma omp parallel for default(shared) collapse(2)
6706 for (int ix = 0; ix < met->nx; ix++)
6707 for (int iy = 0; iy < met->ny; iy++)
6708 for (int ip = 0; ip < met->np; ip++) {
6709 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
6710 if (var[ix][iy][ip] < bound_min)
6711 var[ix][iy][ip] = bound_min;
6712 else if (var[ix][iy][ip] > bound_max)
6713 var[ix][iy][ip] = bound_max;
6714 }
6715
6716 /* Free... */
6717 free(help);
6718}
6719
6720/*****************************************************************************/
6721
6723 const ctl_t *ctl,
6724 const clim_t *clim,
6725 met_t *met) {
6726
6727 /* Check parameters... */
6728 if (ctl->met_cape != 1)
6729 return;
6730
6731 /* Set timer... */
6732 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
6733 LOG(2, "Calculate CAPE...");
6734
6735 /* Vertical spacing (about 100 m)... */
6736 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
6737
6738 /* Loop over columns... */
6739#pragma omp parallel for default(shared) collapse(2)
6740 for (int ix = 0; ix < met->nx; ix++)
6741 for (int iy = 0; iy < met->ny; iy++) {
6742
6743 /* Get potential temperature and water vapor at lowest 50 hPa... */
6744 int n = 0;
6745 double h2o = 0, t, theta = 0;
6746 double pbot = MIN(met->ps[ix][iy], met->p[0]);
6747 double ptop = pbot - 50.;
6748 for (int ip = 0; ip < met->np; ip++) {
6749 if (met->p[ip] <= pbot) {
6750 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
6751 h2o += met->h2o[ix][iy][ip];
6752 n++;
6753 }
6754 if (met->p[ip] < ptop && n > 0)
6755 break;
6756 }
6757 theta /= n;
6758 h2o /= n;
6759
6760 /* Cannot compute anything if water vapor is missing... */
6761 met->plcl[ix][iy] = NAN;
6762 met->plfc[ix][iy] = NAN;
6763 met->pel[ix][iy] = NAN;
6764 met->cape[ix][iy] = NAN;
6765 met->cin[ix][iy] = NAN;
6766 if (h2o <= 0)
6767 continue;
6768
6769 /* Find lifted condensation level (LCL)... */
6770 ptop = P(20.);
6771 pbot = met->ps[ix][iy];
6772 do {
6773 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
6774 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
6775 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
6776 ptop = met->plcl[ix][iy];
6777 else
6778 pbot = met->plcl[ix][iy];
6779 } while (pbot - ptop > 0.1);
6780
6781 /* Calculate CIN up to LCL... */
6783 double dcape, dz, h2o_env, t_env;
6784 double p = met->ps[ix][iy];
6785 met->cape[ix][iy] = met->cin[ix][iy] = 0;
6786 do {
6787 dz = dz0 * TVIRT(t, h2o);
6788 p /= pfac;
6789 t = theta / pow(1000. / p, 0.286);
6790 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6791 &t_env, ci, cw, 1);
6792 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6793 &h2o_env, ci, cw, 0);
6794 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6795 TVIRT(t_env, h2o_env) * dz;
6796 if (dcape < 0)
6797 met->cin[ix][iy] += fabsf((float) dcape);
6798 } while (p > met->plcl[ix][iy]);
6799
6800 /* Calculate level of free convection (LFC), equilibrium level (EL),
6801 and convective available potential energy (CAPE)... */
6802 dcape = 0;
6803 p = met->plcl[ix][iy];
6804 t = theta / pow(1000. / p, 0.286);
6805 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
6806 do {
6807 dz = dz0 * TVIRT(t, h2o);
6808 p /= pfac;
6809 t -= lapse_rate(t, h2o) * dz;
6810 double psat = PSAT(t);
6811 h2o = psat / (p - (1. - EPS) * psat);
6812 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6813 &t_env, ci, cw, 1);
6814 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6815 &h2o_env, ci, cw, 0);
6816 double dcape_old = dcape;
6817 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6818 TVIRT(t_env, h2o_env) * dz;
6819 if (dcape > 0) {
6820 met->cape[ix][iy] += (float) dcape;
6821 if (!isfinite(met->plfc[ix][iy]))
6822 met->plfc[ix][iy] = (float) p;
6823 } else if (dcape_old > 0)
6824 met->pel[ix][iy] = (float) p;
6825 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
6826 met->cin[ix][iy] += fabsf((float) dcape);
6827 } while (p > ptop);
6828
6829 /* Check results... */
6830 if (!isfinite(met->plfc[ix][iy]))
6831 met->cin[ix][iy] = NAN;
6832 }
6833}
6834
6835/*****************************************************************************/
6836
6838 met_t *met) {
6839
6840 /* Set timer... */
6841 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
6842 LOG(2, "Calculate cloud data...");
6843
6844 /* Thresholds for cloud detection... */
6845 const double ccmin = 0.01, cwmin = 1e-6;
6846
6847 /* Loop over columns... */
6848#pragma omp parallel for default(shared) collapse(2)
6849 for (int ix = 0; ix < met->nx; ix++)
6850 for (int iy = 0; iy < met->ny; iy++) {
6851
6852 /* Init... */
6853 met->pct[ix][iy] = NAN;
6854 met->pcb[ix][iy] = NAN;
6855 met->cl[ix][iy] = 0;
6856
6857 /* Loop over pressure levels... */
6858 for (int ip = 0; ip < met->np - 1; ip++) {
6859
6860 /* Check pressure... */
6861 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
6862 continue;
6863
6864 /* Check ice water and liquid water content... */
6865 if (met->cc[ix][iy][ip] > ccmin
6866 && (met->lwc[ix][iy][ip] > cwmin
6867 || met->rwc[ix][iy][ip] > cwmin
6868 || met->iwc[ix][iy][ip] > cwmin
6869 || met->swc[ix][iy][ip] > cwmin)) {
6870
6871 /* Get cloud top pressure ... */
6872 met->pct[ix][iy]
6873 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
6874
6875 /* Get cloud bottom pressure ... */
6876 if (!isfinite(met->pcb[ix][iy]))
6877 met->pcb[ix][iy]
6878 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
6879 }
6880
6881 /* Get cloud water... */
6882 met->cl[ix][iy] += (float)
6883 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
6884 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
6885 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
6886 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
6887 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
6888 }
6889 }
6890}
6891
6892/*****************************************************************************/
6893
6895 const ctl_t *ctl,
6896 met_t *met) {
6897
6898 met_t *help;
6899
6900 /* Check parameters... */
6901 if (ctl->met_detrend <= 0)
6902 return;
6903
6904 /* Set timer... */
6905 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
6906 LOG(2, "Detrend meteo data...");
6907
6908 /* Allocate... */
6909 ALLOC(help, met_t, 1);
6910
6911 /* Calculate standard deviation... */
6912 const double sigma = ctl->met_detrend / 2.355;
6913 const double tssq = 2. * SQR(sigma);
6914
6915 /* Calculate box size in latitude... */
6916 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
6917 sy = MIN(MAX(1, sy), met->ny / 2);
6918
6919 /* Calculate background... */
6920#pragma omp parallel for default(shared) collapse(2)
6921 for (int ix = 0; ix < met->nx; ix++) {
6922 for (int iy = 0; iy < met->ny; iy++) {
6923
6924 /* Calculate Cartesian coordinates... */
6925 double x0[3];
6926 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
6927
6928 /* Calculate box size in longitude... */
6929 int sx =
6930 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
6931 fabs(met->lon[1] - met->lon[0]));
6932 sx = MIN(MAX(1, sx), met->nx / 2);
6933
6934 /* Init... */
6935 float wsum = 0;
6936 for (int ip = 0; ip < met->np; ip++) {
6937 help->t[ix][iy][ip] = 0;
6938 help->u[ix][iy][ip] = 0;
6939 help->v[ix][iy][ip] = 0;
6940 help->w[ix][iy][ip] = 0;
6941 }
6942
6943 /* Loop over neighboring grid points... */
6944 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
6945 int ix3 = ix2;
6946 if (ix3 < 0)
6947 ix3 += met->nx;
6948 else if (ix3 >= met->nx)
6949 ix3 -= met->nx;
6950 for (int iy2 = MAX(iy - sy, 0);
6951 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
6952
6953 /* Calculate Cartesian coordinates... */
6954 double x1[3];
6955 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
6956
6957 /* Calculate weighting factor... */
6958 const float w = (float) exp(-DIST2(x0, x1) / tssq);
6959
6960 /* Add data... */
6961 wsum += w;
6962 for (int ip = 0; ip < met->np; ip++) {
6963 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
6964 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
6965 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
6966 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
6967 }
6968 }
6969 }
6970
6971 /* Normalize... */
6972 for (int ip = 0; ip < met->np; ip++) {
6973 help->t[ix][iy][ip] /= wsum;
6974 help->u[ix][iy][ip] /= wsum;
6975 help->v[ix][iy][ip] /= wsum;
6976 help->w[ix][iy][ip] /= wsum;
6977 }
6978 }
6979 }
6980
6981 /* Subtract background... */
6982#pragma omp parallel for default(shared) collapse(3)
6983 for (int ix = 0; ix < met->nx; ix++)
6984 for (int iy = 0; iy < met->ny; iy++)
6985 for (int ip = 0; ip < met->np; ip++) {
6986 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
6987 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
6988 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
6989 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
6990 }
6991
6992 /* Free... */
6993 free(help);
6994}
6995
6996/*****************************************************************************/
6997
6999 met_t *met) {
7000
7001 /* Set timer... */
7002 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
7003 LOG(2, "Extrapolate meteo data...");
7004
7005 /* Loop over columns... */
7006#pragma omp parallel for default(shared) collapse(2)
7007 for (int ix = 0; ix < met->nx; ix++)
7008 for (int iy = 0; iy < met->ny; iy++) {
7009
7010 /* Find lowest valid data point... */
7011 int ip0;
7012 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
7013 if (!isfinite(met->t[ix][iy][ip0])
7014 || !isfinite(met->u[ix][iy][ip0])
7015 || !isfinite(met->v[ix][iy][ip0])
7016 || !isfinite(met->w[ix][iy][ip0]))
7017 break;
7018
7019 /* Extrapolate... */
7020 for (int ip = ip0; ip >= 0; ip--) {
7021 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
7022 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
7023 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
7024 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
7025 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
7026 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
7027 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
7028 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
7029 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
7030 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
7031 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
7032 }
7033 }
7034}
7035
7036/*****************************************************************************/
7037
7039 const ctl_t *ctl,
7040 met_t *met) {
7041
7042 float *help;
7043
7044 double logp[EP];
7045
7046 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
7047
7048 /* Set timer... */
7049 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
7050 LOG(2, "Calculate geopotential heights...");
7051
7052 /* Allocate... */
7053 ALLOC(help, float,
7054 EX * EY * EP);
7055
7056 /* Calculate log pressure... */
7057#pragma omp parallel for default(shared)
7058 for (int ip = 0; ip < met->np; ip++)
7059 logp[ip] = log(met->p[ip]);
7060
7061 /* Apply hydrostatic equation to calculate geopotential heights... */
7062#pragma omp parallel for default(shared) collapse(2)
7063 for (int ix = 0; ix < met->nx; ix++)
7064 for (int iy = 0; iy < met->ny; iy++) {
7065
7066 /* Get surface height and pressure... */
7067 const double zs = met->zs[ix][iy];
7068 const double lnps = log(met->ps[ix][iy]);
7069
7070 /* Get temperature and water vapor at the surface... */
7071 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
7072 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
7073 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
7074 const double h2os =
7075 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
7076 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
7077
7078 /* Upper part of profile... */
7079 met->z[ix][iy][ip0 + 1]
7080 = (float) (zs +
7081 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
7082 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
7083 for (int ip = ip0 + 2; ip < met->np; ip++)
7084 met->z[ix][iy][ip]
7085 = (float) (met->z[ix][iy][ip - 1] +
7086 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
7087 met->h2o[ix][iy][ip - 1], logp[ip],
7088 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7089
7090 /* Lower part of profile... */
7091 met->z[ix][iy][ip0]
7092 = (float) (zs +
7093 ZDIFF(lnps, ts, h2os, logp[ip0],
7094 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
7095 for (int ip = ip0 - 1; ip >= 0; ip--)
7096 met->z[ix][iy][ip]
7097 = (float) (met->z[ix][iy][ip + 1] +
7098 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
7099 met->h2o[ix][iy][ip + 1], logp[ip],
7100 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7101 }
7102
7103 /* Check control parameters... */
7104 if (dx == 0 || dy == 0)
7105 return;
7106
7107 /* Default smoothing parameters... */
7108 if (dx < 0 || dy < 0) {
7109 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
7110 dx = 3;
7111 dy = 2;
7112 } else {
7113 dx = 6;
7114 dy = 4;
7115 }
7116 }
7117
7118 /* Calculate weights for smoothing... */
7119 float ws[dx + 1][dy + 1];
7120#pragma omp parallel for default(shared) collapse(2)
7121 for (int ix = 0; ix <= dx; ix++)
7122 for (int iy = 0; iy < dy; iy++)
7123 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
7124 * (1.0f - (float) iy / (float) dy);
7125
7126 /* Copy data... */
7127#pragma omp parallel for default(shared) collapse(3)
7128 for (int ix = 0; ix < met->nx; ix++)
7129 for (int iy = 0; iy < met->ny; iy++)
7130 for (int ip = 0; ip < met->np; ip++)
7131 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
7132
7133 /* Horizontal smoothing... */
7134#pragma omp parallel for default(shared) collapse(3)
7135 for (int ip = 0; ip < met->np; ip++)
7136 for (int ix = 0; ix < met->nx; ix++)
7137 for (int iy = 0; iy < met->ny; iy++) {
7138 float res = 0, wsum = 0;
7139 int iy0 = MAX(iy - dy + 1, 0);
7140 int iy1 = MIN(iy + dy - 1, met->ny - 1);
7141 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
7142 int ix3 = ix2;
7143 if (ix3 < 0)
7144 ix3 += met->nx;
7145 else if (ix3 >= met->nx)
7146 ix3 -= met->nx;
7147 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
7148 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
7149 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
7150 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
7151 wsum += w;
7152 }
7153 }
7154 if (wsum > 0)
7155 met->z[ix][iy][ip] = res / wsum;
7156 else
7157 met->z[ix][iy][ip] = NAN;
7158 }
7159
7160 /* Free... */
7161 free(help);
7162}
7163
7164/*****************************************************************************/
7165
7167 const char *filename,
7168 const int ncid,
7169 const ctl_t *ctl,
7170 met_t *met) {
7171
7172 char levname[LEN], tstr[10];
7173
7174 double rtime = 0, r, r2;
7175
7176 int varid, year2, mon2, day2, hour2, min2, sec2,
7177 year, mon, day, hour, min, sec;
7178
7179 size_t np;
7180
7181 /* Set timer... */
7182 SELECT_TIMER("READ_MET_GRID", "INPUT", NVTX_READ);
7183 LOG(2, "Read meteo grid information...");
7184
7185 /* MPTRAC meteo files... */
7186 if (ctl->met_clams == 0) {
7187
7188 /* Get time from filename... */
7189 met->time = time_from_filename(filename, 16);
7190
7191 /* Check time information from data file... */
7192 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7193 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
7194 NC(nc_get_var_double(ncid, varid, &rtime));
7195 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
7196 WARN("Time information in meteo file does not match filename!");
7197 } else
7198 WARN("Time information in meteo file is missing!");
7199 }
7200
7201 /* CLaMS meteo files... */
7202 else {
7203
7204 /* Read time from file... */
7205 NC_GET_DOUBLE("time", &rtime, 0);
7206
7207 /* Get time from filename (considering the century)... */
7208 if (rtime < 0)
7209 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
7210 else
7211 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
7212 year = atoi(tstr);
7213 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
7214 mon = atoi(tstr);
7215 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
7216 day = atoi(tstr);
7217 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
7218 hour = atoi(tstr);
7219 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
7220 }
7221
7222 /* Check time... */
7223 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7224 || day < 1 || day > 31 || hour < 0 || hour > 23)
7225 ERRMSG("Cannot read time from filename!");
7226 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
7227 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7228 met->time, year2, mon2, day2, hour2, min2);
7229
7230 /* Get grid dimensions... */
7231 NC_INQ_DIM("lon", &met->nx, 2, EX);
7232 LOG(2, "Number of longitudes: %d", met->nx);
7233
7234 NC_INQ_DIM("lat", &met->ny, 2, EY);
7235 LOG(2, "Number of latitudes: %d", met->ny);
7236
7237 int dimid2;
7238 sprintf(levname, "lev");
7239 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7240 sprintf(levname, "plev");
7241 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7242 sprintf(levname, "hybrid");
7243 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7244 sprintf(levname, "hybrid_level");
7245
7246 NC_INQ_DIM(levname, &met->np, 1, EP);
7247 if (met->np == 1) {
7248 sprintf(levname, "lev_2");
7249 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR) {
7250 sprintf(levname, "plev");
7251 NC(nc_inq_dimid(ncid, levname, &dimid2));
7252 }
7253 NC(nc_inq_dimlen(ncid, dimid2, &np));
7254 met->np = (int) np;
7255 }
7256 LOG(2, "Number of levels: %d", met->np);
7257 if (met->np < 2 || met->np > EP)
7258 ERRMSG("Number of levels out of range!");
7259
7260 /* Read longitudes and latitudes... */
7261 NC_GET_DOUBLE("lon", met->lon, 1);
7262 LOG(2, "Longitudes: %g, %g ... %g deg",
7263 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7264 NC_GET_DOUBLE("lat", met->lat, 1);
7265 LOG(2, "Latitudes: %g, %g ... %g deg",
7266 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7267
7268 /* Check grid spacing... */
7269 for (int ix = 2; ix < met->nx; ix++)
7270 if (fabs
7271 (fabs(met->lon[ix] - met->lon[ix - 1]) -
7272 fabs(met->lon[1] - met->lon[0])) > 0.001)
7273 ERRMSG("No regular grid spacing in longitudes!");
7274 for (int iy = 2; iy < met->ny; iy++)
7275 if (fabs
7276 (fabs(met->lat[iy] - met->lat[iy - 1]) -
7277 fabs(met->lat[1] - met->lat[0])) > 0.001) {
7278 WARN("No regular grid spacing in latitudes!");
7279 break;
7280 }
7281
7282 /* Read pressure levels... */
7283 if (ctl->met_np <= 0) {
7284 NC_GET_DOUBLE(levname, met->p, 1);
7285 for (int ip = 0; ip < met->np; ip++)
7286 met->p[ip] /= 100.;
7287 LOG(2, "Altitude levels: %g, %g ... %g km",
7288 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7289 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7290 met->p[0], met->p[1], met->p[met->np - 1]);
7291 }
7292
7293 /* Read hybrid levels... */
7294 if (strcasecmp(levname, "hybrid") == 0)
7295 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
7296}
7297
7298/*****************************************************************************/
7299
7301 const int ncid,
7302 const ctl_t *ctl,
7303 met_t *met) {
7304
7305 /* Set timer... */
7306 SELECT_TIMER("READ_MET_LEVELS", "INPUT", NVTX_READ);
7307 LOG(2, "Read level data...");
7308
7309 /* Read temperature... */
7310 if (!read_met_nc_3d(ncid, "t", "T", "temp", "TEMP", ctl, met, met->t, 1.0))
7311 ERRMSG("Cannot read temperature!");
7312
7313 /* Read horizontal wind and vertical velocity... */
7314 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, met->u, 1.0))
7315 ERRMSG("Cannot read zonal wind!");
7316 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, met->v, 1.0))
7317 ERRMSG("Cannot read meridional wind!");
7318 if (!read_met_nc_3d
7319 (ncid, "w", "W", "omega", "OMEGA", ctl, met, met->w, 0.01f))
7320 WARN("Cannot read vertical velocity!");
7321
7322 /* Read water vapor... */
7323 if (!ctl->met_relhum) {
7324 if (!read_met_nc_3d
7325 (ncid, "q", "Q", "sh", "SH", ctl, met, met->h2o, (float) (MA / MH2O)))
7326 WARN("Cannot read specific humidity!");
7327 } else {
7328 if (!read_met_nc_3d
7329 (ncid, "rh", "RH", NULL, NULL, ctl, met, met->h2o, 0.01f))
7330 WARN("Cannot read relative humidity!");
7331#pragma omp parallel for default(shared) collapse(2)
7332 for (int ix = 0; ix < met->nx; ix++)
7333 for (int iy = 0; iy < met->ny; iy++)
7334 for (int ip = 0; ip < met->np; ip++) {
7335 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
7336 met->h2o[ix][iy][ip] =
7337 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
7338 }
7339 }
7340
7341 /* Read ozone... */
7342 if (!read_met_nc_3d
7343 (ncid, "o3", "O3", NULL, NULL, ctl, met, met->o3, (float) (MA / MO3)))
7344 WARN("Cannot read ozone data!");
7345
7346 /* Read cloud data... */
7347 if (!read_met_nc_3d
7348 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, met->lwc, 1.0))
7349 WARN("Cannot read cloud liquid water content!");
7350 if (!read_met_nc_3d
7351 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, met->rwc, 1.0))
7352 WARN("Cannot read cloud rain water content!");
7353 if (!read_met_nc_3d
7354 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, met->iwc, 1.0))
7355 WARN("Cannot read cloud ice water content!");
7356 if (!read_met_nc_3d
7357 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, met->swc, 1.0))
7358 WARN("Cannot read cloud snow water content!");
7359 if (!read_met_nc_3d(ncid, "cc", "CC", NULL, NULL, ctl, met, met->cc, 1.0))
7360 WARN("Cannot read cloud cover!");
7361
7362 /* Read zeta and zeta_dot... */
7363 if (!read_met_nc_3d
7364 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, met->zetal, 1.0))
7365 WARN("Cannot read ZETA!");
7366 if (!read_met_nc_3d
7367 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
7368 NULL, ctl, met, met->zeta_dotl, 0.00001157407f))
7369 WARN("Cannot read ZETA_DOT!");
7370
7371 /* Store velocities on model levels... */
7372 if (ctl->met_vert_coord != 0) {
7373 for (int ix = 0; ix < met->nx; ix++)
7374 for (int iy = 0; iy < met->ny; iy++)
7375 for (int ip = 0; ip < met->np; ip++) {
7376 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
7377 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
7378 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
7379 }
7380
7381 /* Save number of model levels... */
7382 met->npl = met->np;
7383 }
7384
7385 /* Get pressure on model levels... */
7386 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
7387
7388 /* Read 3-D pressure field... */
7389 if (ctl->met_vert_coord == 1) {
7390 if (!read_met_nc_3d
7391 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, met->pl,
7392 0.01f))
7393 if (!read_met_nc_3d
7394 (ncid, "press", "PRESS", NULL, NULL, ctl, met, met->pl, 1.0))
7395 ERRMSG("Cannot read pressure on model levels!");
7396 }
7397
7398 /* Use a and b coefficients for full levels... */
7399 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
7400
7401 /* Grid level coefficients... */
7402 double hyam[EP], hybm[EP];
7403
7404 /* Read coefficients from file... */
7405 if (ctl->met_vert_coord == 2) {
7406 int varid;
7407 if (nc_inq_varid(ncid, "hyam", &varid) == NC_NOERR
7408 && nc_inq_varid(ncid, "hybm", &varid) == NC_NOERR) {
7409 NC_GET_DOUBLE("hyam", hyam, 1);
7410 NC_GET_DOUBLE("hybm", hybm, 1);
7411 } else if (nc_inq_varid(ncid, "a_hybrid_level", &varid) == NC_NOERR
7412 && nc_inq_varid(ncid, "b_hybrid_level",
7413 &varid) == NC_NOERR) {
7414 NC_GET_DOUBLE("a_hybrid_level", hyam, 1);
7415 NC_GET_DOUBLE("b_hybrid_level", hybm, 1);
7416 } else
7417 ERRMSG("Cannot read a and b level coefficients from netCDF file!");
7418 }
7419
7420 /* Use control parameters... */
7421 else if (ctl->met_vert_coord == 3) {
7422
7423 /* Check number of levels... */
7424 if (met->np != ctl->met_nlev)
7425 ERRMSG("Mismatch in number of model levels!");
7426
7427 /* Copy parameters... */
7428 for (int ip = 0; ip < met->np; ip++) {
7429 hyam[ip] = ctl->met_lev_hyam[ip];
7430 hybm[ip] = ctl->met_lev_hybm[ip];
7431 }
7432 }
7433
7434 /* Calculate pressure... */
7435 for (int ix = 0; ix < met->nx; ix++)
7436 for (int iy = 0; iy < met->ny; iy++)
7437 for (int ip = 0; ip < met->np; ip++)
7438 met->pl[ix][iy][ip] =
7439 (float) (hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy]);
7440 }
7441
7442 /* Use a and b coefficients for half levels... */
7443 else if (ctl->met_vert_coord == 4) {
7444
7445 /* Grid level coefficients... */
7446 double hyam[EP], hybm[EP];
7447
7448 /* Use control parameters... */
7449 for (int ip = 0; ip < met->np + 1; ip++) {
7450 hyam[ip] = ctl->met_lev_hyam[ip];
7451 hybm[ip] = ctl->met_lev_hybm[ip];
7452 }
7453
7454 /* Check number of levels... */
7455 if (met->np + 1 != ctl->met_nlev)
7456 ERRMSG("Mismatch in number of model levels!");
7457
7458 /* Calculate pressure... */
7459#pragma omp parallel for default(shared) collapse(2)
7460 for (int ix = 0; ix < met->nx; ix++)
7461 for (int iy = 0; iy < met->ny; iy++)
7462 for (int ip = 0; ip < met->np; ip++) {
7463 double p0 = hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy];
7464 double p1 = hyam[ip + 1] / 100. + hybm[ip + 1] * met->ps[ix][iy];
7465 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
7466 }
7467 }
7468
7469 /* Check ordering of pressure levels... */
7470 for (int ix = 0; ix < met->nx; ix++)
7471 for (int iy = 0; iy < met->ny; iy++)
7472 for (int ip = 1; ip < met->np; ip++)
7473 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
7474 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
7475 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
7476 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
7477 ERRMSG("Pressure profiles are not monotonic!");
7478 }
7479
7480 /* Interpolate from model levels to pressure levels... */
7481 if (ctl->met_np > 0) {
7482
7483 /* Check pressure on model levels... */
7484 if (met->pl[0][0][0] <= 0)
7485 ERRMSG("Pressure on model levels is missing, check MET_VERT_COORD!");
7486
7487 /* Interpolate variables... */
7488 read_met_ml2pl(ctl, met, met->t, "T");
7489 read_met_ml2pl(ctl, met, met->u, "U");
7490 read_met_ml2pl(ctl, met, met->v, "V");
7491 read_met_ml2pl(ctl, met, met->w, "W");
7492 read_met_ml2pl(ctl, met, met->h2o, "H2O");
7493 read_met_ml2pl(ctl, met, met->o3, "O3");
7494 read_met_ml2pl(ctl, met, met->lwc, "LWC");
7495 read_met_ml2pl(ctl, met, met->rwc, "RWC");
7496 read_met_ml2pl(ctl, met, met->iwc, "IWC");
7497 read_met_ml2pl(ctl, met, met->swc, "SWC");
7498 read_met_ml2pl(ctl, met, met->cc, "CC");
7499
7500 /* Set new pressure levels... */
7501 met->np = ctl->met_np;
7502 for (int ip = 0; ip < met->np; ip++)
7503 met->p[ip] = ctl->met_p[ip];
7504 }
7505
7506 /* Check ordering of pressure levels... */
7507 for (int ip = 1; ip < met->np; ip++)
7508 if (met->p[ip - 1] < met->p[ip])
7509 ERRMSG("Pressure levels must be descending!");
7510}
7511
7512/*****************************************************************************/
7513
7515 const ctl_t *ctl,
7516 const met_t *met,
7517 float var[EX][EY][EP],
7518 const char *varname) {
7519
7520 double aux[EP], p[EP];
7521
7522 /* Set timer... */
7523 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
7524 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
7525
7526 /* Loop over columns... */
7527#pragma omp parallel for default(shared) private(aux,p) collapse(2)
7528 for (int ix = 0; ix < met->nx; ix++)
7529 for (int iy = 0; iy < met->ny; iy++) {
7530
7531 /* Copy pressure profile... */
7532 for (int ip = 0; ip < met->np; ip++)
7533 p[ip] = met->pl[ix][iy][ip];
7534
7535 /* Interpolate... */
7536 for (int ip = 0; ip < ctl->met_np; ip++) {
7537 double pt = ctl->met_p[ip];
7538 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
7539 pt = p[0];
7540 else if ((pt > p[met->np - 1] && p[1] > p[0])
7541 || (pt < p[met->np - 1] && p[1] < p[0]))
7542 pt = p[met->np - 1];
7543 int ip2 = locate_irr(p, met->np, pt);
7544 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
7545 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
7546 }
7547
7548 /* Copy data... */
7549 for (int ip = 0; ip < ctl->met_np; ip++)
7550 var[ix][iy][ip] = (float) aux[ip];
7551 }
7552}
7553
7554/*****************************************************************************/
7555
7557 const ctl_t *ctl,
7558 met_t *met) {
7559
7560 /* Check parameters... */
7561 if (ctl->advect_vert_coord != 1)
7562 return;
7563
7564 /* Set timer... */
7565 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
7566 LOG(2, "Make zeta profiles monotone...");
7567
7568 /* Create monotone zeta profiles... */
7569#pragma omp parallel for default(shared) collapse(2)
7570 for (int i = 0; i < met->nx; i++)
7571 for (int j = 0; j < met->ny; j++) {
7572 int k = 1;
7573
7574 while (k < met->npl) { /* Check if there is an inversion at level k... */
7575 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
7576 /* Find the upper level k+l over the inversion... */
7577 int l = 0;
7578 do {
7579 l++;
7580 }
7581 while ((met->zetal[i][j][k - 1] >=
7582 met->zetal[i][j][k + l]) & (k + l < met->npl));
7583
7584 /* Interpolate linear between the top and bottom
7585 of the inversion... */
7586 float s =
7587 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
7588 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
7589
7590 for (int m = k; m < k + l; m++) {
7591 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
7592 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
7593 }
7594
7595 /* Search for more inversions above the last inversion ... */
7596 k = k + l;
7597 } else {
7598 k++;
7599 }
7600 }
7601 }
7602
7603 /* Create monotone pressure profiles... */
7604#pragma omp parallel for default(shared) collapse(2)
7605 for (int i = 0; i < met->nx; i++)
7606 for (int j = 0; j < met->ny; j++) {
7607 int k = 1;
7608
7609 while (k < met->npl) { /* Check if there is an inversion at level k... */
7610 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
7611
7612 /* Find the upper level k+l over the inversion... */
7613 int l = 0;
7614 do {
7615 l++;
7616 }
7617 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
7618 met->npl));
7619
7620 /* Interpolate linear between the top and bottom
7621 of the inversion... */
7622 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
7623 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
7624
7625 for (int m = k; m < k + l; m++) {
7626 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
7627 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
7628 }
7629
7630 /* Search for more inversions above the last inversion ... */
7631 k += l;
7632 } else {
7633 k++;
7634 }
7635 }
7636 }
7637}
7638
7639/*****************************************************************************/
7640
7642 const char *filename,
7643 const ctl_t *ctl,
7644 const clim_t *clim,
7645 met_t *met) {
7646
7647 int ncid;
7648
7649 /* Open netCDF file... */
7650 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7651 WARN("Cannot open file!");
7652 return 0;
7653 }
7654
7655 /* Read coordinates of meteo data... */
7656 read_met_grid(filename, ncid, ctl, met);
7657
7658 /* Read surface data... */
7659 read_met_surface(ncid, ctl, met);
7660
7661 /* Read meteo data on vertical levels... */
7662 read_met_levels(ncid, ctl, met);
7663
7664 /* Extrapolate data for lower boundary... */
7666
7667 /* Fix polar winds... */
7669
7670 /* Create periodic boundary conditions... */
7671 read_met_periodic(met);
7672
7673 /* Downsampling... */
7674 read_met_sample(ctl, met);
7675
7676 /* Calculate geopotential heights... */
7677 read_met_geopot(ctl, met);
7678
7679 /* Calculate potential vorticity... */
7680 read_met_pv(met);
7681
7682 /* Calculate boundary layer data... */
7683 read_met_pbl(ctl, met);
7684
7685 /* Calculate tropopause data... */
7686 read_met_tropo(ctl, clim, met);
7687
7688 /* Calculate cloud properties... */
7689 read_met_cloud(met);
7690
7691 /* Calculate convective available potential energy... */
7692 read_met_cape(ctl, clim, met);
7693
7694 /* Calculate total column ozone... */
7695 read_met_ozone(met);
7696
7697 /* Detrending... */
7698 read_met_detrend(ctl, met);
7699
7700 /* Check meteo data and smooth zeta profiles ... */
7701 read_met_monotonize(ctl, met);
7702
7703 /* Close file... */
7704 NC(nc_close(ncid));
7705
7706 /* Return success... */
7707 return 1;
7708}
7709
7710/*****************************************************************************/
7711
7713 const int ncid,
7714 const char *varname,
7715 const char *varname2,
7716 const char *varname3,
7717 const char *varname4,
7718 const char *varname5,
7719 const char *varname6,
7720 const ctl_t *ctl,
7721 const met_t *met,
7722 float dest[EX][EY],
7723 const float scl,
7724 const int init) {
7725
7726 char varsel[LEN];
7727
7728 float offset, scalfac;
7729
7730 int varid;
7731
7732 /* Check if variable exists... */
7733 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7734 sprintf(varsel, "%s", varname);
7735 else if (varname2 != NULL
7736 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7737 sprintf(varsel, "%s", varname2);
7738 else if (varname3 != NULL
7739 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7740 sprintf(varsel, "%s", varname3);
7741 else if (varname4 != NULL
7742 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7743 sprintf(varsel, "%s", varname4);
7744 else if (varname5 != NULL
7745 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
7746 sprintf(varsel, "%s", varname5);
7747 else if (varname6 != NULL
7748 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
7749 sprintf(varsel, "%s", varname6);
7750 else
7751 return 0;
7752
7753 /* Read packed data... */
7754 if (ctl->met_nc_scale
7755 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
7756 && nc_get_att_float(ncid, varid, "scale_factor",
7757 &scalfac) == NC_NOERR) {
7758
7759 /* Allocate... */
7760 short *help;
7761 ALLOC(help, short,
7762 EX * EY * EP);
7763
7764 /* Read fill value and missing value... */
7765 short fillval, missval;
7766 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7767 fillval = 0;
7768 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
7769 missval = 0;
7770
7771 /* Write info... */
7772 LOG(2, "Read 2-D variable: %s"
7773 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
7774 varsel, fillval, missval, scalfac, offset);
7775
7776 /* Read data... */
7777 NC(nc_get_var_short(ncid, varid, help));
7778
7779 /* Check meteo data layout... */
7780 if (ctl->met_convention != 0)
7781 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
7782
7783 /* Copy and check data... */
7784#pragma omp parallel for default(shared) num_threads(12)
7785 for (int ix = 0; ix < met->nx; ix++)
7786 for (int iy = 0; iy < met->ny; iy++) {
7787 if (init)
7788 dest[ix][iy] = 0;
7789 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
7790 if ((fillval == 0 || aux != fillval)
7791 && (missval == 0 || aux != missval)
7792 && fabsf(aux * scalfac + offset) < 1e14f)
7793 dest[ix][iy] += scl * (aux * scalfac + offset);
7794 else
7795 dest[ix][iy] = NAN;
7796 }
7797
7798 /* Free... */
7799 free(help);
7800 }
7801
7802 /* Unpacked data... */
7803 else {
7804
7805 /* Allocate... */
7806 float *help;
7807 ALLOC(help, float,
7808 EX * EY);
7809
7810 /* Read fill value and missing value... */
7811 float fillval, missval;
7812 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7813 fillval = 0;
7814 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7815 missval = 0;
7816
7817 /* Write info... */
7818 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
7819 varsel, fillval, missval);
7820
7821 /* Read data... */
7822 NC(nc_get_var_float(ncid, varid, help));
7823
7824 /* Check meteo data layout... */
7825 if (ctl->met_convention == 0) {
7826
7827 /* Copy and check data (ordering: lat, lon)... */
7828#pragma omp parallel for default(shared) num_threads(12)
7829 for (int ix = 0; ix < met->nx; ix++)
7830 for (int iy = 0; iy < met->ny; iy++) {
7831 if (init)
7832 dest[ix][iy] = 0;
7833 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
7834 if ((fillval == 0 || aux != fillval)
7835 && (missval == 0 || aux != missval)
7836 && fabsf(aux) < 1e14f)
7837 dest[ix][iy] += scl * aux;
7838 else
7839 dest[ix][iy] = NAN;
7840 }
7841
7842 } else {
7843
7844 /* Copy and check data (ordering: lon, lat)... */
7845#pragma omp parallel for default(shared) num_threads(12)
7846 for (int iy = 0; iy < met->ny; iy++)
7847 for (int ix = 0; ix < met->nx; ix++) {
7848 if (init)
7849 dest[ix][iy] = 0;
7850 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
7851 if ((fillval == 0 || aux != fillval)
7852 && (missval == 0 || aux != missval)
7853 && fabsf(aux) < 1e14f)
7854 dest[ix][iy] += scl * aux;
7855 else
7856 dest[ix][iy] = NAN;
7857 }
7858 }
7859
7860 /* Free... */
7861 free(help);
7862 }
7863
7864 /* Return... */
7865 return 1;
7866}
7867
7868/*****************************************************************************/
7869
7871 const int ncid,
7872 const char *varname,
7873 const char *varname2,
7874 const char *varname3,
7875 const char *varname4,
7876 const ctl_t *ctl,
7877 const met_t *met,
7878 float dest[EX][EY][EP],
7879 const float scl) {
7880
7881 char varsel[LEN];
7882
7883 float offset, scalfac;
7884
7885 int varid;
7886
7887 /* Check if variable exists... */
7888 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7889 sprintf(varsel, "%s", varname);
7890 else if (varname2 != NULL
7891 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7892 sprintf(varsel, "%s", varname2);
7893 else if (varname3 != NULL
7894 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7895 sprintf(varsel, "%s", varname3);
7896 else if (varname4 != NULL
7897 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7898 sprintf(varsel, "%s", varname4);
7899 else
7900 return 0;
7901
7902 /* Read packed data... */
7903 if (ctl->met_nc_scale
7904 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
7905 && nc_get_att_float(ncid, varid, "scale_factor",
7906 &scalfac) == NC_NOERR) {
7907
7908 /* Allocate... */
7909 short *help;
7910 ALLOC(help, short,
7911 EX * EY * EP);
7912
7913 /* Read fill value and missing value... */
7914 short fillval, missval;
7915 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7916 fillval = 0;
7917 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
7918 missval = 0;
7919
7920 /* Write info... */
7921 LOG(2, "Read 3-D variable: %s "
7922 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
7923 varsel, fillval, missval, scalfac, offset);
7924
7925 /* Read data... */
7926 NC(nc_get_var_short(ncid, varid, help));
7927
7928 /* Check meteo data layout... */
7929 if (ctl->met_convention != 0)
7930 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
7931
7932 /* Copy and check data... */
7933#pragma omp parallel for default(shared) num_threads(12)
7934 for (int ix = 0; ix < met->nx; ix++)
7935 for (int iy = 0; iy < met->ny; iy++)
7936 for (int ip = 0; ip < met->np; ip++) {
7937 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7938 if ((fillval == 0 || aux != fillval)
7939 && (missval == 0 || aux != missval)
7940 && fabsf(aux * scalfac + offset) < 1e14f)
7941 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
7942 else
7943 dest[ix][iy][ip] = NAN;
7944 }
7945
7946 /* Free... */
7947 free(help);
7948 }
7949
7950 /* Unpacked data... */
7951 else {
7952
7953 /* Allocate... */
7954 float *help;
7955 ALLOC(help, float,
7956 EX * EY * EP);
7957
7958 /* Read fill value and missing value... */
7959 float fillval, missval;
7960 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7961 fillval = 0;
7962 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7963 missval = 0;
7964
7965 /* Write info... */
7966 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
7967 varsel, fillval, missval);
7968
7969 /* Read data... */
7970 NC(nc_get_var_float(ncid, varid, help));
7971
7972 /* Check meteo data layout... */
7973 if (ctl->met_convention == 0) {
7974
7975 /* Copy and check data (ordering: lev, lat, lon)... */
7976#pragma omp parallel for default(shared) num_threads(12)
7977 for (int ix = 0; ix < met->nx; ix++)
7978 for (int iy = 0; iy < met->ny; iy++)
7979 for (int ip = 0; ip < met->np; ip++) {
7980 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7981 if ((fillval == 0 || aux != fillval)
7982 && (missval == 0 || aux != missval)
7983 && fabsf(aux) < 1e14f)
7984 dest[ix][iy][ip] = scl * aux;
7985 else
7986 dest[ix][iy][ip] = NAN;
7987 }
7988
7989 } else {
7990
7991 /* Copy and check data (ordering: lon, lat, lev)... */
7992#pragma omp parallel for default(shared) num_threads(12)
7993 for (int ip = 0; ip < met->np; ip++)
7994 for (int iy = 0; iy < met->ny; iy++)
7995 for (int ix = 0; ix < met->nx; ix++) {
7996 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7997 if ((fillval == 0 || aux != fillval)
7998 && (missval == 0 || aux != missval)
7999 && fabsf(aux) < 1e14f)
8000 dest[ix][iy][ip] = scl * aux;
8001 else
8002 dest[ix][iy][ip] = NAN;
8003 }
8004 }
8005
8006 /* Free... */
8007 free(help);
8008 }
8009
8010 /* Return... */
8011 return 1;
8012}
8013
8014/*****************************************************************************/
8015
8017 const ctl_t *ctl,
8018 met_t *met) {
8019
8020 /* Set timer... */
8021 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
8022 LOG(2, "Calculate planetary boundary layer...");
8023
8024 /* Convert PBL height from meteo file to pressure... */
8025 if (ctl->met_pbl == 1) {
8026
8027 /* Loop over grid points... */
8028#pragma omp parallel for default(shared) collapse(2)
8029 for (int ix = 0; ix < met->nx; ix++)
8030 for (int iy = 0; iy < met->ny; iy++) {
8031
8032 /* Get pressure at top of PBL... */
8033 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
8034 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
8035 met->pbl[ix][iy] =
8036 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
8037 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
8038 }
8039 }
8040
8041 /* Determine PBL based on Richardson number... */
8042 else if (ctl->met_pbl == 2) {
8043
8044 /* Parameters used to estimate the height of the PBL
8045 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
8046 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
8047
8048 /* Loop over grid points... */
8049#pragma omp parallel for default(shared) collapse(2)
8050 for (int ix = 0; ix < met->nx; ix++)
8051 for (int iy = 0; iy < met->ny; iy++) {
8052
8053 /* Set bottom level of PBL... */
8054 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
8055
8056 /* Find lowest level near the bottom... */
8057 int ip;
8058 for (ip = 1; ip < met->np; ip++)
8059 if (met->p[ip] < pbl_bot)
8060 break;
8061
8062 /* Get near surface data... */
8063 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
8064 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
8065 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
8066
8067 /* Init... */
8068 double rib_old = 0;
8069
8070 /* Loop over levels... */
8071 for (; ip < met->np; ip++) {
8072
8073 /* Get squared horizontal wind speed... */
8074 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
8075 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
8076 vh2 = MAX(vh2, SQR(umin));
8077
8078 /* Calculate bulk Richardson number... */
8079 const double rib =
8080 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
8081 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
8082 met->h2o[ix][iy][ip]) - tvs) / vh2;
8083
8084 /* Check for critical value... */
8085 if (rib >= rib_crit) {
8086 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
8087 rib, met->p[ip], rib_crit));
8088 if (met->pbl[ix][iy] > pbl_bot)
8089 met->pbl[ix][iy] = (float) pbl_bot;
8090 break;
8091 }
8092
8093 /* Save Richardson number... */
8094 rib_old = rib;
8095 }
8096 }
8097 }
8098
8099 /* Determine PBL based on potential temperature... */
8100 if (ctl->met_pbl == 3) {
8101
8102 /* Parameters used to estimate the height of the PBL
8103 (following HYSPLIT model)... */
8104 const double dtheta = 2.0, zmin = 0.1;
8105
8106 /* Loop over grid points... */
8107#pragma omp parallel for default(shared) collapse(2)
8108 for (int ix = 0; ix < met->nx; ix++)
8109 for (int iy = 0; iy < met->ny; iy++) {
8110
8111 /* Potential temperature at the surface... */
8112 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
8113
8114 /* Find topmost level where theta exceeds surface value by 2 K... */
8115 int ip;
8116 for (ip = met->np - 2; ip > 0; ip--)
8117 if (met->p[ip] >= 300.)
8118 if (met->p[ip] > met->ps[ix][iy]
8119 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
8120 break;
8121
8122 /* Interpolate... */
8123 met->pbl[ix][iy]
8124 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
8125 met->p[ip + 1],
8126 THETA(met->p[ip], met->t[ix][iy][ip]),
8127 met->p[ip], theta0 + dtheta));
8128
8129 /* Check minimum value... */
8130 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
8131 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
8132 met->pbl[ix][iy] = (float) pbl_min;
8133 }
8134 }
8135
8136 /* Loop over grid points... */
8137#pragma omp parallel for default(shared) collapse(2)
8138 for (int ix = 0; ix < met->nx; ix++)
8139 for (int iy = 0; iy < met->ny; iy++) {
8140
8141 /* Check minimum value... */
8142 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
8143 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
8144
8145 /* Check maximum value... */
8146 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
8147 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
8148 }
8149}
8150
8151/*****************************************************************************/
8152
8154 met_t *met) {
8155
8156 /* Set timer... */
8157 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
8158 LOG(2, "Apply periodic boundary conditions...");
8159
8160 /* Check longitudes... */
8161 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
8162 + met->lon[1] - met->lon[0] - 360) < 0.01))
8163 return;
8164
8165 /* Increase longitude counter... */
8166 if ((++met->nx) >= EX)
8167 ERRMSG("Cannot create periodic boundary conditions!");
8168
8169 /* Set longitude... */
8170 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
8171
8172 /* Loop over latitudes and pressure levels... */
8173#pragma omp parallel for default(shared)
8174 for (int iy = 0; iy < met->ny; iy++) {
8175 met->ps[met->nx - 1][iy] = met->ps[0][iy];
8176 met->zs[met->nx - 1][iy] = met->zs[0][iy];
8177 met->ts[met->nx - 1][iy] = met->ts[0][iy];
8178 met->us[met->nx - 1][iy] = met->us[0][iy];
8179 met->vs[met->nx - 1][iy] = met->vs[0][iy];
8180 met->ess[met->nx - 1][iy] = met->ess[0][iy];
8181 met->nss[met->nx - 1][iy] = met->nss[0][iy];
8182 met->shf[met->nx - 1][iy] = met->shf[0][iy];
8183 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
8184 met->sst[met->nx - 1][iy] = met->sst[0][iy];
8185 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
8186 met->cape[met->nx - 1][iy] = met->cape[0][iy];
8187 met->cin[met->nx - 1][iy] = met->cin[0][iy];
8188 for (int ip = 0; ip < met->np; ip++) {
8189 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
8190 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
8191 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
8192 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
8193 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
8194 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
8195 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
8196 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
8197 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
8198 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
8199 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
8200 }
8201 for (int ip = 0; ip < met->npl; ip++) {
8202 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
8203 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
8204 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
8205 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
8206 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
8207 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
8208 }
8209 }
8210}
8211
8212/*****************************************************************************/
8213
8215 met_t *met) {
8216
8217 /* Set timer... */
8218 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
8219 LOG(2, "Apply fix for polar winds...");
8220
8221 /* Check latitudes... */
8222 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
8223 return;
8224
8225 /* Loop over hemispheres... */
8226 for (int ihem = 0; ihem < 2; ihem++) {
8227
8228 /* Set latitude indices... */
8229 int i89 = 1, i90 = 0, sign = 1;
8230 if (ihem == 1) {
8231 i89 = met->ny - 2;
8232 i90 = met->ny - 1;
8233 }
8234 if (met->lat[i90] < 0)
8235 sign = -1;
8236
8237 /* Look-up table of cosinus and sinus... */
8238 double clon[EX], slon[EX];
8239#pragma omp parallel for default(shared)
8240 for (int ix = 0; ix < met->nx; ix++) {
8241 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
8242 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
8243 }
8244
8245 /* Loop over levels... */
8246#pragma omp parallel for default(shared)
8247 for (int ip = 0; ip < met->np; ip++) {
8248
8249 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
8250 double vel89x = 0, vel89y = 0;
8251 for (int ix = 0; ix < met->nx; ix++) {
8252 vel89x +=
8253 (met->u[ix][i89][ip] * clon[ix] -
8254 met->v[ix][i89][ip] * slon[ix]) / met->nx;
8255 vel89y +=
8256 (met->u[ix][i89][ip] * slon[ix] +
8257 met->v[ix][i89][ip] * clon[ix]) / met->nx;
8258 }
8259
8260 /* Replace 90 degree winds by 89 degree mean... */
8261 for (int ix = 0; ix < met->nx; ix++) {
8262 met->u[ix][i90][ip]
8263 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
8264 met->v[ix][i90][ip]
8265 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
8266 }
8267 }
8268 }
8269}
8270
8271/*****************************************************************************/
8272
8274 met_t *met) {
8275
8276 double pows[EP];
8277
8278 /* Set timer... */
8279 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
8280 LOG(2, "Calculate potential vorticity...");
8281
8282 /* Set powers... */
8283#pragma omp parallel for default(shared)
8284 for (int ip = 0; ip < met->np; ip++)
8285 pows[ip] = pow(1000. / met->p[ip], 0.286);
8286
8287 /* Loop over grid points... */
8288#pragma omp parallel for default(shared)
8289 for (int ix = 0; ix < met->nx; ix++) {
8290
8291 /* Set indices... */
8292 const int ix0 = MAX(ix - 1, 0);
8293 const int ix1 = MIN(ix + 1, met->nx - 1);
8294
8295 /* Loop over grid points... */
8296 for (int iy = 0; iy < met->ny; iy++) {
8297
8298 /* Set indices... */
8299 const int iy0 = MAX(iy - 1, 0);
8300 const int iy1 = MIN(iy + 1, met->ny - 1);
8301
8302 /* Set auxiliary variables... */
8303 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
8304 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
8305 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
8306 const double c0 = cos(DEG2RAD(met->lat[iy0]));
8307 const double c1 = cos(DEG2RAD(met->lat[iy1]));
8308 const double cr = cos(DEG2RAD(latr));
8309 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
8310
8311 /* Loop over grid points... */
8312 for (int ip = 0; ip < met->np; ip++) {
8313
8314 /* Get gradients in longitude... */
8315 const double dtdx
8316 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
8317 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
8318
8319 /* Get gradients in latitude... */
8320 const double dtdy
8321 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
8322 const double dudy
8323 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
8324
8325 /* Set indices... */
8326 const int ip0 = MAX(ip - 1, 0);
8327 const int ip1 = MIN(ip + 1, met->np - 1);
8328
8329 /* Get gradients in pressure... */
8330 double dtdp, dudp, dvdp;
8331 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
8332 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
8333 if (ip != ip0 && ip != ip1) {
8334 double denom = dp0 * dp1 * (dp0 + dp1);
8335 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
8336 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
8337 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
8338 / denom;
8339 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
8340 - dp1 * dp1 * met->u[ix][iy][ip0]
8341 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
8342 / denom;
8343 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
8344 - dp1 * dp1 * met->v[ix][iy][ip0]
8345 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
8346 / denom;
8347 } else {
8348 const double denom = dp0 + dp1;
8349 dtdp =
8350 (met->t[ix][iy][ip1] * pows[ip1] -
8351 met->t[ix][iy][ip0] * pows[ip0]) / denom;
8352 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
8353 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
8354 }
8355
8356 /* Calculate PV... */
8357 met->pv[ix][iy][ip] = (float)
8358 (1e6 * G0 *
8359 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
8360 }
8361 }
8362 }
8363
8364 /* Fix for polar regions... */
8365#pragma omp parallel for default(shared)
8366 for (int ix = 0; ix < met->nx; ix++)
8367 for (int ip = 0; ip < met->np; ip++) {
8368 met->pv[ix][0][ip]
8369 = met->pv[ix][1][ip]
8370 = met->pv[ix][2][ip];
8371 met->pv[ix][met->ny - 1][ip]
8372 = met->pv[ix][met->ny - 2][ip]
8373 = met->pv[ix][met->ny - 3][ip];
8374 }
8375}
8376
8377/*****************************************************************************/
8378
8380 met_t *met) {
8381
8382 /* Set timer... */
8383 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
8384 LOG(2, "Calculate total column ozone...");
8385
8386 /* Loop over columns... */
8387#pragma omp parallel for default(shared) collapse(2)
8388 for (int ix = 0; ix < met->nx; ix++)
8389 for (int iy = 0; iy < met->ny; iy++) {
8390
8391 /* Integrate... */
8392 double cd = 0;
8393 for (int ip = 1; ip < met->np; ip++)
8394 if (met->p[ip - 1] <= met->ps[ix][iy]) {
8395 const double vmr =
8396 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
8397 const double dp = met->p[ip - 1] - met->p[ip];
8398 cd += vmr * MO3 / MA * dp * 1e2 / G0;
8399 }
8400
8401 /* Convert to Dobson units... */
8402 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
8403 }
8404}
8405
8406/*****************************************************************************/
8407
8409 const ctl_t *ctl,
8410 met_t *met) {
8411
8412 met_t *help;
8413
8414 /* Check parameters... */
8415 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
8416 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
8417 return;
8418
8419 /* Set timer... */
8420 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
8421 LOG(2, "Downsampling of meteo data...");
8422
8423 /* Allocate... */
8424 ALLOC(help, met_t, 1);
8425
8426 /* Copy data... */
8427 help->nx = met->nx;
8428 help->ny = met->ny;
8429 help->np = met->np;
8430 memcpy(help->lon, met->lon, sizeof(met->lon));
8431 memcpy(help->lat, met->lat, sizeof(met->lat));
8432 memcpy(help->p, met->p, sizeof(met->p));
8433
8434 /* Smoothing... */
8435 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
8436 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
8437 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
8438 help->ps[ix][iy] = 0;
8439 help->zs[ix][iy] = 0;
8440 help->ts[ix][iy] = 0;
8441 help->us[ix][iy] = 0;
8442 help->vs[ix][iy] = 0;
8443 help->ess[ix][iy] = 0;
8444 help->nss[ix][iy] = 0;
8445 help->shf[ix][iy] = 0;
8446 help->lsm[ix][iy] = 0;
8447 help->sst[ix][iy] = 0;
8448 help->pbl[ix][iy] = 0;
8449 help->cape[ix][iy] = 0;
8450 help->cin[ix][iy] = 0;
8451 help->t[ix][iy][ip] = 0;
8452 help->u[ix][iy][ip] = 0;
8453 help->v[ix][iy][ip] = 0;
8454 help->w[ix][iy][ip] = 0;
8455 help->h2o[ix][iy][ip] = 0;
8456 help->o3[ix][iy][ip] = 0;
8457 help->lwc[ix][iy][ip] = 0;
8458 help->rwc[ix][iy][ip] = 0;
8459 help->iwc[ix][iy][ip] = 0;
8460 help->swc[ix][iy][ip] = 0;
8461 help->cc[ix][iy][ip] = 0;
8462 float wsum = 0;
8463 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
8464 ix2++) {
8465 int ix3 = ix2;
8466 if (ix3 < 0)
8467 ix3 += met->nx;
8468 else if (ix3 >= met->nx)
8469 ix3 -= met->nx;
8470
8471 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
8472 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
8473 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
8474 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
8475 float w = (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
8476 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
8477 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
8478 help->ps[ix][iy] += w * met->ps[ix3][iy2];
8479 help->zs[ix][iy] += w * met->zs[ix3][iy2];
8480 help->ts[ix][iy] += w * met->ts[ix3][iy2];
8481 help->us[ix][iy] += w * met->us[ix3][iy2];
8482 help->vs[ix][iy] += w * met->vs[ix3][iy2];
8483 help->ess[ix][iy] += w * met->ess[ix3][iy2];
8484 help->nss[ix][iy] += w * met->nss[ix3][iy2];
8485 help->shf[ix][iy] += w * met->shf[ix3][iy2];
8486 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
8487 help->sst[ix][iy] += w * met->sst[ix3][iy2];
8488 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
8489 help->cape[ix][iy] += w * met->cape[ix3][iy2];
8490 help->cin[ix][iy] += w * met->cin[ix3][iy2];
8491 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
8492 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
8493 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
8494 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
8495 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
8496 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
8497 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
8498 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
8499 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
8500 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
8501 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
8502 wsum += w;
8503 }
8504 }
8505 help->ps[ix][iy] /= wsum;
8506 help->zs[ix][iy] /= wsum;
8507 help->ts[ix][iy] /= wsum;
8508 help->us[ix][iy] /= wsum;
8509 help->vs[ix][iy] /= wsum;
8510 help->ess[ix][iy] /= wsum;
8511 help->nss[ix][iy] /= wsum;
8512 help->shf[ix][iy] /= wsum;
8513 help->lsm[ix][iy] /= wsum;
8514 help->sst[ix][iy] /= wsum;
8515 help->pbl[ix][iy] /= wsum;
8516 help->cape[ix][iy] /= wsum;
8517 help->cin[ix][iy] /= wsum;
8518 help->t[ix][iy][ip] /= wsum;
8519 help->u[ix][iy][ip] /= wsum;
8520 help->v[ix][iy][ip] /= wsum;
8521 help->w[ix][iy][ip] /= wsum;
8522 help->h2o[ix][iy][ip] /= wsum;
8523 help->o3[ix][iy][ip] /= wsum;
8524 help->lwc[ix][iy][ip] /= wsum;
8525 help->rwc[ix][iy][ip] /= wsum;
8526 help->iwc[ix][iy][ip] /= wsum;
8527 help->swc[ix][iy][ip] /= wsum;
8528 help->cc[ix][iy][ip] /= wsum;
8529 }
8530 }
8531 }
8532
8533 /* Downsampling... */
8534 met->nx = 0;
8535 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
8536 met->lon[met->nx] = help->lon[ix];
8537 met->ny = 0;
8538 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
8539 met->lat[met->ny] = help->lat[iy];
8540 met->ps[met->nx][met->ny] = help->ps[ix][iy];
8541 met->zs[met->nx][met->ny] = help->zs[ix][iy];
8542 met->ts[met->nx][met->ny] = help->ts[ix][iy];
8543 met->us[met->nx][met->ny] = help->us[ix][iy];
8544 met->vs[met->nx][met->ny] = help->vs[ix][iy];
8545 met->ess[met->nx][met->ny] = help->ess[ix][iy];
8546 met->nss[met->nx][met->ny] = help->nss[ix][iy];
8547 met->shf[met->nx][met->ny] = help->shf[ix][iy];
8548 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
8549 met->sst[met->nx][met->ny] = help->sst[ix][iy];
8550 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
8551 met->cape[met->nx][met->ny] = help->cape[ix][iy];
8552 met->cin[met->nx][met->ny] = help->cin[ix][iy];
8553 met->np = 0;
8554 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
8555 met->p[met->np] = help->p[ip];
8556 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
8557 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
8558 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
8559 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
8560 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
8561 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
8562 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
8563 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
8564 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
8565 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
8566 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
8567 met->np++;
8568 }
8569 met->ny++;
8570 }
8571 met->nx++;
8572 }
8573
8574 /* Free... */
8575 free(help);
8576}
8577
8578/*****************************************************************************/
8579
8581 const int ncid,
8582 const ctl_t *ctl,
8583 met_t *met) {
8584
8585 /* Set timer... */
8586 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
8587 LOG(2, "Read surface data...");
8588
8589 /* Read surface pressure... */
8590 if (read_met_nc_2d
8591 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, met->ps, 1.0f,
8592 1)) {
8593 for (int ix = 0; ix < met->nx; ix++)
8594 for (int iy = 0; iy < met->ny; iy++)
8595 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8596 } else
8597 if (!read_met_nc_2d
8598 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, met->ps, 0.01f,
8599 1)) {
8600 WARN("Cannot not read surface pressure data (use lowest level)!");
8601 for (int ix = 0; ix < met->nx; ix++)
8602 for (int iy = 0; iy < met->ny; iy++)
8603 met->ps[ix][iy]
8604 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
8605 }
8606
8607 /* MPTRAC meteo data... */
8608 if (ctl->met_clams == 0) {
8609
8610 /* Read geopotential height at the surface... */
8611 if (!read_met_nc_2d
8612 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, met->zs,
8613 (float) (1. / (1000. * G0)), 1))
8614 if (!read_met_nc_2d
8615 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, met->zs,
8616 (float) (1. / 1000.), 1))
8617 WARN("Cannot read surface geopotential height!");
8618 }
8619
8620 /* CLaMS meteo data... */
8621 else {
8622
8623 /* Read geopotential height at the surface
8624 (use lowermost level of 3-D data field)... */
8625 float *help;
8626 ALLOC(help, float,
8627 EX * EY * EP);
8628 memcpy(help, met->pl, sizeof(met->pl));
8629 if (!read_met_nc_3d
8630 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
8631 (float) (1e-3 / G0)))
8632 ERRMSG("Cannot read geopotential height!");
8633 for (int ix = 0; ix < met->nx; ix++)
8634 for (int iy = 0; iy < met->ny; iy++)
8635 met->zs[ix][iy] = met->pl[ix][iy][0];
8636 memcpy(met->pl, help, sizeof(met->pl));
8637 free(help);
8638 }
8639
8640 /* Read temperature at the surface... */
8641 if (!read_met_nc_2d
8642 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, met->ts, 1.0, 1))
8643 WARN("Cannot read surface temperature!");
8644
8645 /* Read zonal wind at the surface... */
8646 if (!read_met_nc_2d
8647 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, met->us,
8648 1.0, 1))
8649 WARN("Cannot read surface zonal wind!");
8650
8651 /* Read meridional wind at the surface... */
8652 if (!read_met_nc_2d
8653 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, met->vs,
8654 1.0, 1))
8655 WARN("Cannot read surface meridional wind!");
8656
8657 /* Read eastward turbulent surface stress... */
8658 if (!read_met_nc_2d
8659 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, met->ess, 1.0,
8660 1))
8661 WARN("Cannot read eastward turbulent surface stress!");
8662
8663 /* Read northward turbulent surface stress... */
8664 if (!read_met_nc_2d
8665 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, met->nss, 1.0,
8666 1))
8667 WARN("Cannot read nothward turbulent surface stress!");
8668
8669 /* Read surface sensible heat flux... */
8670 if (!read_met_nc_2d
8671 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, met->shf, 1.0,
8672 1))
8673 WARN("Cannot read surface sensible heat flux!");
8674
8675 /* Read land-sea mask... */
8676 if (!read_met_nc_2d
8677 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, met->lsm, 1.0,
8678 1))
8679 WARN("Cannot read land-sea mask!");
8680
8681 /* Read sea surface temperature... */
8682 if (!read_met_nc_2d
8683 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, met->sst,
8684 1.0, 1))
8685 WARN("Cannot read sea surface temperature!");
8686
8687 /* Read PBL... */
8688 if (ctl->met_pbl == 0)
8689 if (!read_met_nc_2d
8690 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
8691 0.01f, 1))
8692 WARN("Cannot read planetary boundary layer pressure!");
8693 if (ctl->met_pbl == 1)
8694 if (!read_met_nc_2d
8695 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
8696 0.001f, 1))
8697 WARN("Cannot read planetary boundary layer height!");
8698
8699 /* Read CAPE... */
8700 if (ctl->met_cape == 0)
8701 if (!read_met_nc_2d
8702 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, met->cape,
8703 1.0, 1))
8704 WARN("Cannot read CAPE!");
8705
8706 /* Read CIN... */
8707 if (ctl->met_cape == 0)
8708 if (!read_met_nc_2d
8709 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, met->cin,
8710 1.0, 1))
8711 WARN("Cannot read convective inhibition!");
8712}
8713
8714/*****************************************************************************/
8715
8717 const ctl_t *ctl,
8718 const clim_t *clim,
8719 met_t *met) {
8720
8721 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
8722 th2[200], z[EP], z2[200];
8723
8724 /* Set timer... */
8725 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
8726 LOG(2, "Calculate tropopause...");
8727
8728 /* Get altitude and pressure profiles... */
8729#pragma omp parallel for default(shared)
8730 for (int iz = 0; iz < met->np; iz++)
8731 z[iz] = Z(met->p[iz]);
8732#pragma omp parallel for default(shared)
8733 for (int iz = 0; iz <= 190; iz++) {
8734 z2[iz] = 4.5 + 0.1 * iz;
8735 p2[iz] = P(z2[iz]);
8736 }
8737
8738 /* Do not calculate tropopause... */
8739 if (ctl->met_tropo == 0)
8740#pragma omp parallel for default(shared) collapse(2)
8741 for (int ix = 0; ix < met->nx; ix++)
8742 for (int iy = 0; iy < met->ny; iy++)
8743 met->pt[ix][iy] = NAN;
8744
8745 /* Use tropopause climatology... */
8746 else if (ctl->met_tropo == 1) {
8747#pragma omp parallel for default(shared) collapse(2)
8748 for (int ix = 0; ix < met->nx; ix++)
8749 for (int iy = 0; iy < met->ny; iy++)
8750 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
8751 }
8752
8753 /* Use cold point... */
8754 else if (ctl->met_tropo == 2) {
8755
8756 /* Loop over grid points... */
8757#pragma omp parallel for default(shared) private(t,t2) collapse(2)
8758 for (int ix = 0; ix < met->nx; ix++)
8759 for (int iy = 0; iy < met->ny; iy++) {
8760
8761 /* Interpolate temperature profile... */
8762 for (int iz = 0; iz < met->np; iz++)
8763 t[iz] = met->t[ix][iy][iz];
8764 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
8765
8766 /* Find minimum... */
8767 int iz = (int) gsl_stats_min_index(t2, 1, 171);
8768 if (iz > 0 && iz < 170)
8769 met->pt[ix][iy] = (float) p2[iz];
8770 else
8771 met->pt[ix][iy] = NAN;
8772 }
8773 }
8774
8775 /* Use WMO definition... */
8776 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
8777
8778 /* Loop over grid points... */
8779#pragma omp parallel for default(shared) private(t,t2) collapse(2)
8780 for (int ix = 0; ix < met->nx; ix++)
8781 for (int iy = 0; iy < met->ny; iy++) {
8782
8783 /* Interpolate temperature profile... */
8784 int iz;
8785 for (iz = 0; iz < met->np; iz++)
8786 t[iz] = met->t[ix][iy][iz];
8787 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
8788
8789 /* Find 1st tropopause... */
8790 met->pt[ix][iy] = NAN;
8791 for (iz = 0; iz <= 170; iz++) {
8792 int found = 1;
8793 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
8794 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
8795 found = 0;
8796 break;
8797 }
8798 if (found) {
8799 if (iz > 0 && iz < 170)
8800 met->pt[ix][iy] = (float) p2[iz];
8801 break;
8802 }
8803 }
8804
8805 /* Find 2nd tropopause... */
8806 if (ctl->met_tropo == 4) {
8807 met->pt[ix][iy] = NAN;
8808 for (; iz <= 170; iz++) {
8809 int found = 1;
8810 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
8811 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
8812 found = 0;
8813 break;
8814 }
8815 if (found)
8816 break;
8817 }
8818 for (; iz <= 170; iz++) {
8819 int found = 1;
8820 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
8821 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
8822 found = 0;
8823 break;
8824 }
8825 if (found) {
8826 if (iz > 0 && iz < 170)
8827 met->pt[ix][iy] = (float) p2[iz];
8828 break;
8829 }
8830 }
8831 }
8832 }
8833 }
8834
8835 /* Use dynamical tropopause... */
8836 else if (ctl->met_tropo == 5) {
8837
8838 /* Loop over grid points... */
8839#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
8840 for (int ix = 0; ix < met->nx; ix++)
8841 for (int iy = 0; iy < met->ny; iy++) {
8842
8843 /* Interpolate potential vorticity profile... */
8844 for (int iz = 0; iz < met->np; iz++)
8845 pv[iz] = met->pv[ix][iy][iz];
8846 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
8847
8848 /* Interpolate potential temperature profile... */
8849 for (int iz = 0; iz < met->np; iz++)
8850 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
8851 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
8852
8853 /* Find dynamical tropopause... */
8854 met->pt[ix][iy] = NAN;
8855 for (int iz = 0; iz <= 170; iz++)
8856 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
8857 || th2[iz] >= ctl->met_tropo_theta) {
8858 if (iz > 0 && iz < 170)
8859 met->pt[ix][iy] = (float) p2[iz];
8860 break;
8861 }
8862 }
8863 }
8864
8865 else
8866 ERRMSG("Cannot calculate tropopause!");
8867
8868 /* Interpolate temperature, geopotential height, and water vapor... */
8869#pragma omp parallel for default(shared) collapse(2)
8870 for (int ix = 0; ix < met->nx; ix++)
8871 for (int iy = 0; iy < met->ny; iy++) {
8872 double h2ot, tt, zt;
8874 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
8875 met->lat[iy], &tt, ci, cw, 1);
8876 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
8877 met->lat[iy], &zt, ci, cw, 0);
8878 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
8879 met->lat[iy], &h2ot, ci, cw, 0);
8880 met->tt[ix][iy] = (float) tt;
8881 met->zt[ix][iy] = (float) zt;
8882 met->h2ot[ix][iy] = (float) h2ot;
8883 }
8884}
8885
8886/*****************************************************************************/
8887
8889 const char *filename,
8890 const ctl_t *ctl,
8891 double *rt,
8892 double *rz,
8893 double *rlon,
8894 double *rlat,
8895 double *robs,
8896 int *nobs) {
8897
8898 /* Write info... */
8899 LOG(1, "Read observation data: %s", filename);
8900
8901 /* Read data... */
8902 if (ctl->obs_type == 0)
8903 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
8904 else if (ctl->obs_type == 1)
8905 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
8906 else
8907 ERRMSG("Set OBS_TYPE to 0 or 1!");
8908
8909 /* Check time... */
8910 for (int i = 1; i < *nobs; i++)
8911 if (rt[i] < rt[i - 1])
8912 ERRMSG("Time must be ascending!");
8913
8914 /* Write info... */
8915 int n = *nobs;
8916 double mini, maxi;
8917 LOG(2, "Number of observations: %d", *nobs);
8918 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
8919 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8920 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
8921 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
8922 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
8923 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
8924 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
8925 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
8926 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
8927 LOG(2, "Observation range: %g ... %g", mini, maxi);
8928}
8929
8930/*****************************************************************************/
8931
8933 const char *filename,
8934 double *rt,
8935 double *rz,
8936 double *rlon,
8937 double *rlat,
8938 double *robs,
8939 int *nobs) {
8940
8941 /* Open observation data file... */
8942 FILE *in;
8943 if (!(in = fopen(filename, "r")))
8944 ERRMSG("Cannot open file!");
8945
8946 /* Read observations... */
8947 char line[LEN];
8948 while (fgets(line, LEN, in))
8949 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
8950 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
8951 if ((++(*nobs)) >= NOBS)
8952 ERRMSG("Too many observations!");
8953
8954 /* Close observation data file... */
8955 fclose(in);
8956}
8957
8958/*****************************************************************************/
8959
8961 const char *filename,
8962 double *rt,
8963 double *rz,
8964 double *rlon,
8965 double *rlat,
8966 double *robs,
8967 int *nobs) {
8968
8969 int ncid, varid;
8970
8971 /* Open netCDF file... */
8972 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8973 ERRMSG("Cannot open file!");
8974
8975 /* Read the observations from the NetCDF file... */
8976 NC_INQ_DIM("nobs", nobs, 1, NOBS);
8977 NC_GET_DOUBLE("time", rt, 1);
8978 NC_GET_DOUBLE("alt", rz, 1);
8979 NC_GET_DOUBLE("lon", rlon, 1);
8980 NC_GET_DOUBLE("lat", rlat, 1);
8981 NC_GET_DOUBLE("obs", robs, 1);
8982
8983 /* Close file... */
8984 NC(nc_close(ncid));
8985}
8986
8987/*****************************************************************************/
8988
8990 const char *filename,
8991 int argc,
8992 char *argv[],
8993 const char *varname,
8994 const int arridx,
8995 const char *defvalue,
8996 char *value) {
8997
8998 FILE *in = NULL;
8999
9000 char fullname1[LEN], fullname2[LEN], rval[LEN];
9001
9002 int contain = 0, i;
9003
9004 /* Open file... */
9005 if (filename[strlen(filename) - 1] != '-')
9006 if (!(in = fopen(filename, "r")))
9007 ERRMSG("Cannot open file!");
9008
9009 /* Set full variable name... */
9010 if (arridx >= 0) {
9011 sprintf(fullname1, "%s[%d]", varname, arridx);
9012 sprintf(fullname2, "%s[*]", varname);
9013 } else {
9014 sprintf(fullname1, "%s", varname);
9015 sprintf(fullname2, "%s", varname);
9016 }
9017
9018 /* Read data... */
9019 if (in != NULL) {
9020 char dummy[LEN], line[LEN], rvarname[LEN];
9021 while (fgets(line, LEN, in)) {
9022 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
9023 if (strcasecmp(rvarname, fullname1) == 0 ||
9024 strcasecmp(rvarname, fullname2) == 0) {
9025 contain = 1;
9026 break;
9027 }
9028 }
9029 }
9030 for (i = 1; i < argc - 1; i++)
9031 if (strcasecmp(argv[i], fullname1) == 0 ||
9032 strcasecmp(argv[i], fullname2) == 0) {
9033 sprintf(rval, "%s", argv[i + 1]);
9034 contain = 1;
9035 break;
9036 }
9037
9038 /* Close file... */
9039 if (in != NULL)
9040 fclose(in);
9041
9042 /* Check for missing variables... */
9043 if (!contain) {
9044 if (strlen(defvalue) > 0)
9045 sprintf(rval, "%s", defvalue);
9046 else
9047 ERRMSG("Missing variable %s!\n", fullname1);
9048 }
9049
9050 /* Write info... */
9051 LOG(1, "%s = %s", fullname1, rval);
9052
9053 /* Return values... */
9054 if (value != NULL)
9055 sprintf(value, "%s", rval);
9056 return atof(rval);
9057}
9058
9059/*****************************************************************************/
9060
9061double sedi(
9062 const double p,
9063 const double T,
9064 const double rp,
9065 const double rhop) {
9066
9067 /* Convert particle radius from microns to m... */
9068 const double rp_help = rp * 1e-6;
9069
9070 /* Density of dry air [kg / m^3]... */
9071 const double rho = RHO(p, T);
9072
9073 /* Dynamic viscosity of air [kg / (m s)]... */
9074 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
9075
9076 /* Thermal velocity of an air molecule [m / s]... */
9077 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
9078
9079 /* Mean free path of an air molecule [m]... */
9080 const double lambda = 2. * eta / (rho * v);
9081
9082 /* Knudsen number for air (dimensionless)... */
9083 const double K = lambda / rp_help;
9084
9085 /* Cunningham slip-flow correction (dimensionless)... */
9086 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
9087
9088 /* Sedimentation velocity [m / s]... */
9089 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
9090}
9091
9092/*****************************************************************************/
9093
9095 const double *x,
9096 const double *y,
9097 const int n,
9098 const double *x2,
9099 double *y2,
9100 const int n2,
9101 const int method) {
9102
9103 /* Cubic spline interpolation... */
9104 if (method == 1) {
9105
9106 /* Allocate... */
9107 gsl_interp_accel *acc = gsl_interp_accel_alloc();
9108 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
9109
9110 /* Interpolate profile... */
9111 gsl_spline_init(s, x, y, (size_t) n);
9112 for (int i = 0; i < n2; i++)
9113 if (x2[i] <= x[0])
9114 y2[i] = y[0];
9115 else if (x2[i] >= x[n - 1])
9116 y2[i] = y[n - 1];
9117 else
9118 y2[i] = gsl_spline_eval(s, x2[i], acc);
9119
9120 /* Free... */
9121 gsl_spline_free(s);
9122 gsl_interp_accel_free(acc);
9123 }
9124
9125 /* Linear interpolation... */
9126 else {
9127 for (int i = 0; i < n2; i++)
9128 if (x2[i] <= x[0])
9129 y2[i] = y[0];
9130 else if (x2[i] >= x[n - 1])
9131 y2[i] = y[n - 1];
9132 else {
9133 int idx = locate_irr(x, n, x2[i]);
9134 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
9135 }
9136 }
9137}
9138
9139/*****************************************************************************/
9140
9142 const float *data,
9143 const int n) {
9144
9145 if (n <= 0)
9146 return 0;
9147
9148 float mean = 0, var = 0;
9149
9150 for (int i = 0; i < n; ++i) {
9151 mean += data[i];
9152 var += SQR(data[i]);
9153 }
9154
9155 var = var / (float) n - SQR(mean / (float) n);
9156
9157 return (var > 0 ? sqrtf(var) : 0);
9158}
9159
9160/*****************************************************************************/
9161
9163 const double sec,
9164 const double lon,
9165 const double lat) {
9166
9167 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
9168 const double D = sec / 86400 - 0.5;
9169
9170 /* Geocentric apparent ecliptic longitude [rad]... */
9171 const double g = DEG2RAD(357.529 + 0.98560028 * D);
9172 const double q = 280.459 + 0.98564736 * D;
9173 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
9174
9175 /* Mean obliquity of the ecliptic [rad]... */
9176 const double e = DEG2RAD(23.439 - 0.00000036 * D);
9177
9178 /* Declination [rad]... */
9179 const double sindec = sin(e) * sin(L);
9180
9181 /* Right ascension [rad]... */
9182 const double ra = atan2(cos(e) * sin(L), cos(L));
9183
9184 /* Greenwich Mean Sidereal Time [h]... */
9185 const double GMST = 18.697374558 + 24.06570982441908 * D;
9186
9187 /* Local Sidereal Time [h]... */
9188 const double LST = GMST + lon / 15;
9189
9190 /* Hour angle [rad]... */
9191 const double h = LST / 12 * M_PI - ra;
9192
9193 /* Convert latitude... */
9194 const double lat_help = DEG2RAD(lat);
9195
9196 /* Return solar zenith angle [rad]... */
9197 return acos(sin(lat_help) * sindec +
9198 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
9199}
9200
9201/*****************************************************************************/
9202
9204 const int year,
9205 const int mon,
9206 const int day,
9207 const int hour,
9208 const int min,
9209 const int sec,
9210 const double remain,
9211 double *jsec) {
9212
9213 struct tm t0, t1;
9214
9215 t0.tm_year = 100;
9216 t0.tm_mon = 0;
9217 t0.tm_mday = 1;
9218 t0.tm_hour = 0;
9219 t0.tm_min = 0;
9220 t0.tm_sec = 0;
9221
9222 t1.tm_year = year - 1900;
9223 t1.tm_mon = mon - 1;
9224 t1.tm_mday = day;
9225 t1.tm_hour = hour;
9226 t1.tm_min = min;
9227 t1.tm_sec = sec;
9228
9229 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
9230}
9231
9232/*****************************************************************************/
9233
9235 const char *name,
9236 const char *group,
9237 const int output) {
9238
9239 static char names[NTIMER][100], groups[NTIMER][100];
9240
9241 static double rt_name[NTIMER], rt_group[NTIMER],
9242 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
9243
9244 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
9245
9246 /* Get time... */
9247 t1 = omp_get_wtime();
9248 dt = t1 - t0;
9249
9250 /* Add elapsed time to current timers... */
9251 if (iname >= 0) {
9252 rt_name[iname] += dt;
9253 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
9254 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
9255 ct_name[iname]++;
9256 }
9257 if (igroup >= 0)
9258 rt_group[igroup] += t1 - t0;
9259
9260 /* Report timers... */
9261 if (output) {
9262 for (int i = 0; i < nname; i++)
9263 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
9264 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
9265 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
9266 for (int i = 0; i < ngroup; i++)
9267 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
9268 double total = 0.0;
9269 for (int i = 0; i < nname; i++)
9270 total += rt_name[i];
9271 LOG(1, "TIMER_TOTAL = %.3f s", total);
9272 }
9273
9274 /* Identify IDs of next timer... */
9275 for (iname = 0; iname < nname; iname++)
9276 if (strcasecmp(name, names[iname]) == 0)
9277 break;
9278 for (igroup = 0; igroup < ngroup; igroup++)
9279 if (strcasecmp(group, groups[igroup]) == 0)
9280 break;
9281
9282 /* Check whether this is a new timer... */
9283 if (iname >= nname) {
9284 sprintf(names[iname], "%s", name);
9285 if ((++nname) >= NTIMER)
9286 ERRMSG("Too many timers!");
9287 }
9288
9289 /* Check whether this is a new group... */
9290 if (igroup >= ngroup) {
9291 sprintf(groups[igroup], "%s", group);
9292 if ((++ngroup) >= NTIMER)
9293 ERRMSG("Too many groups!");
9294 }
9295
9296 /* Save starting time... */
9297 t0 = t1;
9298}
9299
9300/*****************************************************************************/
9301
9303 const char *filename,
9304 const int offset) {
9305
9306 char tstr[10];
9307
9308 double t;
9309
9310 /* Get time from filename... */
9311 int len = (int) strlen(filename);
9312 sprintf(tstr, "%.4s", &filename[len - offset]);
9313 int year = atoi(tstr);
9314 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
9315 int mon = atoi(tstr);
9316 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
9317 int day = atoi(tstr);
9318 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
9319 int hour = atoi(tstr);
9320 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
9321 int min = atoi(tstr);
9322
9323 /* Check time... */
9324 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
9325 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
9326 ERRMSG("Cannot read time from filename!");
9327
9328 /* Convert time to Julian seconds... */
9329 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
9330
9331 /* Return time... */
9332 return t;
9333}
9334
9335/*****************************************************************************/
9336
9338 const clim_t *clim,
9339 const atm_t *atm,
9340 const int ip) {
9341
9342 /* Get tropopause pressure... */
9343 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
9344
9345 /* Get pressure range... */
9346 const double p1 = pt * 0.866877899;
9347 const double p0 = pt / 0.866877899;
9348
9349 /* Get weighting factor... */
9350 if (atm->p[ip] > p0)
9351 return 1;
9352 else if (atm->p[ip] < p1)
9353 return 0;
9354 else
9355 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
9356}
9357
9358/*****************************************************************************/
9359
9361 const char *filename,
9362 const ctl_t *ctl,
9363 const atm_t *atm,
9364 const double t) {
9365
9366 FILE *out;
9367
9368 /* Set time interval for output... */
9369 const double t0 = t - 0.5 * ctl->dt_mod;
9370 const double t1 = t + 0.5 * ctl->dt_mod;
9371
9372 /* Check if gnuplot output is requested... */
9373 if (ctl->atm_gpfile[0] != '-') {
9374
9375 /* Create gnuplot pipe... */
9376 if (!(out = popen("gnuplot", "w")))
9377 ERRMSG("Cannot create pipe to gnuplot!");
9378
9379 /* Set plot filename... */
9380 fprintf(out, "set out \"%s.png\"\n", filename);
9381
9382 /* Set time string... */
9383 double r;
9384 int year, mon, day, hour, min, sec;
9385 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9386 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
9387 year, mon, day, hour, min);
9388
9389 /* Dump gnuplot file to pipe... */
9390 FILE *in;
9391 if (!(in = fopen(ctl->atm_gpfile, "r")))
9392 ERRMSG("Cannot open file!");
9393 char line[LEN];
9394 while (fgets(line, LEN, in))
9395 fprintf(out, "%s", line);
9396 fclose(in);
9397 }
9398
9399 else {
9400
9401 /* Create file... */
9402 if (!(out = fopen(filename, "w")))
9403 ERRMSG("Cannot create file!");
9404 }
9405
9406 /* Write header... */
9407 fprintf(out,
9408 "# $1 = time [s]\n"
9409 "# $2 = altitude [km]\n"
9410 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
9411 for (int iq = 0; iq < ctl->nq; iq++)
9412 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
9413 ctl->qnt_unit[iq]);
9414 fprintf(out, "\n");
9415
9416 /* Write data... */
9417 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
9418
9419 /* Check time... */
9420 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
9421 continue;
9422
9423 /* Write output... */
9424 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
9425 atm->lon[ip], atm->lat[ip]);
9426 for (int iq = 0; iq < ctl->nq; iq++) {
9427 fprintf(out, " ");
9428 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
9429 fprintf(out, ctl->qnt_format[iq], NAN);
9430 else
9431 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
9432 }
9433 fprintf(out, "\n");
9434 }
9435
9436 /* Close file... */
9437 fclose(out);
9438}
9439
9440/*****************************************************************************/
9441
9443 const char *filename,
9444 const ctl_t *ctl,
9445 const atm_t *atm) {
9446
9447 FILE *out;
9448
9449 /* Create file... */
9450 if (!(out = fopen(filename, "w")))
9451 ERRMSG("Cannot create file!");
9452
9453 /* Write version of binary data... */
9454 int version = 100;
9455 FWRITE(&version, int,
9456 1,
9457 out);
9458
9459 /* Write data... */
9460 FWRITE(&atm->np, int,
9461 1,
9462 out);
9463 FWRITE(atm->time, double,
9464 (size_t) atm->np,
9465 out);
9466 FWRITE(atm->p, double,
9467 (size_t) atm->np,
9468 out);
9469 FWRITE(atm->lon, double,
9470 (size_t) atm->np,
9471 out);
9472 FWRITE(atm->lat, double,
9473 (size_t) atm->np,
9474 out);
9475 for (int iq = 0; iq < ctl->nq; iq++)
9476 FWRITE(atm->q[iq], double,
9477 (size_t) atm->np,
9478 out);
9479
9480 /* Write final flag... */
9481 int final = 999;
9482 FWRITE(&final, int,
9483 1,
9484 out);
9485
9486 /* Close file... */
9487 fclose(out);
9488}
9489
9490/*****************************************************************************/
9491
9493 const char *filename,
9494 const ctl_t *ctl,
9495 const atm_t *atm) {
9496
9497 int tid, pid, ncid, varid;
9498 size_t start[2], count[2];
9499
9500 /* Create file... */
9501 nc_create(filename, NC_NETCDF4, &ncid);
9502
9503 /* Define dimensions... */
9504 NC(nc_def_dim(ncid, "time", 1, &tid));
9505 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9506
9507 /* Define variables and their attributes... */
9508 int dim_ids[2] = { tid, pid };
9509 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9510 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9511 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
9512 ctl->atm_nc_level, 0);
9513 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
9514 ctl->atm_nc_level, 0);
9515 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
9516 ctl->atm_nc_level, 0);
9517 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
9518 for (int iq = 0; iq < ctl->nq; iq++)
9519 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9520 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9521 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9522
9523 /* Define global attributes... */
9524 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9525 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9526
9527 /* End definitions... */
9528 NC(nc_enddef(ncid));
9529
9530 /* Write data... */
9531 NC_PUT_DOUBLE("time", atm->time, 0);
9532 NC_PUT_DOUBLE("LAT", atm->lat, 0);
9533 NC_PUT_DOUBLE("LON", atm->lon, 0);
9534 NC_PUT_DOUBLE("PRESS", atm->p, 0);
9535 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
9536 for (int iq = 0; iq < ctl->nq; iq++)
9537 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9538
9539 /* Close file... */
9540 NC(nc_close(ncid));
9541}
9542
9543/*****************************************************************************/
9544
9546 const char *dirname,
9547 const ctl_t *ctl,
9548 const atm_t *atm,
9549 const double t) {
9550
9551 /* Global Counter... */
9552 static size_t out_cnt = 0;
9553
9554 double r, r_start, r_stop;
9555 int year, mon, day, hour, min, sec;
9556 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
9557 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
9558 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
9559
9560 int ncid, varid, tid, pid, cid;
9561 int dim_ids[2];
9562
9563 /* time, nparc */
9564 size_t start[2];
9565 size_t count[2];
9566
9567 /* Determine start and stop times of calculation... */
9568 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9569 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
9570 &min_start, &sec_start, &r_start);
9571 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
9572 &min_stop, &sec_stop, &r_stop);
9573
9574 sprintf(filename_out, "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc",
9575 dirname,
9576 year_start % 100, mon_start, day_start, hour_start,
9577 year_stop % 100, mon_stop, day_stop, hour_stop);
9578 LOG(1, "Write traj file: %s", filename_out);
9579
9580 /* Define hyperslap for the traj_file... */
9581 start[0] = out_cnt;
9582 start[1] = 0;
9583 count[0] = 1;
9584 count[1] = (size_t) atm->np;
9585
9586 /* Create the file at the first timestep... */
9587 if (out_cnt == 0) {
9588
9589 /* Create file... */
9590 nc_create(filename_out, NC_NETCDF4, &ncid);
9591
9592 /* Define dimensions... */
9593 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
9594 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9595 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
9596 dim_ids[0] = tid;
9597 dim_ids[1] = pid;
9598
9599 /* Define variables and their attributes... */
9600 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9601 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9602 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
9603 ctl->atm_nc_level, 0);
9604 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
9605 ctl->atm_nc_level, 0);
9606 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
9607 ctl->atm_nc_level, 0);
9608 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
9609 ctl->atm_nc_level, 0);
9610 for (int iq = 0; iq < ctl->nq; iq++)
9611 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9612 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9613 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9614
9615 /* Define global attributes... */
9616 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9617 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9618
9619 /* End definitions... */
9620 NC(nc_enddef(ncid));
9621 NC(nc_close(ncid));
9622 }
9623
9624 /* Increment global counter to change hyperslap... */
9625 out_cnt++;
9626
9627 /* Open file... */
9628 NC(nc_open(filename_out, NC_WRITE, &ncid));
9629
9630 /* Write data... */
9631 NC_PUT_DOUBLE("time", atm->time, 1);
9632 NC_PUT_DOUBLE("LAT", atm->lat, 1);
9633 NC_PUT_DOUBLE("LON", atm->lon, 1);
9634 NC_PUT_DOUBLE("PRESS", atm->p, 1);
9635 if (ctl->advect_vert_coord == 1) {
9636 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
9637 } else if (ctl->qnt_zeta >= 0) {
9638 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
9639 }
9640 for (int iq = 0; iq < ctl->nq; iq++)
9641 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
9642
9643 /* Close file... */
9644 NC(nc_close(ncid));
9645
9646 /* At the last time step create the init_fix_YYYYMMDDHH file... */
9647 if ((year == year_stop) && (mon == mon_stop)
9648 && (day == day_stop) && (hour == hour_stop)) {
9649
9650 /* Set filename... */
9651 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
9652 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
9653 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
9654 LOG(1, "Write init file: %s", filename_init);
9655
9656 /* Create file... */
9657 nc_create(filename_init, NC_NETCDF4, &ncid);
9658
9659 /* Define dimensions... */
9660 NC(nc_def_dim(ncid, "time", 1, &tid));
9661 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9662 dim_ids[0] = tid;
9663 dim_ids[1] = pid;
9664
9665 /* Define variables and their attributes... */
9666 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9667 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9668 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
9669 ctl->atm_nc_level, 0);
9670 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
9671 ctl->atm_nc_level, 0);
9672 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
9673 ctl->atm_nc_level, 0);
9674 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
9675 for (int iq = 0; iq < ctl->nq; iq++)
9676 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9677 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9678 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9679
9680 /* Define global attributes... */
9681 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9682 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9683
9684 /* End definitions... */
9685 NC(nc_enddef(ncid));
9686
9687 /* Write data... */
9688 NC_PUT_DOUBLE("time", atm->time, 0);
9689 NC_PUT_DOUBLE("LAT", atm->lat, 0);
9690 NC_PUT_DOUBLE("LON", atm->lon, 0);
9691 NC_PUT_DOUBLE("PRESS", atm->p, 0);
9692 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
9693 for (int iq = 0; iq < ctl->nq; iq++)
9694 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9695
9696 /* Close file... */
9697 NC(nc_close(ncid));
9698 }
9699}
9700
9701/*****************************************************************************/
9702
9704 const char *filename,
9705 const ctl_t *ctl,
9706 const atm_t *atm) {
9707
9708 int ncid, obsid, varid;
9709
9710 size_t start[2], count[2];
9711
9712 /* Create file... */
9713 NC(nc_create(filename, NC_NETCDF4, &ncid));
9714
9715 /* Define dimensions... */
9716 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
9717
9718 /* Define variables and their attributes... */
9719 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
9720 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9721 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
9722 ctl->atm_nc_level, 0);
9723 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
9724 ctl->atm_nc_level, 0);
9725 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
9726 ctl->atm_nc_level, 0);
9727 for (int iq = 0; iq < ctl->nq; iq++)
9728 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
9729 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
9730 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9731
9732 /* Define global attributes... */
9733 NC_PUT_ATT_GLOBAL("featureType", "point");
9734
9735 /* End definitions... */
9736 NC(nc_enddef(ncid));
9737
9738 /* Write data... */
9739 NC_PUT_DOUBLE("time", atm->time, 0);
9740 NC_PUT_DOUBLE("press", atm->p, 0);
9741 NC_PUT_DOUBLE("lon", atm->lon, 0);
9742 NC_PUT_DOUBLE("lat", atm->lat, 0);
9743 for (int iq = 0; iq < ctl->nq; iq++)
9744 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9745
9746 /* Close file... */
9747 NC(nc_close(ncid));
9748}
9749
9750/*****************************************************************************/
9751
9753 const char *filename,
9754 const ctl_t *ctl,
9755 const atm_t *atm,
9756 const double t) {
9757
9758 static FILE *out;
9759
9760 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
9761 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
9762
9763 static int *obscount, ct, cx, cy, cz, ip, ix, iy, iz, n, nobs, nk;
9764
9765 /* Set timer... */
9766 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
9767
9768 /* Init... */
9769 if (t == ctl->t_start) {
9770
9771 /* Check quantity index for mass... */
9772 if (ctl->qnt_m < 0)
9773 ERRMSG("Need quantity mass!");
9774
9775 /* Allocate... */
9776 ALLOC(area, double,
9777 ctl->csi_ny);
9778 ALLOC(rt, double,
9779 NOBS);
9780 ALLOC(rz, double,
9781 NOBS);
9782 ALLOC(rlon, double,
9783 NOBS);
9784 ALLOC(rlat, double,
9785 NOBS);
9786 ALLOC(robs, double,
9787 NOBS);
9788
9789 /* Read observation data... */
9790 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
9791
9792 /* Read kernel data... */
9793 if (ctl->csi_kernel[0] != '-')
9794 read_kernel(ctl->csi_kernel, kz, kw, &nk);
9795
9796 /* Create new file... */
9797 LOG(1, "Write CSI data: %s", filename);
9798 if (!(out = fopen(filename, "w")))
9799 ERRMSG("Cannot create file!");
9800
9801 /* Write header... */
9802 fprintf(out,
9803 "# $1 = time [s]\n"
9804 "# $2 = number of hits (cx)\n"
9805 "# $3 = number of misses (cy)\n"
9806 "# $4 = number of false alarms (cz)\n"
9807 "# $5 = number of observations (cx + cy)\n"
9808 "# $6 = number of forecasts (cx + cz)\n"
9809 "# $7 = bias (ratio of forecasts and observations) [%%]\n"
9810 "# $8 = probability of detection (POD) [%%]\n"
9811 "# $9 = false alarm rate (FAR) [%%]\n"
9812 "# $10 = critical success index (CSI) [%%]\n");
9813 fprintf(out,
9814 "# $11 = hits associated with random chance\n"
9815 "# $12 = equitable threat score (ETS) [%%]\n"
9816 "# $13 = Pearson linear correlation coefficient\n"
9817 "# $14 = Spearman rank-order correlation coefficient\n"
9818 "# $15 = column density mean error (F - O) [kg/m^2]\n"
9819 "# $16 = column density root mean square error (RMSE) [kg/m^2]\n"
9820 "# $17 = column density mean absolute error [kg/m^2]\n"
9821 "# $18 = log-likelihood function\n"
9822 "# $19 = number of data points\n\n");
9823
9824 /* Set grid box size... */
9825 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
9826 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
9827 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
9828
9829 /* Set horizontal coordinates... */
9830 for (iy = 0; iy < ctl->csi_ny; iy++) {
9831 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
9832 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat));
9833 }
9834 }
9835
9836 /* Set time interval... */
9837 const double t0 = t - 0.5 * ctl->dt_mod;
9838 const double t1 = t + 0.5 * ctl->dt_mod;
9839
9840 /* Allocate... */
9841 ALLOC(modmean, double,
9842 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9843 ALLOC(obsmean, double,
9844 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9845 ALLOC(obscount, int,
9846 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9847 ALLOC(obsstd, double,
9848 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9849
9850 /* Loop over observations... */
9851 for (int i = 0; i < nobs; i++) {
9852
9853 /* Check time... */
9854 if (rt[i] < t0)
9855 continue;
9856 else if (rt[i] >= t1)
9857 break;
9858
9859 /* Check observation data... */
9860 if (!isfinite(robs[i]))
9861 continue;
9862
9863 /* Calculate indices... */
9864 ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
9865 iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
9866 iz = (int) ((rz[i] - ctl->csi_z0) / dz);
9867
9868 /* Check indices... */
9869 if (ix < 0 || ix >= ctl->csi_nx ||
9870 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9871 continue;
9872
9873 /* Get mean observation index... */
9874 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9875 obsmean[idx] += robs[i];
9876 obsstd[idx] += SQR(robs[i]);
9877 obscount[idx]++;
9878 }
9879
9880 /* Analyze model data... */
9881 for (ip = 0; ip < atm->np; ip++) {
9882
9883 /* Check time... */
9884 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9885 continue;
9886
9887 /* Get indices... */
9888 ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
9889 iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
9890 iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
9891
9892 /* Check indices... */
9893 if (ix < 0 || ix >= ctl->csi_nx ||
9894 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9895 continue;
9896
9897 /* Get total mass in grid cell... */
9898 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9899 modmean[idx] += kernel_weight(kz, kw, nk, atm->p[ip])
9900 * atm->q[ctl->qnt_m][ip];
9901 }
9902
9903 /* Analyze all grid cells... */
9904 for (ix = 0; ix < ctl->csi_nx; ix++)
9905 for (iy = 0; iy < ctl->csi_ny; iy++)
9906 for (iz = 0; iz < ctl->csi_nz; iz++) {
9907
9908 /* Calculate mean observation index... */
9909 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9910 if (obscount[idx] > 0) {
9911 obsmean[idx] /= obscount[idx];
9912 obsstd[idx] -= SQR(obsmean[idx]);
9913 obsstd[idx] = sqrt(obsstd[idx]);
9914 }
9915
9916 /* Calculate column density... */
9917 if (modmean[idx] > 0)
9918 modmean[idx] /= (1e6 * area[iy]);
9919
9920 /* Calculate CSI... */
9921 if (obscount[idx] > 0) {
9922 ct++;
9923 if (obsmean[idx] >= ctl->csi_obsmin &&
9924 modmean[idx] >= ctl->csi_modmin)
9925 cx++;
9926 else if (obsmean[idx] >= ctl->csi_obsmin &&
9927 modmean[idx] < ctl->csi_modmin)
9928 cy++;
9929 else if (obsmean[idx] < ctl->csi_obsmin &&
9930 modmean[idx] >= ctl->csi_modmin)
9931 cz++;
9932 }
9933
9934 /* Save data for other verification statistics... */
9935 if (obscount[idx] > 0
9936 && (obsmean[idx] >= ctl->csi_obsmin
9937 || modmean[idx] >= ctl->csi_modmin)) {
9938 x[n] = modmean[idx];
9939 y[n] = obsmean[idx];
9940 if (modmean[idx] >= ctl->csi_modmin)
9941 obsstdn[n] = obsstd[idx];
9942 if ((++n) >= NCSI)
9943 ERRMSG("Too many data points to calculate statistics!");
9944 }
9945 }
9946
9947 /* Write output... */
9948 if (fmod(t, ctl->csi_dt_out) == 0) {
9949
9950 /* Calculate verification statistics
9951 (https://www.cawcr.gov.au/projects/verification/) ... */
9952 static double work[2 * NCSI], work2[2 * NCSI];;
9953 const int n_obs = cx + cy;
9954 const int n_for = cx + cz;
9955 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
9956 const double pod = (n_obs > 0) ? (100. * cx) / n_obs : NAN;
9957 const double far = (n_for > 0) ? (100. * cz) / n_for : NAN;
9958 const double csi =
9959 (cx + cy + cz > 0) ? (100. * cx) / (cx + cy + cz) : NAN;
9960 const double cx_rd = (ct > 0) ? (1. * n_obs * n_for) / ct : NAN;
9961 const double ets = (cx + cy + cz - cx_rd > 0) ?
9962 (100. * (cx - cx_rd)) / (cx + cy + cz - cx_rd) : NAN;
9963 const double rho_p =
9964 (n > 0) ? gsl_stats_correlation(x, 1, y, 1, (size_t) n) : NAN;
9965 const double rho_s =
9966 (n > 0) ? gsl_stats_spearman(x, 1, y, 1, (size_t) n, work) : NAN;
9967 for (int i = 0; i < n; i++) {
9968 work[i] = x[i] - y[i];
9969 work2[i] = (obsstdn[i] != 0) ? (x[i] - y[i]) / obsstdn[i] : 0;
9970 }
9971 const double mean = (n > 0) ? gsl_stats_mean(work, 1, (size_t) n) : NAN;
9972 const double rmse =
9973 (n > 0) ? gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n,
9974 0.0) : NAN;
9975 const double absdev =
9976 (n > 0) ? gsl_stats_absdev_m(work, 1, (size_t) n, 0.0) : NAN;
9977 const double loglikelihood =
9978 (n > 0) ? gsl_stats_tss(work2, 1, (size_t) n) * (-0.5) : GSL_NAN;
9979
9980 /* Write... */
9981 fprintf(out,
9982 "%.2f %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n", t,
9983 cx, cy, cz, n_obs, n_for, bias, pod, far, csi, cx_rd, ets, rho_p,
9984 rho_s, mean, rmse, absdev, loglikelihood, n);
9985
9986 /* Set counters to zero... */
9987 n = ct = cx = cy = cz = 0;
9988 }
9989
9990 /* Free... */
9991 free(modmean);
9992 free(obsmean);
9993 free(obscount);
9994 free(obsstd);
9995
9996 /* Finalize... */
9997 if (t == ctl->t_stop) {
9998
9999 /* Close output file... */
10000 fclose(out);
10001
10002 /* Free... */
10003 free(area);
10004 free(rt);
10005 free(rz);
10006 free(rlon);
10007 free(rlat);
10008 free(robs);
10009 }
10010}
10011
10012/*****************************************************************************/
10013
10015 const char *filename,
10016 const ctl_t *ctl,
10017 const atm_t *atm,
10018 const double t) {
10019
10020 static FILE *out;
10021
10022 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
10023 x[3], zm[NENS];
10024
10025 static int n[NENS];
10026
10027 /* Set timer... */
10028 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
10029
10030 /* Check quantities... */
10031 if (ctl->qnt_ens < 0)
10032 ERRMSG("Missing ensemble IDs!");
10033
10034 /* Set time interval... */
10035 const double t0 = t - 0.5 * ctl->dt_mod;
10036 const double t1 = t + 0.5 * ctl->dt_mod;
10037
10038 /* Init... */
10039 for (int i = 0; i < NENS; i++) {
10040 for (int iq = 0; iq < ctl->nq; iq++)
10041 qm[iq][i] = qs[iq][i] = 0;
10042 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
10043 n[i] = 0;
10044 }
10045
10046 /* Loop over air parcels... */
10047 for (int ip = 0; ip < atm->np; ip++) {
10048
10049 /* Check time... */
10050 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10051 continue;
10052
10053 /* Check ensemble ID... */
10054 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
10055 ERRMSG("Ensemble ID is out of range!");
10056
10057 /* Get means... */
10058 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
10059 for (int iq = 0; iq < ctl->nq; iq++) {
10060 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
10061 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
10062 }
10063 xm[ctl->qnt_ens][0] += x[0];
10064 xm[ctl->qnt_ens][1] += x[1];
10065 xm[ctl->qnt_ens][2] += x[2];
10066 zm[ctl->qnt_ens] += Z(atm->p[ip]);
10067 n[ctl->qnt_ens]++;
10068 }
10069
10070 /* Create file... */
10071 LOG(1, "Write ensemble data: %s", filename);
10072 if (!(out = fopen(filename, "w")))
10073 ERRMSG("Cannot create file!");
10074
10075 /* Write header... */
10076 fprintf(out,
10077 "# $1 = time [s]\n"
10078 "# $2 = altitude [km]\n"
10079 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
10080 for (int iq = 0; iq < ctl->nq; iq++)
10081 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
10082 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10083 for (int iq = 0; iq < ctl->nq; iq++)
10084 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
10085 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10086 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
10087
10088 /* Write data... */
10089 for (int i = 0; i < NENS; i++)
10090 if (n[i] > 0) {
10091 cart2geo(xm[i], &dummy, &lon, &lat);
10092 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
10093 for (int iq = 0; iq < ctl->nq; iq++) {
10094 fprintf(out, " ");
10095 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
10096 }
10097 for (int iq = 0; iq < ctl->nq; iq++) {
10098 fprintf(out, " ");
10099 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
10100 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
10101 }
10102 fprintf(out, " %d\n", n[i]);
10103 }
10104
10105 /* Close file... */
10106 fclose(out);
10107}
10108
10109/*****************************************************************************/
10110
10112 const char *filename,
10113 const ctl_t *ctl,
10114 met_t *met0,
10115 met_t *met1,
10116 const atm_t *atm,
10117 const double t) {
10118
10119 static double kz[EP], kw[EP];
10120
10121 static int nk;
10122
10123 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
10124
10125 int *ixs, *iys, *izs, *np;
10126
10127 /* Set timer... */
10128 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
10129
10130 /* Write info... */
10131 LOG(1, "Write grid data: %s", filename);
10132
10133 /* Init... */
10134 if (t == ctl->t_start) {
10135
10136 /* Read kernel data... */
10137 if (ctl->grid_kernel[0] != '-')
10138 read_kernel(ctl->grid_kernel, kz, kw, &nk);
10139 }
10140
10141 /* Allocate... */
10142 ALLOC(cd, double,
10143 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10144 for (int iq = 0; iq < ctl->nq; iq++) {
10145 ALLOC(mean[iq], double,
10146 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10147 ALLOC(sigma[iq], double,
10148 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10149 }
10150 ALLOC(vmr_impl, double,
10151 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10152 ALLOC(z, double,
10153 ctl->grid_nz);
10154 ALLOC(lon, double,
10155 ctl->grid_nx);
10156 ALLOC(lat, double,
10157 ctl->grid_ny);
10158 ALLOC(area, double,
10159 ctl->grid_ny);
10160 ALLOC(press, double,
10161 ctl->grid_nz);
10162 ALLOC(np, int,
10163 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10164 ALLOC(ixs, int,
10165 atm->np);
10166 ALLOC(iys, int,
10167 atm->np);
10168 ALLOC(izs, int,
10169 atm->np);
10170
10171 /* Set grid box size... */
10172 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
10173 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
10174 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
10175
10176 /* Set vertical coordinates... */
10177#pragma omp parallel for default(shared)
10178 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10179 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
10180 press[iz] = P(z[iz]);
10181 }
10182
10183 /* Set horizontal coordinates... */
10184 for (int ix = 0; ix < ctl->grid_nx; ix++)
10185 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
10186#pragma omp parallel for default(shared)
10187 for (int iy = 0; iy < ctl->grid_ny; iy++) {
10188 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
10189 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
10190 }
10191
10192 /* Set time interval for output... */
10193 const double t0 = t - 0.5 * ctl->dt_mod;
10194 const double t1 = t + 0.5 * ctl->dt_mod;
10195
10196 /* Get grid box indices... */
10197#pragma omp parallel for default(shared)
10198 for (int ip = 0; ip < atm->np; ip++) {
10199 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
10200 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
10201 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
10202 if (atm->time[ip] < t0 || atm->time[ip] > t1
10203 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
10204 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
10205 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
10206 izs[ip] = -1;
10207 }
10208
10209 /* Average data... */
10210 for (int ip = 0; ip < atm->np; ip++)
10211 if (izs[ip] >= 0) {
10212 int idx =
10213 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
10214 double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
10215 np[idx]++;
10216 for (int iq = 0; iq < ctl->nq; iq++) {
10217 mean[iq][idx] += kernel * atm->q[iq][ip];
10218 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
10219 }
10220 }
10221
10222 /* Calculate column density and volume mixing ratio... */
10223#pragma omp parallel for default(shared)
10224 for (int ix = 0; ix < ctl->grid_nx; ix++)
10225 for (int iy = 0; iy < ctl->grid_ny; iy++)
10226 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10227
10228 /* Get grid index... */
10229 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
10230
10231 /* Calculate column density... */
10232 cd[idx] = NAN;
10233 if (ctl->qnt_m >= 0)
10234 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
10235
10236 /* Calculate volume mixing ratio (implicit)... */
10237 vmr_impl[idx] = NAN;
10238 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
10239 && met1 != NULL) {
10240 vmr_impl[idx] = 0;
10241 if (mean[ctl->qnt_m][idx] > 0) {
10242
10243 /* Get temperature... */
10244 double temp;
10246 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
10247 lon[ix], lat[iy], &temp, ci, cw, 1);
10248
10249 /* Calculate volume mixing ratio... */
10250 vmr_impl[idx] =
10251 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
10252 }
10253 }
10254
10255 /* Calculate mean... */
10256 if (np[idx] > 0)
10257 for (int iq = 0; iq < ctl->nq; iq++) {
10258 mean[iq][idx] /= np[idx];
10259 double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
10260 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
10261 } else
10262 for (int iq = 0; iq < ctl->nq; iq++) {
10263 mean[iq][idx] = NAN;
10264 sigma[iq][idx] = NAN;
10265 }
10266 }
10267
10268 /* Write ASCII data... */
10269 if (ctl->grid_type == 0)
10270 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
10271 t, z, lon, lat, area, dz, np);
10272
10273 /* Write netCDF data... */
10274 else if (ctl->grid_type == 1)
10275 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
10276 t, z, lon, lat, area, dz, np);
10277
10278 /* Error message... */
10279 else
10280 ERRMSG("Grid data format GRID_TYPE unknown!");
10281
10282 /* Free... */
10283 free(cd);
10284 for (int iq = 0; iq < ctl->nq; iq++) {
10285 free(mean[iq]);
10286 free(sigma[iq]);
10287 }
10288 free(vmr_impl);
10289 free(z);
10290 free(lon);
10291 free(lat);
10292 free(area);
10293 free(press);
10294 free(np);
10295 free(ixs);
10296 free(iys);
10297 free(izs);
10298}
10299
10300/*****************************************************************************/
10301
10303 const char *filename,
10304 const ctl_t *ctl,
10305 const double *cd,
10306 double *mean[NQ],
10307 double *sigma[NQ],
10308 const double *vmr_impl,
10309 const double t,
10310 const double *z,
10311 const double *lon,
10312 const double *lat,
10313 const double *area,
10314 const double dz,
10315 const int *np) {
10316
10317 FILE *out;
10318
10319 /* Check if gnuplot output is requested... */
10320 if (ctl->grid_gpfile[0] != '-') {
10321
10322 /* Create gnuplot pipe... */
10323 if (!(out = popen("gnuplot", "w")))
10324 ERRMSG("Cannot create pipe to gnuplot!");
10325
10326 /* Set plot filename... */
10327 fprintf(out, "set out \"%s.png\"\n", filename);
10328
10329 /* Set time string... */
10330 double r;
10331 int year, mon, day, hour, min, sec;
10332 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
10333 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
10334 year, mon, day, hour, min);
10335
10336 /* Dump gnuplot file to pipe... */
10337 FILE *in;
10338 char line[LEN];
10339 if (!(in = fopen(ctl->grid_gpfile, "r")))
10340 ERRMSG("Cannot open file!");
10341 while (fgets(line, LEN, in))
10342 fprintf(out, "%s", line);
10343 fclose(in);
10344 }
10345
10346 else {
10347
10348 /* Create file... */
10349 if (!(out = fopen(filename, "w")))
10350 ERRMSG("Cannot create file!");
10351 }
10352
10353 /* Write header... */
10354 fprintf(out,
10355 "# $1 = time [s]\n"
10356 "# $2 = altitude [km]\n"
10357 "# $3 = longitude [deg]\n"
10358 "# $4 = latitude [deg]\n"
10359 "# $5 = surface area [km^2]\n"
10360 "# $6 = layer depth [km]\n"
10361 "# $7 = column density (implicit) [kg/m^2]\n"
10362 "# $8 = volume mixing ratio (implicit) [ppv]\n"
10363 "# $9 = number of particles [1]\n");
10364 for (int iq = 0; iq < ctl->nq; iq++)
10365 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
10366 ctl->qnt_unit[iq]);
10367 if (ctl->grid_stddev)
10368 for (int iq = 0; iq < ctl->nq; iq++)
10369 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
10370 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10371 fprintf(out, "\n");
10372
10373 /* Write data... */
10374 for (int ix = 0; ix < ctl->grid_nx; ix++) {
10375 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
10376 fprintf(out, "\n");
10377 for (int iy = 0; iy < ctl->grid_ny; iy++) {
10378 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
10379 fprintf(out, "\n");
10380 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10381 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
10382 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
10383 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
10384 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
10385 for (int iq = 0; iq < ctl->nq; iq++) {
10386 fprintf(out, " ");
10387 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
10388 }
10389 if (ctl->grid_stddev)
10390 for (int iq = 0; iq < ctl->nq; iq++) {
10391 fprintf(out, " ");
10392 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
10393 }
10394 fprintf(out, "\n");
10395 }
10396 }
10397 }
10398 }
10399
10400 /* Close file... */
10401 fclose(out);
10402}
10403
10404/*****************************************************************************/
10405
10407 const char *filename,
10408 const ctl_t *ctl,
10409 const double *cd,
10410 double *mean[NQ],
10411 double *sigma[NQ],
10412 const double *vmr_impl,
10413 const double t,
10414 const double *z,
10415 const double *lon,
10416 const double *lat,
10417 const double *area,
10418 const double dz,
10419 const int *np) {
10420
10421 char longname[2 * LEN], varname[2 * LEN];
10422
10423 double *help;
10424
10425 int *help2, ncid, dimid[10], varid;
10426
10427 size_t start[2], count[2];
10428
10429 /* Allocate... */
10430 ALLOC(help, double,
10431 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10432 ALLOC(help2, int,
10433 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10434
10435 /* Create file... */
10436 NC(nc_create(filename, NC_NETCDF4, &ncid));
10437
10438 /* Define dimensions... */
10439 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
10440 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
10441 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
10442 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
10443 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
10444
10445 /* Define variables and their attributes... */
10446 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
10447 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
10448 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
10449 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
10450 0);
10451 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
10452 0);
10453 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
10454 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
10455
10456 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
10457 ctl->grid_nc_level, 0);
10458 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid, "volume mixing ratio (implicit)",
10459 "ppv", ctl->grid_nc_level, 0);
10460 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
10461 for (int iq = 0; iq < ctl->nq; iq++) {
10462 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
10463 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
10464 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
10465 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
10466 if (ctl->grid_stddev) {
10467 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
10468 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
10469 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
10470 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
10471 }
10472 }
10473 /* End definitions... */
10474 NC(nc_enddef(ncid));
10475
10476 /* Write data... */
10477 NC_PUT_DOUBLE("time", &t, 0);
10478 NC_PUT_DOUBLE("lon", lon, 0);
10479 NC_PUT_DOUBLE("lat", lat, 0);
10480 NC_PUT_DOUBLE("z", z, 0);
10481 NC_PUT_DOUBLE("area", area, 0);
10482 NC_PUT_DOUBLE("dz", &dz, 0);
10483
10484 for (int ix = 0; ix < ctl->grid_nx; ix++)
10485 for (int iy = 0; iy < ctl->grid_ny; iy++)
10486 for (int iz = 0; iz < ctl->grid_nz; iz++)
10487 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10488 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10489 NC_PUT_DOUBLE("cd", help, 0);
10490
10491 for (int ix = 0; ix < ctl->grid_nx; ix++)
10492 for (int iy = 0; iy < ctl->grid_ny; iy++)
10493 for (int iz = 0; iz < ctl->grid_nz; iz++)
10494 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10495 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10496 NC_PUT_DOUBLE("vmr_impl", help, 0);
10497
10498 for (int ix = 0; ix < ctl->grid_nx; ix++)
10499 for (int iy = 0; iy < ctl->grid_ny; iy++)
10500 for (int iz = 0; iz < ctl->grid_nz; iz++)
10501 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10502 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10503 NC_PUT_INT("np", help2, 0);
10504
10505 for (int iq = 0; iq < ctl->nq; iq++) {
10506 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
10507 for (int ix = 0; ix < ctl->grid_nx; ix++)
10508 for (int iy = 0; iy < ctl->grid_ny; iy++)
10509 for (int iz = 0; iz < ctl->grid_nz; iz++)
10510 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10511 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10512 NC_PUT_DOUBLE(varname, help, 0);
10513 }
10514
10515 if (ctl->grid_stddev)
10516 for (int iq = 0; iq < ctl->nq; iq++) {
10517 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
10518 for (int ix = 0; ix < ctl->grid_nx; ix++)
10519 for (int iy = 0; iy < ctl->grid_ny; iy++)
10520 for (int iz = 0; iz < ctl->grid_nz; iz++)
10521 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10522 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10523 NC_PUT_DOUBLE(varname, help, 0);
10524 }
10525
10526 /* Close file... */
10527 NC(nc_close(ncid));
10528
10529 /* Free... */
10530 free(help);
10531 free(help2);
10532}
10533
10534/*****************************************************************************/
10535
10537 const char *filename,
10538 const ctl_t *ctl,
10539 met_t *met) {
10540
10541 /* Create file... */
10542 FILE *out;
10543 if (!(out = fopen(filename, "w")))
10544 ERRMSG("Cannot create file!");
10545
10546 /* Write type of binary data... */
10547 FWRITE(&ctl->met_type, int,
10548 1,
10549 out);
10550
10551 /* Write version of binary data... */
10552 int version = 103;
10553 FWRITE(&version, int,
10554 1,
10555 out);
10556
10557 /* Write grid data... */
10558 FWRITE(&met->time, double,
10559 1,
10560 out);
10561 FWRITE(&met->nx, int,
10562 1,
10563 out);
10564 FWRITE(&met->ny, int,
10565 1,
10566 out);
10567 FWRITE(&met->np, int,
10568 1,
10569 out);
10570 FWRITE(met->lon, double,
10571 (size_t) met->nx,
10572 out);
10573 FWRITE(met->lat, double,
10574 (size_t) met->ny,
10575 out);
10576 FWRITE(met->p, double,
10577 (size_t) met->np,
10578 out);
10579
10580 /* Write surface data... */
10581 write_met_bin_2d(out, met, met->ps, "PS");
10582 write_met_bin_2d(out, met, met->ts, "TS");
10583 write_met_bin_2d(out, met, met->zs, "ZS");
10584 write_met_bin_2d(out, met, met->us, "US");
10585 write_met_bin_2d(out, met, met->vs, "VS");
10586 write_met_bin_2d(out, met, met->ess, "ESS");
10587 write_met_bin_2d(out, met, met->nss, "NSS");
10588 write_met_bin_2d(out, met, met->shf, "SHF");
10589 write_met_bin_2d(out, met, met->lsm, "LSM");
10590 write_met_bin_2d(out, met, met->sst, "SST");
10591 write_met_bin_2d(out, met, met->pbl, "PBL");
10592 write_met_bin_2d(out, met, met->pt, "PT");
10593 write_met_bin_2d(out, met, met->tt, "TT");
10594 write_met_bin_2d(out, met, met->zt, "ZT");
10595 write_met_bin_2d(out, met, met->h2ot, "H2OT");
10596 write_met_bin_2d(out, met, met->pct, "PCT");
10597 write_met_bin_2d(out, met, met->pcb, "PCB");
10598 write_met_bin_2d(out, met, met->cl, "CL");
10599 write_met_bin_2d(out, met, met->plcl, "PLCL");
10600 write_met_bin_2d(out, met, met->plfc, "PLFC");
10601 write_met_bin_2d(out, met, met->pel, "PEL");
10602 write_met_bin_2d(out, met, met->cape, "CAPE");
10603 write_met_bin_2d(out, met, met->cin, "CIN");
10604 write_met_bin_2d(out, met, met->o3c, "O3C");
10605
10606 /* Write level data... */
10607 write_met_bin_3d(out, ctl, met, met->z, "Z",
10608 (ctl->met_zfp_tol_z <= 0 ? ctl->met_zfp_prec : 0),
10609 ctl->met_zfp_tol_z);
10610 write_met_bin_3d(out, ctl, met, met->t, "T",
10611 (ctl->met_zfp_tol_t <= 0 ? ctl->met_zfp_prec : 0),
10612 ctl->met_zfp_tol_t);
10613 write_met_bin_3d(out, ctl, met, met->u, "U", ctl->met_zfp_prec, 0);
10614 write_met_bin_3d(out, ctl, met, met->v, "V", ctl->met_zfp_prec, 0);
10615 write_met_bin_3d(out, ctl, met, met->w, "W", ctl->met_zfp_prec, 0);
10616 write_met_bin_3d(out, ctl, met, met->pv, "PV", ctl->met_zfp_prec, 0);
10617 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", ctl->met_zfp_prec, 0);
10618 write_met_bin_3d(out, ctl, met, met->o3, "O3", ctl->met_zfp_prec, 0);
10619 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", ctl->met_zfp_prec, 0);
10620 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", ctl->met_zfp_prec, 0);
10621 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", ctl->met_zfp_prec, 0);
10622 write_met_bin_3d(out, ctl, met, met->swc, "SWC", ctl->met_zfp_prec, 0);
10623 write_met_bin_3d(out, ctl, met, met->cc, "CC", ctl->met_zfp_prec, 0);
10624
10625 /* Write final flag... */
10626 int final = 999;
10627 FWRITE(&final, int,
10628 1,
10629 out);
10630
10631 /* Close file... */
10632 fclose(out);
10633}
10634
10635/*****************************************************************************/
10636
10638 FILE *out,
10639 met_t *met,
10640 float var[EX][EY],
10641 const char *varname) {
10642
10643 float *help;
10644
10645 /* Allocate... */
10646 ALLOC(help, float,
10647 EX * EY);
10648
10649 /* Copy data... */
10650 for (int ix = 0; ix < met->nx; ix++)
10651 for (int iy = 0; iy < met->ny; iy++)
10652 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
10653
10654 /* Write uncompressed data... */
10655 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
10656 FWRITE(help, float,
10657 (size_t) (met->nx * met->ny),
10658 out);
10659
10660 /* Free... */
10661 free(help);
10662}
10663
10664/*****************************************************************************/
10665
10667 FILE *out,
10668 const ctl_t *ctl,
10669 met_t *met,
10670 float var[EX][EY][EP],
10671 const char *varname,
10672 const int precision,
10673 const double tolerance) {
10674
10675 float *help;
10676
10677 /* Allocate... */
10678 ALLOC(help, float,
10679 EX * EY * EP);
10680
10681 /* Copy data... */
10682#pragma omp parallel for default(shared) collapse(2)
10683 for (int ix = 0; ix < met->nx; ix++)
10684 for (int iy = 0; iy < met->ny; iy++)
10685 for (int ip = 0; ip < met->np; ip++)
10686 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
10687
10688 /* Write uncompressed data... */
10689 if (ctl->met_type == 1) {
10690 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
10691 FWRITE(help, float,
10692 (size_t) (met->nx * met->ny * met->np),
10693 out);
10694 }
10695
10696 /* Write packed data... */
10697 else if (ctl->met_type == 2)
10698 compress_pck(varname, help, (size_t) (met->ny * met->nx),
10699 (size_t) met->np, 0, out);
10700
10701 /* Write zfp data... */
10702#ifdef ZFP
10703 else if (ctl->met_type == 3) {
10704 FWRITE(&precision, int,
10705 1,
10706 out);
10707 FWRITE(&tolerance, double,
10708 1,
10709 out);
10710 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
10711 tolerance, 0, out);
10712 }
10713#endif
10714
10715 /* Write zstd data... */
10716#ifdef ZSTD
10717 else if (ctl->met_type == 4)
10718 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
10719 ctl->met_zstd_level, out);
10720#endif
10721
10722 /* Write cmultiscale data... */
10723#ifdef CMS
10724 else if (ctl->met_type == 5) {
10725 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
10726 (size_t) met->np, 0, out);
10727 }
10728#endif
10729
10730 /* Unknown method... */
10731 else {
10732 ERRMSG("MET_TYPE not supported!");
10733 LOG(3, "%d %g", precision, tolerance);
10734 }
10735
10736 /* Free... */
10737 free(help);
10738}
10739
10740/*****************************************************************************/
10741
10743 const char *filename,
10744 const ctl_t *ctl,
10745 met_t *met) {
10746
10747 /* Create file... */
10748 int ncid, varid;
10749 size_t start[4], count[4];
10750 nc_create(filename, NC_NETCDF4, &ncid);
10751
10752 /* Define dimensions... */
10753 int tid, lonid, latid, levid;
10754 NC(nc_def_dim(ncid, "time", 1, &tid));
10755 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
10756 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
10757 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
10758
10759 /* Define grid... */
10760 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
10761 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
10762 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
10763 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
10764 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
10765
10766 /* Define surface variables... */
10767 int dimid2[2] = { latid, lonid };
10768 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
10769 ctl->met_nc_level, 0);
10770 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
10771 ctl->met_nc_level, 0);
10772 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
10773 ctl->met_nc_level, 0);
10774 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
10775 "m s**-1", ctl->met_nc_level, 0);
10776 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
10777 "m s**-1", ctl->met_nc_level, 0);
10778 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
10779 "Instantaneous eastward turbulent surface stress", "N m**-2",
10780 ctl->met_nc_level, 0);
10781 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
10782 "Instantaneous northward turbulent surface stress", "N m**-2",
10783 ctl->met_nc_level, 0);
10784 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
10785 "Instantaneous surface sensible heat flux", "W m**-1",
10786 ctl->met_nc_level, 0);
10787 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
10788 ctl->met_nc_level, 0);
10789 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
10790 ctl->met_nc_level, 0);
10791 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
10792 ctl->met_nc_level, 0);
10793 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
10794 ctl->met_nc_level, 0);
10795 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
10796 ctl->met_nc_level, 0);
10797 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
10798 ctl->met_nc_level, 0);
10799 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
10800 ctl->met_nc_level, 0);
10801 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
10802 ctl->met_nc_level, 0);
10803 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
10804 ctl->met_nc_level, 0);
10805 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water", "kg m**2",
10806 ctl->met_nc_level, 0);
10807 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
10808 "Pressure at lifted condensation level (LCL)", "Pa",
10809 ctl->met_nc_level, 0);
10810 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
10811 "Pressure at level of free convection (LFC)", "Pa",
10812 ctl->met_nc_level, 0);
10813 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2, "Pressure at equilibrium level (EL)",
10814 "Pa", ctl->met_nc_level, 0);
10815 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
10816 "Convective available potential energy", "J kg**-1",
10817 ctl->met_nc_level, 0);
10818 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition", "J kg**-1",
10819 ctl->met_nc_level, 0);
10820 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
10821 ctl->met_nc_level, 0);
10822
10823 /* Define level data... */
10824 int dimid3[3] = { levid, latid, lonid };
10825 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
10826 ctl->met_nc_level, ctl->met_nc_quant);
10827 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
10828 ctl->met_nc_level, ctl->met_nc_quant);
10829 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
10830 ctl->met_nc_level, ctl->met_nc_quant);
10831 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
10832 ctl->met_nc_level, ctl->met_nc_quant);
10833 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
10834 ctl->met_nc_level, ctl->met_nc_quant);
10835 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
10836 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10837 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
10838 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10839 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
10840 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10841 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
10842 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10843 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
10844 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10845 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
10846 ctl->met_nc_level, ctl->met_nc_quant);
10847
10848 /* End definitions... */
10849 NC(nc_enddef(ncid));
10850
10851 /* Write grid data... */
10852 NC_PUT_DOUBLE("time", &met->time, 0);
10853 NC_PUT_DOUBLE("lon", met->lon, 0);
10854 NC_PUT_DOUBLE("lat", met->lat, 0);
10855 double phelp[EP];
10856 for (int ip = 0; ip < met->np; ip++)
10857 phelp[ip] = 100. * met->p[ip];
10858 NC_PUT_DOUBLE("lev", phelp, 0);
10859
10860 /* Write surface data... */
10861 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
10862 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
10863 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
10864 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
10865 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
10866 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
10867 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
10868 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
10869 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
10870 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
10871 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
10872 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
10873 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
10874 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
10875 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
10876 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
10877 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
10878 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
10879 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
10880 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
10881 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
10882 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
10883 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
10884 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
10885
10886 /* Write level data... */
10887 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
10888 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
10889 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
10890 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
10891 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
10892 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
10893 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
10894 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
10895 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
10896 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
10897 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
10898
10899 /* Close file... */
10900 NC(nc_close(ncid));
10901}
10902
10903/*****************************************************************************/
10904
10906 const int ncid,
10907 const char *varname,
10908 met_t *met,
10909 float var[EX][EY],
10910 const float scl) {
10911
10912 int varid;
10913 size_t start[4], count[4];
10914
10915 /* Allocate... */
10916 float *help;
10917 ALLOC(help, float,
10918 EX * EY);
10919
10920 /* Copy data... */
10921 for (int ix = 0; ix < met->nx; ix++)
10922 for (int iy = 0; iy < met->ny; iy++)
10923 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
10924
10925 /* Write data... */
10926 NC_PUT_FLOAT(varname, help, 0);
10927
10928 /* Free... */
10929 free(help);
10930}
10931
10932/*****************************************************************************/
10933
10935 const int ncid,
10936 const char *varname,
10937 met_t *met,
10938 float var[EX][EY][EP],
10939 const float scl) {
10940
10941 int varid;
10942 size_t start[4], count[4];
10943
10944 /* Allocate... */
10945 float *help;
10946 ALLOC(help, float,
10947 EX * EY * EP);
10948
10949 /* Copy data... */
10950 for (int ix = 0; ix < met->nx; ix++)
10951 for (int iy = 0; iy < met->ny; iy++)
10952 for (int ip = 0; ip < met->np; ip++)
10953 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
10954
10955 /* Write data... */
10956 NC_PUT_FLOAT(varname, help, 0);
10957
10958 /* Free... */
10959 free(help);
10960}
10961
10962/*****************************************************************************/
10963
10965 const char *filename,
10966 const ctl_t *ctl,
10967 met_t *met0,
10968 met_t *met1,
10969 const atm_t *atm,
10970 const double t) {
10971
10972 static FILE *out;
10973
10974 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
10975 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
10976
10977 static int nobs, *obscount, ip, okay;
10978
10979 /* Set timer... */
10980 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
10981
10982 /* Init... */
10983 if (t == ctl->t_start) {
10984
10985 /* Check quantity index for mass... */
10986 if (ctl->qnt_m < 0)
10987 ERRMSG("Need quantity mass!");
10988
10989 /* Check molar mass... */
10990 if (ctl->molmass <= 0)
10991 ERRMSG("Specify molar mass!");
10992
10993 /* Allocate... */
10994 ALLOC(lon, double,
10995 ctl->prof_nx);
10996 ALLOC(lat, double,
10997 ctl->prof_ny);
10998 ALLOC(area, double,
10999 ctl->prof_ny);
11000 ALLOC(z, double,
11001 ctl->prof_nz);
11002 ALLOC(press, double,
11003 ctl->prof_nz);
11004 ALLOC(rt, double,
11005 NOBS);
11006 ALLOC(rz, double,
11007 NOBS);
11008 ALLOC(rlon, double,
11009 NOBS);
11010 ALLOC(rlat, double,
11011 NOBS);
11012 ALLOC(robs, double,
11013 NOBS);
11014
11015 /* Read observation data... */
11016 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11017
11018 /* Create new output file... */
11019 LOG(1, "Write profile data: %s", filename);
11020 if (!(out = fopen(filename, "w")))
11021 ERRMSG("Cannot create file!");
11022
11023 /* Write header... */
11024 fprintf(out,
11025 "# $1 = time [s]\n"
11026 "# $2 = altitude [km]\n"
11027 "# $3 = longitude [deg]\n"
11028 "# $4 = latitude [deg]\n"
11029 "# $5 = pressure [hPa]\n"
11030 "# $6 = temperature [K]\n"
11031 "# $7 = volume mixing ratio [ppv]\n"
11032 "# $8 = H2O volume mixing ratio [ppv]\n"
11033 "# $9 = O3 volume mixing ratio [ppv]\n"
11034 "# $10 = observed BT index [K]\n"
11035 "# $11 = number of observations\n");
11036
11037 /* Set grid box size... */
11038 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
11039 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
11040 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
11041
11042 /* Set vertical coordinates... */
11043 for (int iz = 0; iz < ctl->prof_nz; iz++) {
11044 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
11045 press[iz] = P(z[iz]);
11046 }
11047
11048 /* Set horizontal coordinates... */
11049 for (int ix = 0; ix < ctl->prof_nx; ix++)
11050 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
11051 for (int iy = 0; iy < ctl->prof_ny; iy++) {
11052 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
11053 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
11054 }
11055 }
11056
11057 /* Set time interval... */
11058 const double t0 = t - 0.5 * ctl->dt_mod;
11059 const double t1 = t + 0.5 * ctl->dt_mod;
11060
11061 /* Allocate... */
11062 ALLOC(mass, double,
11063 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
11064 ALLOC(obsmean, double,
11065 ctl->prof_nx * ctl->prof_ny);
11066 ALLOC(obscount, int,
11067 ctl->prof_nx * ctl->prof_ny);
11068
11069 /* Loop over observations... */
11070 for (int i = 0; i < nobs; i++) {
11071
11072 /* Check time... */
11073 if (rt[i] < t0)
11074 continue;
11075 else if (rt[i] >= t1)
11076 break;
11077
11078 /* Check observation data... */
11079 if (!isfinite(robs[i]))
11080 continue;
11081
11082 /* Calculate indices... */
11083 int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
11084 int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
11085
11086 /* Check indices... */
11087 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
11088 continue;
11089
11090 /* Get mean observation index... */
11091 int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
11092 obsmean[idx] += robs[i];
11093 obscount[idx]++;
11094 }
11095
11096 /* Analyze model data... */
11097 for (ip = 0; ip < atm->np; ip++) {
11098
11099 /* Check time... */
11100 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11101 continue;
11102
11103 /* Get indices... */
11104 int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
11105 int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
11106 int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
11107
11108 /* Check indices... */
11109 if (ix < 0 || ix >= ctl->prof_nx ||
11110 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
11111 continue;
11112
11113 /* Get total mass in grid cell... */
11114 int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11115 mass[idx] += atm->q[ctl->qnt_m][ip];
11116 }
11117
11118 /* Extract profiles... */
11119 for (int ix = 0; ix < ctl->prof_nx; ix++)
11120 for (int iy = 0; iy < ctl->prof_ny; iy++) {
11121 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
11122 if (obscount[idx2] > 0) {
11123
11124 /* Check profile... */
11125 okay = 0;
11126 for (int iz = 0; iz < ctl->prof_nz; iz++) {
11127 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11128 if (mass[idx3] > 0) {
11129 okay = 1;
11130 break;
11131 }
11132 }
11133 if (!okay)
11134 continue;
11135
11136 /* Write output... */
11137 fprintf(out, "\n");
11138
11139 /* Loop over altitudes... */
11140 for (int iz = 0; iz < ctl->prof_nz; iz++) {
11141
11142 /* Get temperature, water vapor, and ozone... */
11144 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
11145 lon[ix], lat[iy], &temp, ci, cw, 1);
11146 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
11147 lon[ix], lat[iy], &h2o, ci, cw, 0);
11148 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
11149 lon[ix], lat[iy], &o3, ci, cw, 0);
11150
11151 /* Calculate volume mixing ratio... */
11152 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11153 vmr = MA / ctl->molmass * mass[idx3]
11154 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
11155
11156 /* Write output... */
11157 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
11158 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
11159 obsmean[idx2] / obscount[idx2], obscount[idx2]);
11160 }
11161 }
11162 }
11163
11164 /* Free... */
11165 free(mass);
11166 free(obsmean);
11167 free(obscount);
11168
11169 /* Finalize... */
11170 if (t == ctl->t_stop) {
11171
11172 /* Close output file... */
11173 fclose(out);
11174
11175 /* Free... */
11176 free(lon);
11177 free(lat);
11178 free(area);
11179 free(z);
11180 free(press);
11181 free(rt);
11182 free(rz);
11183 free(rlon);
11184 free(rlat);
11185 free(robs);
11186 }
11187}
11188
11189/*****************************************************************************/
11190
11192 const char *filename,
11193 const ctl_t *ctl,
11194 met_t *met0,
11195 met_t *met1,
11196 const atm_t *atm,
11197 const double t) {
11198
11199 static FILE *out;
11200
11201 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
11202 kw[EP];
11203
11204 static int nobs, nk;
11205
11206 /* Set timer... */
11207 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
11208
11209 /* Init... */
11210 if (t == ctl->t_start) {
11211
11212 /* Allocate... */
11213 ALLOC(rt, double,
11214 NOBS);
11215 ALLOC(rz, double,
11216 NOBS);
11217 ALLOC(rlon, double,
11218 NOBS);
11219 ALLOC(rlat, double,
11220 NOBS);
11221 ALLOC(robs, double,
11222 NOBS);
11223
11224 /* Read observation data... */
11225 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11226
11227 /* Read kernel data... */
11228 if (ctl->sample_kernel[0] != '-')
11229 read_kernel(ctl->sample_kernel, kz, kw, &nk);
11230
11231 /* Create output file... */
11232 LOG(1, "Write sample data: %s", filename);
11233 if (!(out = fopen(filename, "w")))
11234 ERRMSG("Cannot create file!");
11235
11236 /* Write header... */
11237 fprintf(out,
11238 "# $1 = time [s]\n"
11239 "# $2 = altitude [km]\n"
11240 "# $3 = longitude [deg]\n"
11241 "# $4 = latitude [deg]\n"
11242 "# $5 = surface area [km^2]\n"
11243 "# $6 = layer depth [km]\n"
11244 "# $7 = number of particles [1]\n"
11245 "# $8 = column density [kg/m^2]\n"
11246 "# $9 = volume mixing ratio [ppv]\n"
11247 "# $10 = observed BT index [K]\n\n");
11248
11249 /* Set latitude range, squared radius, and area... */
11250 dlat = DY2DEG(ctl->sample_dx);
11251 rmax2 = SQR(ctl->sample_dx);
11252 area = M_PI * rmax2;
11253 }
11254
11255 /* Set time interval for output... */
11256 const double t0 = t - 0.5 * ctl->dt_mod;
11257 const double t1 = t + 0.5 * ctl->dt_mod;
11258
11259 /* Loop over observations... */
11260 for (int i = 0; i < nobs; i++) {
11261
11262 /* Check time... */
11263 if (rt[i] < t0)
11264 continue;
11265 else if (rt[i] >= t1)
11266 break;
11267
11268 /* Calculate Cartesian coordinates... */
11269 double x0[3];
11270 geo2cart(0, rlon[i], rlat[i], x0);
11271
11272 /* Set pressure range... */
11273 const double rp = P(rz[i]);
11274 const double ptop = P(rz[i] + ctl->sample_dz);
11275 const double pbot = P(rz[i] - ctl->sample_dz);
11276
11277 /* Init... */
11278 double mass = 0;
11279 int np = 0;
11280
11281 /* Loop over air parcels... */
11282 //#pragma omp parallel for default(shared) reduction(+:mass,np)
11283 for (int ip = 0; ip < atm->np; ip++) {
11284
11285 /* Check time... */
11286 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11287 continue;
11288
11289 /* Check latitude... */
11290 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
11291 continue;
11292
11293 /* Check horizontal distance... */
11294 double x1[3];
11295 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
11296 if (DIST2(x0, x1) > rmax2)
11297 continue;
11298
11299 /* Check pressure... */
11300 if (ctl->sample_dz > 0)
11301 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
11302 continue;
11303
11304 /* Add mass... */
11305 if (ctl->qnt_m >= 0)
11306 mass +=
11307 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11308 np++;
11309 }
11310
11311 /* Calculate column density... */
11312 const double cd = mass / (1e6 * area);
11313
11314 /* Calculate volume mixing ratio... */
11315 double vmr = 0;
11316 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
11317 if (mass > 0) {
11318
11319 /* Get temperature... */
11320 double temp;
11322 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
11323 rlon[i], rlat[i], &temp, ci, cw, 1);
11324
11325 /* Calculate volume mixing ratio... */
11326 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
11327 }
11328 } else
11329 vmr = NAN;
11330
11331 /* Write output... */
11332 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
11333 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
11334 }
11335
11336 /* Finalize...... */
11337 if (t == ctl->t_stop) {
11338
11339 /* Close output file... */
11340 fclose(out);
11341
11342 /* Free... */
11343 free(rt);
11344 free(rz);
11345 free(rlon);
11346 free(rlat);
11347 free(robs);
11348 }
11349}
11350
11351/*****************************************************************************/
11352
11354 const char *filename,
11355 const ctl_t *ctl,
11356 atm_t *atm,
11357 const double t) {
11358
11359 static FILE *out;
11360
11361 static double rmax2, x0[3], x1[3];
11362
11363 /* Set timer... */
11364 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
11365
11366 /* Init... */
11367 if (t == ctl->t_start) {
11368
11369 /* Write info... */
11370 LOG(1, "Write station data: %s", filename);
11371
11372 /* Create new file... */
11373 if (!(out = fopen(filename, "w")))
11374 ERRMSG("Cannot create file!");
11375
11376 /* Write header... */
11377 fprintf(out,
11378 "# $1 = time [s]\n"
11379 "# $2 = altitude [km]\n"
11380 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11381 for (int iq = 0; iq < ctl->nq; iq++)
11382 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
11383 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11384 fprintf(out, "\n");
11385
11386 /* Set geolocation and search radius... */
11387 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
11388 rmax2 = SQR(ctl->stat_r);
11389 }
11390
11391 /* Set time interval for output... */
11392 const double t0 = t - 0.5 * ctl->dt_mod;
11393 const double t1 = t + 0.5 * ctl->dt_mod;
11394
11395 /* Loop over air parcels... */
11396 for (int ip = 0; ip < atm->np; ip++) {
11397
11398 /* Check time... */
11399 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11400 continue;
11401
11402 /* Check time range for station output... */
11403 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
11404 continue;
11405
11406 /* Check station flag... */
11407 if (ctl->qnt_stat >= 0)
11408 if ((int) atm->q[ctl->qnt_stat][ip])
11409 continue;
11410
11411 /* Get Cartesian coordinates... */
11412 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
11413
11414 /* Check horizontal distance... */
11415 if (DIST2(x0, x1) > rmax2)
11416 continue;
11417
11418 /* Set station flag... */
11419 if (ctl->qnt_stat >= 0)
11420 atm->q[ctl->qnt_stat][ip] = 1;
11421
11422 /* Write data... */
11423 fprintf(out, "%.2f %g %g %g",
11424 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
11425 for (int iq = 0; iq < ctl->nq; iq++) {
11426 fprintf(out, " ");
11427 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11428 }
11429 fprintf(out, "\n");
11430 }
11431
11432 /* Close file... */
11433 if (t == ctl->t_stop)
11434 fclose(out);
11435}
11436
11437/*****************************************************************************/
11438
11440 const char *filename,
11441 const ctl_t *ctl,
11442 const atm_t *atm,
11443 const double t) {
11444
11445 FILE *out;
11446
11447 /* Set timer... */
11448 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
11449
11450 /* Write info... */
11451 LOG(1, "Write VTK data: %s", filename);
11452
11453 /* Set time interval for output... */
11454 const double t0 = t - 0.5 * ctl->dt_mod;
11455 const double t1 = t + 0.5 * ctl->dt_mod;
11456
11457 /* Create file... */
11458 if (!(out = fopen(filename, "w")))
11459 ERRMSG("Cannot create file!");
11460
11461 /* Count data points... */
11462 int np = 0;
11463 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11464 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11465 continue;
11466 np++;
11467 }
11468
11469 /* Write header... */
11470 fprintf(out,
11471 "# vtk DataFile Version 3.0\n"
11472 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
11473
11474 /* Write point coordinates... */
11475 fprintf(out, "POINTS %d float\n", np);
11476 if (ctl->vtk_sphere) {
11477 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11478 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11479 continue;
11480 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
11481 + ctl->vtk_offset) / RE;
11482 const double coslat = cos(DEG2RAD(atm->lat[ip]));
11483 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
11484 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
11485 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
11486 fprintf(out, "%g %g %g\n", x, y, z);
11487 }
11488 } else
11489 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11490 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11491 continue;
11492 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
11493 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
11494 }
11495
11496 /* Write point data... */
11497 fprintf(out, "POINT_DATA %d\n", np);
11498 for (int iq = 0; iq < ctl->nq; iq++) {
11499 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
11500 ctl->qnt_name[iq]);
11501 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11502 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11503 continue;
11504 fprintf(out, "%g\n", atm->q[iq][ip]);
11505 }
11506 }
11507
11508 /* Close file... */
11509 fclose(out);
11510}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:7038
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:5722
void day2doy(const int year, const int mon, const int day, int *doy)
Get day of year from date.
Definition: mptrac.c:942
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:6998
void read_met_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:7300
int read_met_nc(const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met)
Reads meteorological data from a NetCDF file and processes it.
Definition: mptrac.c:7641
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:9545
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:10905
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:4238
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:8408
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:10666
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:8888
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:2130
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:3965
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:5418
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:3281
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:6146
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:6837
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:2667
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:9061
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:1504
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:6113
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:8016
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:6894
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:7712
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:8716
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:8932
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:2552
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:2091
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:1137
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:4311
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:7556
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:6265
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:8153
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:4002
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:10014
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:3385
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 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:6237
void read_met_ml2pl(const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname)
Interpolates meteorological data to specified pressure levels.
Definition: mptrac.c:7514
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:8960
void read_met_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:7166
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:6607
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:2027
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:3106
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:1817
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:1207
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:10302
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:5610
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:9203
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:4432
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:1562
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:1437
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:991
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:4103
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:706
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:5913
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:9094
void module_chem_grid(const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double tt)
Calculate grid data for chemistry modules.
Definition: mptrac.c:2405
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:6319
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:3840
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:9234
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:9360
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:1379
void read_met_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:8580
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:1591
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:2594
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:6418
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:2309
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:8989
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:2282
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:3929
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:9141
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:1649
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:7870
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:6636
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:2057
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:9302
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:10964
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:4522
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:9337
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:10742
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:3704
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:4451
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:5666
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:5822
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:8379
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:4285
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:3735
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:1048
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:11353
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:9162
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)
Perform interparcel mixing for a specific quantity.
Definition: mptrac.c:3475
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:961
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:1616
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:3653
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:2110
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:10637
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:8273
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:6001
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:1113
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:2706
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:3869
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:1740
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:6459
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:5473
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:9492
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:2908
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:6057
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:11439
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:4033
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:4582
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:8214
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:3023
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:10406
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:5937
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:2783
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:10934
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:3176
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:3569
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:1030
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:1773
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:5959
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:1180
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:11191
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:10111
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:2960
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:10536
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:9442
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:6722
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:5782
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:1799
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:9752
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:9703
MPTRAC library declarations.
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1243
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:252
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:233
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1730
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:402
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1285
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:208
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:168
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:203
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:213
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:287
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:678
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1390
#define H0
Scale height [km].
Definition: mptrac.h:188
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1223
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1013
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:851
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1027
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:228
#define KARMAN
Karman's constant.
Definition: mptrac.h:198
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:693
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:998
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:1915
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1184
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:282
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1555
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:724
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:292
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:297
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:383
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:1752
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1315
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:193
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:183
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:312
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:262
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:658
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:536
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:472
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:277
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:178
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1363
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1655
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:238
#define NORM(a)
Compute the norm (magnitude) of a vector.
Definition: mptrac.h:1258
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1534
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1631
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1705
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1783
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1684
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:573
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:1882
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:1802
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1467
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:797
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:360
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1511
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:327
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:489
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:218
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1568
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1407
#define NC_INQ_DIM(dimname, ptr, min, max)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1114
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:257
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:1959
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:1995
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:707
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1437
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1161
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:302
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:1845
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:1056
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1606
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:427
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:267
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1086
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:272
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1339
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1492
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:307
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1137
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:870
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:605
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:451
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:173
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:317
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:554
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:897
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:640
Air parcel data.
Definition: mptrac.h:3163
double time[NP]
Time [s].
Definition: mptrac.h:3169
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3178
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3175
int np
Number of air parcels.
Definition: mptrac.h:3166
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3181
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3172
Cache data structure.
Definition: mptrac.h:3191
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3212
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3200
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3203
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3197
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3209
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3206
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3194
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3223
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3229
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3238
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3259
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3235
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3253
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3256
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3250
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3244
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3265
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3268
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3247
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3262
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3241
int np
Number of pressure levels.
Definition: mptrac.h:3226
int no3c
Number of total ozone columns.
Definition: mptrac.h:3232
Climatological data.
Definition: mptrac.h:3331
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3373
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3349
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3361
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3352
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3334
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3379
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3367
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3370
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3364
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3343
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3358
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3337
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3355
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3346
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3340
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3376
Climatological data in the form of time series.
Definition: mptrac.h:3279
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3288
double time[CTS]
Time [s].
Definition: mptrac.h:3285
int ntime
Number of timesteps.
Definition: mptrac.h:3282
Climatological data in the form of zonal means.
Definition: mptrac.h:3299
double time[CT]
Time [s].
Definition: mptrac.h:3311
int np
Number of pressure levels.
Definition: mptrac.h:3308
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3317
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3320
int ntime
Number of timesteps.
Definition: mptrac.h:3302
int nlat
Number of latitudes.
Definition: mptrac.h:3305
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3314
Control parameters.
Definition: mptrac.h:2169
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3043
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2281
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3007
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:2974
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2428
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2895
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2500
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2314
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:2983
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2757
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2260
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2452
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:2935
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2820
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2844
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2188
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2200
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2461
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2209
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2293
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:2977
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2302
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2796
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2745
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:2998
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2269
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3121
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2805
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2656
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2817
double stat_r
Search radius around station [km].
Definition: mptrac.h:3127
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2889
int met_zstd_level
ZSTD compression level (from -5 to 22).
Definition: mptrac.h:2509
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3001
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3151
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2841
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2624
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2290
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2859
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2709
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2440
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2546
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2368
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3070
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3046
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2464
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2663
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2446
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2576
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2643
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2332
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2395
char species[LEN]
Species.
Definition: mptrac.h:2754
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:2992
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3004
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2691
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2621
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2284
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2700
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3031
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3049
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:2948
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2718
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3061
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2215
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2359
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2549
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2311
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3052
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2338
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2640
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3106
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2389
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2483
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2778
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2862
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2612
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3022
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2537
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2685
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2203
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2236
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2380
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2733
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3133
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:2968
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2682
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3067
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:2995
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2242
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2868
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3037
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2365
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2850
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2751
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2350
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2609
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2582
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2212
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2673
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3073
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2660
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2739
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2218
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3076
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:2971
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2618
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:2980
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2579
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2853
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2697
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2561
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2564
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3019
int met_zfp_prec
ZFP compression precision for all variables, except z and T.
Definition: mptrac.h:2512
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2540
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3079
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2275
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2724
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2634
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3085
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2197
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2631
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2206
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2649
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2808
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2398
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2335
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:2989
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3130
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2871
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2781
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2766
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:2907
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2814
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2356
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:2953
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2600
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2880
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:2965
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2916
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2233
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2224
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2425
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3139
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2470
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2715
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3109
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2326
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3016
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2497
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2254
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2374
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2567
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2730
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2627
int met_dx
Stride for longitudes.
Definition: mptrac.h:2570
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2829
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2486
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2386
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2775
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2883
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2473
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2676
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2413
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2407
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2257
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3148
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2272
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2353
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2727
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2646
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2329
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2185
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2431
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2597
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2865
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2278
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3094
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2377
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2266
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3115
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2763
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:2962
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3034
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2555
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2221
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2531
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3055
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2455
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2449
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2179
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:2932
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2832
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2245
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2305
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2666
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3082
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2603
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2263
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:2941
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2877
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2383
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2706
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3010
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2886
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:2490
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:2986
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2392
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3124
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2434
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2904
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3058
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2458
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2419
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2588
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2703
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2480
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2742
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2534
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2838
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2317
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2721
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2811
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2323
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2736
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2823
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2787
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2422
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2410
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3040
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2772
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2230
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3013
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3103
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:2944
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2615
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2835
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:2938
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2799
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3100
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2521
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2922
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2585
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3088
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2847
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2299
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2347
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2362
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2606
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3097
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2320
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2925
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3091
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2558
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2506
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2874
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2443
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2959
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2913
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2856
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2790
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2552
int met_cms_zstd
cmultiscale zstd compression (0=off, 1=on).
Definition: mptrac.h:2524
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3028
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3136
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2919
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2248
int met_np
Number of target pressure levels.
Definition: mptrac.h:2591
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2194
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2503
double met_zfp_tol_t
ZFP compression tolerance for temperature.
Definition: mptrac.h:2515
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2802
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2344
double met_zfp_tol_z
ZFP compression tolerance for geopotential height.
Definition: mptrac.h:2518
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3145
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2793
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2543
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2901
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2679
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2712
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2401
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev).
Definition: mptrac.h:2670
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2341
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2437
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2239
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2826
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2956
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2769
int met_cms_heur
cmultiscale coarsening heuristics (0=default, 1=mean diff, 2=median diff, 3=max diff).
Definition: mptrac.h:2528
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2910
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2371
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2227
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2898
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2892
int met_dy
Stride for latitudes.
Definition: mptrac.h:2573
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2416
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2694
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2748
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2191
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2637
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2287
double t_start
Start time of simulation [s].
Definition: mptrac.h:2467
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2182
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2594
int nq
Number of quantities.
Definition: mptrac.h:2176
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2760
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3112
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3142
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3118
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2688
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3064
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2251
int met_type
Type of meteo data files (0=netCDF, 1=binary, 2=pck, 3=zfp, 4=zstd, 5=cms).
Definition: mptrac.h:2494
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2296
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2308
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3025
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2404
Meteo data structure.
Definition: mptrac.h:3390
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3459
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3447
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3519
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3489
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3546
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3510
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3483
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3504
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3465
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3417
int nx
Number of longitudes.
Definition: mptrac.h:3396
int ny
Number of latitudes.
Definition: mptrac.h:3399
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3441
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3420
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3516
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3429
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3540
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3537
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3426
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3513
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3528
int np
Number of pressure levels.
Definition: mptrac.h:3402
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3495
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3423
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3498
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3435
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3534
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3468
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3480
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3486
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3474
double lon[EX]
Longitude [deg].
Definition: mptrac.h:3408
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3453
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3456
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3450
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3432
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3492
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3501
int npl
Number of model levels.
Definition: mptrac.h:3405
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3444
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3522
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3462
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3507
double time
Time [s].
Definition: mptrac.h:3393
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3471
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3438
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3531
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3477
double lat[EY]
Latitude [deg].
Definition: mptrac.h:3411
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3525
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3543
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3414