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 = 6;
472 const int Nd0_y = 3;
473 const int max_level_grid = 7;
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 /* Initialize multiscale module... */
550 cms_ptr[ip] = cms_init(cms_param);
551
552 /* Create solution pointer... */
553 cms_sol[ip] = cms_read_arr(cms_ptr[ip], tmp_arr, lon, lat, nx, ny);
554
555 /* Set eps threshold value... */
556 if (strcasecmp(varname, "Z") == 0)
557 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_z);
558 else if (strcasecmp(varname, "T") == 0)
559 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_t);
560 else if (strcasecmp(varname, "U") == 0)
561 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_u);
562 else if (strcasecmp(varname, "V") == 0)
563 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_v);
564 else if (strcasecmp(varname, "W") == 0)
565 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_w);
566 else if (strcasecmp(varname, "PV") == 0)
567 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_pv);
568 else if (strcasecmp(varname, "H2O") == 0)
569 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_h2o);
570 else if (strcasecmp(varname, "O3") == 0)
571 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_o3);
572 else if (strcasecmp(varname, "LWC") == 0)
573 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_lwc);
574 else if (strcasecmp(varname, "RWC") == 0)
575 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_rwc);
576 else if (strcasecmp(varname, "IWC") == 0)
577 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_iwc);
578 else if (strcasecmp(varname, "SWC") == 0)
579 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_swc);
580 else if (strcasecmp(varname, "CC") == 0)
581 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_cc);
582 else
583 ERRMSG("Variable name unknown!");
584
585 /* Coarsening... */
586 cms_coarsening(cms_ptr[ip], cms_sol[ip],
587 (unsigned int) ctl->met_cms_heur);
588
589 /* Free... */
590 free(tmp_arr);
591 }
592
593 /* Measure time... */
594 t_coars += (omp_get_wtime() - t0);
595
596 /* Loop over levels... */
597 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
598
599 /* Allocate... */
600 double *tmp_cms, *tmp_org, *tmp_diff;
601 ALLOC(tmp_cms, double,
602 nxy);
603 ALLOC(tmp_org, double,
604 nxy);
605 ALLOC(tmp_diff, double,
606 nxy);
607
608 /* Measure time... */
609 t0 = omp_get_wtime();
610
611 /* Evaluate... */
612#pragma omp parallel for default(shared)
613 for (size_t ix = 0; ix < nx; ix++)
614 for (size_t iy = 0; iy < ny; iy++) {
615 const size_t idx = ARRAY_2D(ix, iy, ny);
616 const double x[] = { lon[ix], lat[iy] };
617 cms_eval(cms_ptr[ip], cms_sol[ip], x, &tmp_cms[idx]);
618 tmp_org[idx] = array[ARRAY_3D(ix, iy, ny, ip, np)];
619 tmp_diff[idx] = tmp_cms[idx] - tmp_org[idx];
620 }
621
622 /* Measure time... */
623 t_eval += (omp_get_wtime() - t0);
624
625 /* Write info... */
626 LOG(2,
627 "cmultiscale: var= %s / lev= %lu / ratio= %g / rho= %g"
628 " / mean= %g / sd= %g / min= %g / max= %g", varname, ip,
629 cms_compression_rate(cms_ptr[ip], cms_sol[ip]),
630 gsl_stats_correlation(tmp_cms, 1, tmp_org, 1, nxy),
631 gsl_stats_mean(tmp_diff, 1, nxy), gsl_stats_sd(tmp_diff, 1, nxy),
632 gsl_stats_min(tmp_diff, 1, nxy), gsl_stats_max(tmp_diff, 1, nxy));
633
634 /* Calculate mean compression ratio... */
635 cr += cms_compression_rate(cms_ptr[ip], cms_sol[ip]) / (double) np;
636
637 /* Save binary data... */
638 if (ctl->met_cms_zstd == 1)
639 cms_save_zstd_sol(cms_sol[ip], inout, 3);
640 else
641 cms_save_sol(cms_sol[ip], inout);
642
643 /* Free... */
644 cms_delete_sol(cms_sol[ip]);
645 cms_delete_module(cms_ptr[ip]);
646 free(tmp_cms);
647 free(tmp_org);
648 free(tmp_diff);
649 }
650 }
651
652 /* Write info... */
653 LOG(2, "Write 3-D variable: %s"
654 " (cms, RATIO= %g, T_COARS= %g s, T_EVAL= %g s)",
655 varname, cr, t_coars, t_eval);
656 }
657
658 /* Free... */
659 cms_delete_param(cms_param);
660}
661#endif
662
663/*****************************************************************************/
664
666 const char *varname,
667 float *array,
668 const size_t nxy,
669 const size_t nz,
670 const int decompress,
671 FILE *inout) {
672
673 double min[EP], max[EP], off[EP], scl[EP];
674
675 unsigned short *sarray;
676
677 /* Allocate... */
678 ALLOC(sarray, unsigned short,
679 nxy * nz);
680
681 /* Read compressed stream and decompress array... */
682 if (decompress) {
683
684 /* Write info... */
685 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
686 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
687
688 /* Read data... */
689 FREAD(&scl, double,
690 nz,
691 inout);
692 FREAD(&off, double,
693 nz,
694 inout);
695 FREAD(sarray, unsigned short,
696 nxy * nz,
697 inout);
698
699 /* Convert to float... */
700#pragma omp parallel for default(shared)
701 for (size_t ixy = 0; ixy < nxy; ixy++)
702 for (size_t iz = 0; iz < nz; iz++)
703 array[ixy * nz + iz]
704 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
705 }
706
707 /* Compress array and output compressed stream... */
708 else {
709
710 /* Write info... */
711 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
712 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
713
714 /* Get range... */
715 for (size_t iz = 0; iz < nz; iz++) {
716 min[iz] = array[iz];
717 max[iz] = array[iz];
718 }
719 for (size_t ixy = 1; ixy < nxy; ixy++)
720 for (size_t iz = 0; iz < nz; iz++) {
721 if (array[ixy * nz + iz] < min[iz])
722 min[iz] = array[ixy * nz + iz];
723 if (array[ixy * nz + iz] > max[iz])
724 max[iz] = array[ixy * nz + iz];
725 }
726
727 /* Get offset and scaling factor... */
728 for (size_t iz = 0; iz < nz; iz++) {
729 scl[iz] = (max[iz] - min[iz]) / 65533.;
730 off[iz] = min[iz];
731 }
732
733 /* Convert to short... */
734#pragma omp parallel for default(shared)
735 for (size_t ixy = 0; ixy < nxy; ixy++)
736 for (size_t iz = 0; iz < nz; iz++)
737 if (scl[iz] != 0)
738 sarray[ixy * nz + iz] = (unsigned short)
739 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
740 else
741 sarray[ixy * nz + iz] = 0;
742
743 /* Write data... */
744 FWRITE(&scl, double,
745 nz,
746 inout);
747 FWRITE(&off, double,
748 nz,
749 inout);
750 FWRITE(sarray, unsigned short,
751 nxy * nz,
752 inout);
753 }
754
755 /* Free... */
756 free(sarray);
757}
758
759/*****************************************************************************/
760
761#ifdef ZFP
762void compress_zfp(
763 const char *varname,
764 float *array,
765 const int nx,
766 const int ny,
767 const int nz,
768 const int precision,
769 const double tolerance,
770 const int decompress,
771 FILE *inout) {
772
773 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
774 const zfp_type type = zfp_type_float;
775 zfp_field *field =
776 zfp_field_3d(array, type, (uint) nx, (uint) ny, (uint) nz);
777
778 /* Allocate meta data for a compressed stream... */
779 zfp_stream *zfp = zfp_stream_open(NULL);
780
781 /* Set compression mode... */
782 int actual_prec = 0;
783 double actual_tol = 0;
784 if (precision > 0)
785 actual_prec = (int) zfp_stream_set_precision(zfp, (uint) precision);
786 else if (tolerance > 0)
787 actual_tol = zfp_stream_set_accuracy(zfp, tolerance);
788 else
789 ERRMSG("Set precision or tolerance!");
790
791 /* Allocate buffer for compressed data... */
792 const size_t bufsize = zfp_stream_maximum_size(zfp, field);
793 void *buffer = malloc(bufsize);
794
795 /* Associate bit stream with allocated buffer... */
796 bitstream *stream = stream_open(buffer, bufsize);
797 zfp_stream_set_bit_stream(zfp, stream);
798 zfp_stream_rewind(zfp);
799
800 /* Read compressed stream and decompress array... */
801 size_t zfpsize;
802 if (decompress) {
803 FREAD(&zfpsize, size_t,
804 1,
805 inout);
806 if (fread(buffer, 1, zfpsize, inout) != zfpsize)
807 ERRMSG("Error while reading zfp data!");
808 if (!zfp_decompress(zfp, field)) {
809 ERRMSG("Decompression failed!");
810 }
811 LOG(2, "Read 3-D variable: %s "
812 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
813 varname, actual_prec, actual_tol,
814 ((double) (nx * ny * nz)) / (double) zfpsize);
815 }
816
817 /* Compress array and output compressed stream... */
818 else {
819 zfpsize = zfp_compress(zfp, field);
820 if (!zfpsize) {
821 ERRMSG("Compression failed!");
822 } else {
823 FWRITE(&zfpsize, size_t,
824 1,
825 inout);
826 if (fwrite(buffer, 1, zfpsize, inout) != zfpsize)
827 ERRMSG("Error while writing zfp data!");
828 }
829 LOG(2, "Write 3-D variable: %s "
830 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
831 varname, actual_prec, actual_tol,
832 ((double) (nx * ny * nz)) / (double) zfpsize);
833 }
834
835 /* Free... */
836 zfp_field_free(field);
837 zfp_stream_close(zfp);
838 stream_close(stream);
839 free(buffer);
840}
841#endif
842
843/*****************************************************************************/
844
845#ifdef ZSTD
846void compress_zstd(
847 const char *varname,
848 float *array,
849 const size_t n,
850 const int decompress,
851 FILE *inout) {
852
853 /* Get buffer sizes... */
854 const size_t uncomprLen = n * sizeof(float);
855 size_t comprLen = ZSTD_compressBound(uncomprLen);
856 size_t compsize;
857
858 /* Allocate... */
859 char *compr = (char *) calloc((uint) comprLen, 1);
860 char *uncompr = (char *) array;
861
862 /* Read compressed stream and decompress array... */
863 if (decompress) {
864 FREAD(&comprLen, size_t,
865 1,
866 inout);
867 if (fread(compr, 1, comprLen, inout) != comprLen)
868 ERRMSG("Error while reading zstd data!");
869 compsize = ZSTD_decompress(uncompr, uncomprLen, compr, comprLen);
870 if (ZSTD_isError(compsize)) {
871 ERRMSG("Decompression failed!");
872 }
873 LOG(2, "Read 3-D variable: %s (zstd, RATIO= %g)",
874 varname, ((double) uncomprLen) / (double) comprLen)
875 }
876
877 /* Compress array and output compressed stream... */
878 else {
879 compsize = ZSTD_compress(compr, comprLen, uncompr, uncomprLen, 0);
880 if (ZSTD_isError(compsize)) {
881 ERRMSG("Compression failed!");
882 } else {
883 FWRITE(&compsize, size_t,
884 1,
885 inout);
886 if (fwrite(compr, 1, compsize, inout) != compsize)
887 ERRMSG("Error while writing zstd data!");
888 }
889 LOG(2, "Write 3-D variable: %s (zstd, RATIO= %g)",
890 varname, ((double) uncomprLen) / (double) compsize);
891 }
892
893 /* Free... */
894 free(compr);
895}
896#endif
897
898/*****************************************************************************/
899
901 const int year,
902 const int mon,
903 const int day,
904 int *doy) {
905
906 const int
907 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
908 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
909
910 /* Get day of year... */
911 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
912 *doy = d0l[mon - 1] + day - 1;
913 else
914 *doy = d0[mon - 1] + day - 1;
915}
916
917/*****************************************************************************/
918
920 const int year,
921 const int doy,
922 int *mon,
923 int *day) {
924
925 const int
926 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
927 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
928
929 int i;
930
931 /* Get month and day... */
932 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
933 for (i = 11; i > 0; i--)
934 if (d0l[i] <= doy)
935 break;
936 *mon = i + 1;
937 *day = doy - d0l[i] + 1;
938 } else {
939 for (i = 11; i > 0; i--)
940 if (d0[i] <= doy)
941 break;
942 *mon = i + 1;
943 *day = doy - d0[i] + 1;
944 }
945}
946
947/*****************************************************************************/
948
950 double *fcReal,
951 double *fcImag,
952 const int n) {
953
954 double data[2 * EX];
955
956 /* Check size... */
957 if (n > EX)
958 ERRMSG("Too many data points!");
959
960 /* Allocate... */
961 gsl_fft_complex_wavetable *wavetable =
962 gsl_fft_complex_wavetable_alloc((size_t) n);
963 gsl_fft_complex_workspace *workspace =
964 gsl_fft_complex_workspace_alloc((size_t) n);
965
966 /* Set data (real, complex)... */
967 for (int i = 0; i < n; i++) {
968 data[2 * i] = fcReal[i];
969 data[2 * i + 1] = fcImag[i];
970 }
971
972 /* Calculate FFT... */
973 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
974
975 /* Copy data... */
976 for (int i = 0; i < n; i++) {
977 fcReal[i] = data[2 * i];
978 fcImag[i] = data[2 * i + 1];
979 }
980
981 /* Free... */
982 gsl_fft_complex_wavetable_free(wavetable);
983 gsl_fft_complex_workspace_free(workspace);
984}
985
986/*****************************************************************************/
987
989 const double z,
990 const double lon,
991 const double lat,
992 double *x) {
993
994 const double radius = z + RE;
995 const double latrad = DEG2RAD(lat);
996 const double lonrad = DEG2RAD(lon);
997 const double coslat = cos(latrad);
998
999 x[0] = radius * coslat * cos(lonrad);
1000 x[1] = radius * coslat * sin(lonrad);
1001 x[2] = radius * sin(latrad);
1002}
1003
1004/*****************************************************************************/
1005
1007 const ctl_t *ctl,
1008 const double t,
1009 const int direct,
1010 const char *metbase,
1011 const double dt_met,
1012 char *filename) {
1013
1014 char repl[LEN];
1015
1016 double t6, r;
1017
1018 int year, mon, day, hour, min, sec;
1019
1020 /* Round time to fixed intervals... */
1021 if (direct == -1)
1022 t6 = floor(t / dt_met) * dt_met;
1023 else
1024 t6 = ceil(t / dt_met) * dt_met;
1025
1026 /* Decode time... */
1027 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1028
1029 /* Set filename of MPTRAC meteo files... */
1030 if (ctl->met_clams == 0) {
1031 if (ctl->met_type == 0)
1032 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1033 else if (ctl->met_type == 1)
1034 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1035 else if (ctl->met_type == 2)
1036 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1037 else if (ctl->met_type == 3)
1038 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1039 else if (ctl->met_type == 4)
1040 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1041 else if (ctl->met_type == 5)
1042 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1043 sprintf(repl, "%d", year);
1044 get_met_replace(filename, "YYYY", repl);
1045 sprintf(repl, "%02d", mon);
1046 get_met_replace(filename, "MM", repl);
1047 sprintf(repl, "%02d", day);
1048 get_met_replace(filename, "DD", repl);
1049 sprintf(repl, "%02d", hour);
1050 get_met_replace(filename, "HH", repl);
1051 }
1052
1053 /* Set filename of CLaMS meteo files... */
1054 else {
1055 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1056 sprintf(repl, "%d", year);
1057 get_met_replace(filename, "YYYY", repl);
1058 sprintf(repl, "%02d", year % 100);
1059 get_met_replace(filename, "YY", repl);
1060 sprintf(repl, "%02d", mon);
1061 get_met_replace(filename, "MM", repl);
1062 sprintf(repl, "%02d", day);
1063 get_met_replace(filename, "DD", repl);
1064 sprintf(repl, "%02d", hour);
1065 get_met_replace(filename, "HH", repl);
1066 }
1067}
1068
1069/*****************************************************************************/
1070
1072 char *orig,
1073 char *search,
1074 char *repl) {
1075
1076 char buffer[LEN];
1077
1078 /* Iterate... */
1079 for (int i = 0; i < 3; i++) {
1080
1081 /* Replace sub-string... */
1082 char *ch;
1083 if (!(ch = strstr(orig, search)))
1084 return;
1085 strncpy(buffer, orig, (size_t) (ch - orig));
1086 buffer[ch - orig] = 0;
1087 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1088 orig[0] = 0;
1089 strcpy(orig, buffer);
1090 }
1091}
1092
1093/*****************************************************************************/
1094
1096 const int met_tropo,
1097 ctl_t *ctl,
1098 clim_t *clim,
1099 met_t *met,
1100 const double *lons,
1101 const int nx,
1102 const double *lats,
1103 const int ny,
1104 double *pt,
1105 double *zt,
1106 double *tt,
1107 double *qt,
1108 double *o3t,
1109 double *ps,
1110 double *zs) {
1111
1113
1114 ctl->met_tropo = met_tropo;
1115 read_met_tropo(ctl, clim, met);
1116#pragma omp parallel for default(shared) private(ci,cw)
1117 for (int ix = 0; ix < nx; ix++)
1118 for (int iy = 0; iy < ny; iy++) {
1119 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1120 &pt[iy * nx + ix], ci, cw, 1);
1121 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1122 &ps[iy * nx + ix], ci, cw, 0);
1123 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1124 &zs[iy * nx + ix], ci, cw, 0);
1125 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1126 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1127 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1128 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1129 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1130 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1131 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1132 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1133 }
1134}
1135
1136/*****************************************************************************/
1137
1139 const double *lons,
1140 const int nlon,
1141 const double *lats,
1142 const int nlat,
1143 const double lon,
1144 const double lat,
1145 double *lon2,
1146 double *lat2) {
1147
1148 /* Check longitude... */
1149 *lon2 = FMOD(lon, 360.);
1150 if (*lon2 < lons[0])
1151 *lon2 += 360;
1152 else if (*lon2 > lons[nlon - 1])
1153 *lon2 -= 360;
1154
1155 /* Check latitude... */
1156 *lat2 = lat;
1157 if (lats[0] < lats[nlat - 1])
1158 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
1159 else
1160 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
1161}
1162
1163/*****************************************************************************/
1164
1166 const met_t *met0,
1167 float heights0[EX][EY][EP],
1168 float array0[EX][EY][EP],
1169 const met_t *met1,
1170 float heights1[EX][EY][EP],
1171 float array1[EX][EY][EP],
1172 const double ts,
1173 const double height,
1174 const double lon,
1175 const double lat,
1176 double *var,
1177 int *ci,
1178 double *cw,
1179 const int init) {
1180
1181 if (init) {
1182
1183 /* Check longitude and latitude... */
1184 double lon2, lat2;
1185 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
1186 &lon2, &lat2);
1187
1188 /* Get horizontal indizes... */
1189 ci[0] = locate_irr(met0->lon, met0->nx, lon2);
1190 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
1191
1192 /* Locate the vertical indizes for each edge of the column... */
1193 int ind[2][4];
1194 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1195 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1196
1197 /* Find minimum and maximum indizes... */
1198 ci[2] = ind[0][0];
1199 int k_max = ind[0][0];
1200 for (int i = 0; i < 2; i++)
1201 for (int j = 0; j < 4; j++) {
1202 if (ci[2] > ind[i][j])
1203 ci[2] = ind[i][j];
1204 if (k_max < ind[i][j])
1205 k_max = ind[i][j];
1206 }
1207
1208 /* Get weighting factors for time, longitude and latitude... */
1209 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1210 cw[0] = (lon2 - met0->lon[ci[0]]) /
1211 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1212 cw[1] = (lat2 - met0->lat[ci[1]]) /
1213 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1214
1215 /* Interpolate in time at the lowest level... */
1216 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1217 - heights0[ci[0]][ci[1]][ci[2]])
1218 + heights0[ci[0]][ci[1]][ci[2]];
1219 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1220 - heights0[ci[0]][ci[1] + 1][ci[2]])
1221 + heights0[ci[0]][ci[1] + 1][ci[2]];
1222 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1223 - heights0[ci[0] + 1][ci[1]][ci[2]])
1224 + heights0[ci[0] + 1][ci[1]][ci[2]];
1225 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1226 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1227 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1228
1229 /* Interpolate in latitude direction... */
1230 double height0 = cw[1] * (height01 - height00) + height00;
1231 double height1 = cw[1] * (height11 - height10) + height10;
1232
1233 /* Interpolate in longitude direction... */
1234 double height_bot = cw[0] * (height1 - height0) + height0;
1235
1236 /* Interpolate in time at the upper level... */
1237 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1238 - heights0[ci[0]][ci[1]][ci[2] + 1])
1239 + heights0[ci[0]][ci[1]][ci[2] + 1];
1240 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1241 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1242 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1243 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1244 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1245 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1246 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1247 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1248 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1249
1250 /* Interpolate in latitude direction... */
1251 height0 = cw[1] * (height01 - height00) + height00;
1252 height1 = cw[1] * (height11 - height10) + height10;
1253
1254 /* Interpolate in longitude direction... */
1255 double height_top = cw[0] * (height1 - height0) + height0;
1256
1257 /* Search at higher levels if height is not in box... */
1258 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1259 ((height_bot <= height) || (height_top > height))
1260 && (height_bot >= height) && (ci[2] < k_max))
1261 ||
1262 ((heights0[0][0][0] < heights0[0][0][1]) &&
1263 ((height_bot >= height) || (height_top < height))
1264 && (height_bot <= height) && (ci[2] < k_max))
1265 ) {
1266
1267 ci[2]++;
1268 height_bot = height_top;
1269
1270 /* Interpolate in time at the next level... */
1271 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1272 - heights0[ci[0]][ci[1]][ci[2] + 1])
1273 + heights0[ci[0]][ci[1]][ci[2] + 1];
1274 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1275 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1276 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1277 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1278 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1279 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1280 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1281 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1282 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1283
1284 /* Interpolate in latitude direction... */
1285 height0 = cw[1] * (height01 - height00) + height00;
1286 height1 = cw[1] * (height11 - height10) + height10;
1287
1288 /* Interpolate in longitude direction... */
1289 height_top = cw[0] * (height1 - height0) + height0;
1290 }
1291
1292 /* Get vertical weighting factors... */
1293 cw[2] = (height - height_bot)
1294 / (height_top - height_bot);
1295 }
1296
1297 /* Calculate the needed array values... */
1298 double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1299 - array0[ci[0]][ci[1]][ci[2]])
1300 + array0[ci[0]][ci[1]][ci[2]];
1301 double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1302 - array0[ci[0] + 1][ci[1]][ci[2]])
1303 + array0[ci[0] + 1][ci[1]][ci[2]];
1304 double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1305 - array0[ci[0]][ci[1] + 1][ci[2]])
1306 + array0[ci[0]][ci[1] + 1][ci[2]];
1307 double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1308 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1309 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1310 double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1311 - array0[ci[0]][ci[1]][ci[2] + 1])
1312 + array0[ci[0]][ci[1]][ci[2] + 1];
1313 double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
1314 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
1315 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
1316 double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
1317 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
1318 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
1319 double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1320 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1321 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1322
1323 double array00 = cw[0] * (array100 - array000) + array000;
1324 double array10 = cw[0] * (array110 - array010) + array010;
1325 double array01 = cw[0] * (array101 - array001) + array001;
1326 double array11 = cw[0] * (array111 - array011) + array011;
1327
1328 double aux0 = cw[1] * (array10 - array00) + array00;
1329 double aux1 = cw[1] * (array11 - array01) + array01;
1330
1331 /* Interpolate vertically... */
1332 *var = cw[2] * (aux1 - aux0) + aux0;
1333}
1334
1335/*****************************************************************************/
1336
1338 const met_t *met,
1339 float array[EX][EY][EP],
1340 const double p,
1341 const double lon,
1342 const double lat,
1343 double *var,
1344 int *ci,
1345 double *cw,
1346 const int init) {
1347
1348 /* Initialize interpolation... */
1349 if (init) {
1350
1351 /* Check longitude and latitude... */
1352 double lon2, lat2;
1353 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1354 &lon2, &lat2);
1355
1356 /* Get interpolation indices... */
1357 ci[0] = locate_irr(met->p, met->np, p);
1358 ci[1] = locate_reg(met->lon, met->nx, lon2);
1359 ci[2] = locate_irr(met->lat, met->ny, lat2);
1360
1361 /* Get interpolation weights... */
1362 cw[0] = (met->p[ci[0] + 1] - p)
1363 / (met->p[ci[0] + 1] - met->p[ci[0]]);
1364 cw[1] = (met->lon[ci[1] + 1] - lon2)
1365 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1366 cw[2] = (met->lat[ci[2] + 1] - lat2)
1367 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1368 }
1369
1370 /* Interpolate vertically... */
1371 double aux00 =
1372 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
1373 + array[ci[1]][ci[2]][ci[0] + 1];
1374 double aux01 =
1375 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
1376 array[ci[1]][ci[2] + 1][ci[0] + 1])
1377 + array[ci[1]][ci[2] + 1][ci[0] + 1];
1378 double aux10 =
1379 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
1380 array[ci[1] + 1][ci[2]][ci[0] + 1])
1381 + array[ci[1] + 1][ci[2]][ci[0] + 1];
1382 double aux11 =
1383 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
1384 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
1385 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
1386
1387 /* Interpolate horizontally... */
1388 aux00 = cw[2] * (aux00 - aux01) + aux01;
1389 aux11 = cw[2] * (aux10 - aux11) + aux11;
1390 *var = cw[1] * (aux00 - aux11) + aux11;
1391}
1392
1393/*****************************************************************************/
1394
1396 const met_t *met,
1397 float zs[EX][EY][EP],
1398 float array[EX][EY][EP],
1399 const double z,
1400 const double lon,
1401 const double lat,
1402 double *var) {
1403
1404 /* Check longitude and latitude... */
1405 double lon2, lat2;
1406 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat, &lon2,
1407 &lat2);
1408
1409 /* Get horizontal indices... */
1410 const int ix = locate_reg(met->lon, met->nx, lon2);
1411 const int iy = locate_irr(met->lat, met->ny, lat2);
1412
1413 /* Interpolate vertically... */
1414 int iz = locate_irr_float(zs[ix][iy], met->npl, z, 0);
1415 double aux00;
1416 if (z >= zs[ix][iy][iz + 1])
1417 aux00 = array[ix][iy][iz + 1];
1418 else if (z <= zs[ix][iy][iz])
1419 aux00 = array[ix][iy][iz];
1420 else
1421 aux00 = LIN(zs[ix][iy][iz], array[ix][iy][iz],
1422 zs[ix][iy][iz + 1], array[ix][iy][iz + 1], z);
1423
1424 iz = locate_irr_float(zs[ix][iy + 1], met->npl, z, iz);
1425 double aux01;
1426 if (z >= zs[ix][iy + 1][iz + 1])
1427 aux01 = array[ix][iy + 1][iz + 1];
1428 else if (z <= zs[ix][iy + 1][iz])
1429 aux01 = array[ix][iy + 1][iz];
1430 else
1431 aux01 = LIN(zs[ix][iy + 1][iz], array[ix][iy + 1][iz],
1432 zs[ix][iy + 1][iz + 1], array[ix][iy + 1][iz + 1], z);
1433
1434 iz = locate_irr_float(zs[ix + 1][iy], met->npl, z, iz);
1435 double aux10;
1436 if (z >= zs[ix + 1][iy][iz + 1])
1437 aux10 = array[ix + 1][iy][iz + 1];
1438 else if (z <= zs[ix + 1][iy][iz])
1439 aux10 = array[ix + 1][iy][iz];
1440 else
1441 aux10 = LIN(zs[ix + 1][iy][iz], array[ix + 1][iy][iz],
1442 zs[ix + 1][iy][iz + 1], array[ix + 1][iy][iz + 1], z);
1443
1444 iz = locate_irr_float(zs[ix + 1][iy + 1], met->npl, z, iz);
1445 double aux11;
1446 if (z >= zs[ix + 1][iy + 1][iz + 1])
1447 aux11 = array[ix + 1][iy + 1][iz + 1];
1448 else if (z <= zs[ix + 1][iy + 1][iz])
1449 aux11 = array[ix + 1][iy + 1][iz];
1450 else
1451 aux11 = LIN(zs[ix + 1][iy + 1][iz], array[ix + 1][iy + 1][iz],
1452 zs[ix + 1][iy + 1][iz + 1], array[ix + 1][iy + 1][iz + 1], z);
1453
1454 /* Interpolate horizontally... */
1455 double aux0 = LIN(met->lat[iy], aux00, met->lat[iy + 1], aux01, lat2);
1456 double aux1 = LIN(met->lat[iy], aux10, met->lat[iy + 1], aux11, lat2);
1457 *var = LIN(met->lon[ix], aux0, met->lon[ix + 1], aux1, lon2);
1458}
1459
1460/*****************************************************************************/
1461
1463 const met_t *met,
1464 float array[EX][EY],
1465 const double lon,
1466 const double lat,
1467 double *var,
1468 int *ci,
1469 double *cw,
1470 const int init) {
1471
1472 /* Initialize interpolation... */
1473 if (init) {
1474
1475 /* Check longitude and latitude... */
1476 double lon2, lat2;
1477 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1478 &lon2, &lat2);
1479
1480 /* Get interpolation indices... */
1481 ci[1] = locate_reg(met->lon, met->nx, lon2);
1482 ci[2] = locate_irr(met->lat, met->ny, lat2);
1483
1484 /* Get interpolation weights... */
1485 cw[1] = (met->lon[ci[1] + 1] - lon2)
1486 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1487 cw[2] = (met->lat[ci[2] + 1] - lat2)
1488 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1489 }
1490
1491 /* Set variables... */
1492 double aux00 = array[ci[1]][ci[2]];
1493 double aux01 = array[ci[1]][ci[2] + 1];
1494 double aux10 = array[ci[1] + 1][ci[2]];
1495 double aux11 = array[ci[1] + 1][ci[2] + 1];
1496
1497 /* Interpolate horizontally... */
1498 if (isfinite(aux00) && isfinite(aux01)
1499 && isfinite(aux10) && isfinite(aux11)) {
1500 aux00 = cw[2] * (aux00 - aux01) + aux01;
1501 aux11 = cw[2] * (aux10 - aux11) + aux11;
1502 *var = cw[1] * (aux00 - aux11) + aux11;
1503 } else {
1504 if (cw[2] < 0.5) {
1505 if (cw[1] < 0.5)
1506 *var = aux11;
1507 else
1508 *var = aux01;
1509 } else {
1510 if (cw[1] < 0.5)
1511 *var = aux10;
1512 else
1513 *var = aux00;
1514 }
1515 }
1516}
1517
1518/*****************************************************************************/
1519
1521 const met_t *met0,
1522 float array0[EX][EY][EP],
1523 const met_t *met1,
1524 float array1[EX][EY][EP],
1525 const double ts,
1526 const double p,
1527 const double lon,
1528 const double lat,
1529 double *var,
1530 int *ci,
1531 double *cw,
1532 const int init) {
1533
1534 double var0, var1;
1535
1536 /* Spatial interpolation... */
1537 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
1538 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
1539
1540 /* Get weighting factor... */
1541 const double wt = (met1->time - ts) / (met1->time - met0->time);
1542
1543 /* Interpolate... */
1544 *var = wt * (var0 - var1) + var1;
1545}
1546
1547/*****************************************************************************/
1548
1550 const met_t *met0,
1551 float zs0[EX][EY][EP],
1552 float array0[EX][EY][EP],
1553 const met_t *met1,
1554 float zs1[EX][EY][EP],
1555 float array1[EX][EY][EP],
1556 const double ts,
1557 const double p,
1558 const double lon,
1559 const double lat,
1560 double *var) {
1561
1562 double var0, var1;
1563
1564 /* Spatial interpolation... */
1565 intpol_met_space_3d_ml(met0, zs0, array0, p, lon, lat, &var0);
1566 intpol_met_space_3d_ml(met1, zs1, array1, p, lon, lat, &var1);
1567
1568 /* Interpolate... */
1569 *var = LIN(met0->time, var0, met1->time, var1, ts);
1570}
1571
1572/*****************************************************************************/
1573
1575 const met_t *met0,
1576 float array0[EX][EY],
1577 const met_t *met1,
1578 float array1[EX][EY],
1579 const double ts,
1580 const double lon,
1581 const double lat,
1582 double *var,
1583 int *ci,
1584 double *cw,
1585 const int init) {
1586
1587 double var0, var1;
1588
1589 /* Spatial interpolation... */
1590 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
1591 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
1592
1593 /* Get weighting factor... */
1594 const double wt = (met1->time - ts) / (met1->time - met0->time);
1595
1596 /* Interpolate... */
1597 if (isfinite(var0) && isfinite(var1))
1598 *var = wt * (var0 - var1) + var1;
1599 else if (wt < 0.5)
1600 *var = var1;
1601 else
1602 *var = var0;
1603}
1604
1605/*****************************************************************************/
1606
1608 const double time0,
1609 float array0[EX][EY],
1610 const double time1,
1611 float array1[EX][EY],
1612 const double lons[EX],
1613 const double lats[EY],
1614 const int nlon,
1615 const int nlat,
1616 const double time,
1617 const double lon,
1618 const double lat,
1619 const int method,
1620 double *var,
1621 double *sigma) {
1622
1623 double aux0, aux1, aux00, aux01, aux10, aux11, mean = 0;
1624
1625 int n = 0;
1626
1627 /* Check longitude and latitude... */
1628 double lon2, lat2;
1629 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
1630
1631 /* Get indices... */
1632 const int ix = locate_reg(lons, (int) nlon, lon2);
1633 const int iy = locate_irr(lats, (int) nlat, lat2);
1634
1635 /* Calculate standard deviation... */
1636 *sigma = 0;
1637 for (int dx = 0; dx < 2; dx++)
1638 for (int dy = 0; dy < 2; dy++) {
1639 if (isfinite(array0[ix + dx][iy + dy])) {
1640 mean += array0[ix + dx][iy + dy];
1641 *sigma += SQR(array0[ix + dx][iy + dy]);
1642 n++;
1643 }
1644 if (isfinite(array1[ix + dx][iy + dy])) {
1645 mean += array1[ix + dx][iy + dy];
1646 *sigma += SQR(array1[ix + dx][iy + dy]);
1647 n++;
1648 }
1649 }
1650 if (n > 0)
1651 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
1652
1653 /* Linear interpolation... */
1654 if (method == 1 && isfinite(array0[ix][iy])
1655 && isfinite(array0[ix][iy + 1])
1656 && isfinite(array0[ix + 1][iy])
1657 && isfinite(array0[ix + 1][iy + 1])
1658 && isfinite(array1[ix][iy])
1659 && isfinite(array1[ix][iy + 1])
1660 && isfinite(array1[ix + 1][iy])
1661 && isfinite(array1[ix + 1][iy + 1])) {
1662
1663 aux00 = LIN(lons[ix], array0[ix][iy],
1664 lons[ix + 1], array0[ix + 1][iy], lon2);
1665 aux01 = LIN(lons[ix], array0[ix][iy + 1],
1666 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1667 aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1668
1669 aux10 = LIN(lons[ix], array1[ix][iy],
1670 lons[ix + 1], array1[ix + 1][iy], lon2);
1671 aux11 = LIN(lons[ix], array1[ix][iy + 1],
1672 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1673 aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1674
1675 *var = LIN(time0, aux0, time1, aux1, time);
1676 }
1677
1678 /* Nearest neighbor interpolation... */
1679 else {
1680 aux00 = NN(lons[ix], array0[ix][iy],
1681 lons[ix + 1], array0[ix + 1][iy], lon2);
1682 aux01 = NN(lons[ix], array0[ix][iy + 1],
1683 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1684 aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1685
1686 aux10 = NN(lons[ix], array1[ix][iy],
1687 lons[ix + 1], array1[ix + 1][iy], lon2);
1688 aux11 = NN(lons[ix], array1[ix][iy + 1],
1689 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1690 aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1691
1692 *var = NN(time0, aux0, time1, aux1, time);
1693 }
1694}
1695
1696/*****************************************************************************/
1697
1699 const double jsec,
1700 int *year,
1701 int *mon,
1702 int *day,
1703 int *hour,
1704 int *min,
1705 int *sec,
1706 double *remain) {
1707
1708 struct tm t0, *t1;
1709
1710 t0.tm_year = 100;
1711 t0.tm_mon = 0;
1712 t0.tm_mday = 1;
1713 t0.tm_hour = 0;
1714 t0.tm_min = 0;
1715 t0.tm_sec = 0;
1716
1717 const time_t jsec0 = (time_t) jsec + timegm(&t0);
1718 t1 = gmtime(&jsec0);
1719
1720 *year = t1->tm_year + 1900;
1721 *mon = t1->tm_mon + 1;
1722 *day = t1->tm_mday;
1723 *hour = t1->tm_hour;
1724 *min = t1->tm_min;
1725 *sec = t1->tm_sec;
1726 *remain = jsec - floor(jsec);
1727}
1728
1729/*****************************************************************************/
1730
1732 const double kz[EP],
1733 const double kw[EP],
1734 const int nk,
1735 const double p) {
1736
1737 /* Check number of data points... */
1738 if (nk < 2)
1739 return 1.0;
1740
1741 /* Get altitude... */
1742 const double z = Z(p);
1743
1744 /* Get weighting factor... */
1745 if (z < kz[0])
1746 return kw[0];
1747 else if (z > kz[nk - 1])
1748 return kw[nk - 1];
1749 else {
1750 int idx = locate_irr(kz, nk, z);
1751 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
1752 }
1753}
1754
1755/*****************************************************************************/
1756
1758 const double t,
1759 const double h2o) {
1760
1761 /*
1762 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
1763 and water vapor volume mixing ratio [1].
1764
1765 Reference: https://en.wikipedia.org/wiki/Lapse_rate
1766 */
1767
1768 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
1769
1770 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
1771}
1772
1773/*****************************************************************************/
1774
1776 ctl_t *ctl) {
1777
1778 if (0 == ctl->met_press_level_def) {
1779
1780 ctl->met_np = 138;
1781
1782 const double press[138] = {
1783 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1784 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1785 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1786 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1787 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1788 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1789 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1790 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1791 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1792 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1793 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1794 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1795 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1796 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1797 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1798 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1799 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1800 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1801 1010.8487, 1013.2500, 1044.45
1802 };
1803
1804 for (int ip = 0; ip < ctl->met_np; ip++)
1805 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1806
1807 } else if (1 == ctl->met_press_level_def) {
1808
1809 ctl->met_np = 92;
1810
1811 const double press[92] = {
1812 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1813 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1814 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1815 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1816 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1817 113.6382,
1818 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1819 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1820 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1821 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1822 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1823 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1824 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1825 1007.4431, 1010.8487, 1013.2500, 1044.45
1826 };
1827
1828 for (int ip = 0; ip < ctl->met_np; ip++)
1829 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1830
1831 } else if (2 == ctl->met_press_level_def) {
1832
1833 ctl->met_np = 60;
1834
1835 const double press[60] = {
1836 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1837 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1838 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1839 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1840 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1841 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1842 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1843 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 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 (3 == ctl->met_press_level_def) {
1850
1851 ctl->met_np = 147;
1852
1853 const double press[147] = {
1854 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1855 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1856 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1857 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1858 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1859 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1860 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1861 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1862 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1863 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1864 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1865 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1866 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1867 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1868 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1869 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1870 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1871 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1872 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
1873 1031.97,
1874 1035.09, 1038.21, 1041.33, 1044.45
1875 };
1876
1877 for (int ip = 0; ip < ctl->met_np; ip++)
1878 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1879
1880 } else if (4 == ctl->met_press_level_def) {
1881
1882 ctl->met_np = 101;
1883
1884 const double press[101] = {
1885 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1886 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1887 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1888 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1889 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1890 113.6382,
1891 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1892 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1893 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1894 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1895 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1896 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1897 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1898 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
1899 1028.85, 1031.97,
1900 1035.09, 1038.21, 1041.33, 1044.45
1901 };
1902
1903 for (int ip = 0; ip < ctl->met_np; ip++)
1904 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1905
1906 } else if (5 == ctl->met_press_level_def) {
1907
1908 ctl->met_np = 62;
1909
1910 const double press[62] = {
1911 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1912 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1913 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1914 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1915 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1916 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1917 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1918 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
1919 1044.45
1920 };
1921
1922 for (int ip = 0; ip < ctl->met_np; ip++)
1923 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1924
1925 } else if (6 == ctl->met_press_level_def) {
1926
1927 ctl->met_np = 137;
1928
1929 const double press[137] = {
1930 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
1931 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
1932 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
1933 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
1934 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
1935 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1936 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
1937 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
1938 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
1939 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
1940 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
1941 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
1942 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
1943 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
1944 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
1945 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
1946 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
1947 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
1948 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
1949 1030.06, 1037.25, 1044.45
1950 };
1951
1952 for (int ip = 0; ip < ctl->met_np; ip++)
1953 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1954
1955 } else if (7 == ctl->met_press_level_def) {
1956
1957 ctl->met_np = 59;
1958
1959 const double press[59] = {
1960 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
1961 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
1962 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
1963 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
1964 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
1965 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
1966 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
1967 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
1968 1028.53, 1046.13
1969 };
1970
1971 for (int ip = 0; ip < ctl->met_np; ip++)
1972 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1973
1974 } else {
1975 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.")
1976 }
1977}
1978
1979/*****************************************************************************/
1980
1982 const double *xx,
1983 const int n,
1984 const double x) {
1985
1986 int ilo = 0;
1987 int ihi = n - 1;
1988 int i = (ihi + ilo) >> 1;
1989
1990 if (xx[i] < xx[i + 1])
1991 while (ihi > ilo + 1) {
1992 i = (ihi + ilo) >> 1;
1993 if (xx[i] > x)
1994 ihi = i;
1995 else
1996 ilo = i;
1997 } else
1998 while (ihi > ilo + 1) {
1999 i = (ihi + ilo) >> 1;
2000 if (xx[i] <= x)
2001 ihi = i;
2002 else
2003 ilo = i;
2004 }
2005
2006 return ilo;
2007}
2008
2009/*****************************************************************************/
2010
2012 const float *xx,
2013 const int n,
2014 const double x,
2015 const int ig) {
2016
2017 int ilo = 0;
2018 int ihi = n - 1;
2019 int i = (ihi + ilo) >> 1;
2020
2021 if (x >= xx[ig] && x < xx[ig + 1])
2022 return ig;
2023
2024 if (xx[i] < xx[i + 1])
2025 while (ihi > ilo + 1) {
2026 i = (ihi + ilo) >> 1;
2027 if (xx[i] > x)
2028 ihi = i;
2029 else
2030 ilo = i;
2031 } else
2032 while (ihi > ilo + 1) {
2033 i = (ihi + ilo) >> 1;
2034 if (xx[i] <= x)
2035 ihi = i;
2036 else
2037 ilo = i;
2038 }
2039
2040 return ilo;
2041}
2042
2043/*****************************************************************************/
2044
2046 const double *xx,
2047 const int n,
2048 const double x) {
2049
2050 /* Calculate index... */
2051 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2052
2053 /* Check range... */
2054 if (i < 0)
2055 return 0;
2056 else if (i > n - 2)
2057 return n - 2;
2058 else
2059 return i;
2060}
2061
2062/*****************************************************************************/
2063
2065 float profiles[EX][EY][EP],
2066 const int np,
2067 const int lon_ap_ind,
2068 const int lat_ap_ind,
2069 const double height_ap,
2070 int *ind) {
2071
2072 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2073 np, height_ap, 0);
2074 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2075 np, height_ap, ind[0]);
2076 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2077 np, height_ap, ind[1]);
2078 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2079 np, height_ap, ind[2]);
2080}
2081
2082/*****************************************************************************/
2083
2085 const ctl_t *ctl,
2086 const cache_t *cache,
2087 met_t *met0,
2088 met_t *met1,
2089 atm_t *atm) {
2090
2091 /* Set timer... */
2092 SELECT_TIMER("MODULE_ADVECT", "PHYSICS", NVTX_GPU);
2093
2094 /* Use omega vertical velocity... */
2095 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2096
2097 /* Loop over particles... */
2098 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2099
2100 /* Init... */
2102 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2103 x[3] = { 0, 0, 0 };
2104
2105 /* Loop over integration nodes... */
2106 for (int i = 0; i < ctl->advect; i++) {
2107
2108 /* Set position... */
2109 if (i == 0) {
2110 dts = 0.0;
2111 x[0] = atm->lon[ip];
2112 x[1] = atm->lat[ip];
2113 x[2] = atm->p[ip];
2114 } else {
2115 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2116 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2117 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2118 x[2] = atm->p[ip] + dts * w[i - 1];
2119 }
2120 const double tm = atm->time[ip] + dts;
2121
2122 /* Interpolate meteo data on pressure levels... */
2123 if (ctl->advect_vert_coord == 0) {
2124 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2125 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2126 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2127 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2128 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2129 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2130 }
2131
2132 /* Interpolate meteo data on model levels... */
2133 else {
2134 intpol_met_time_3d_ml(met0, met0->pl, met0->ul,
2135 met1, met1->pl, met1->ul,
2136 tm, x[2], x[0], x[1], &u[i]);
2137 intpol_met_time_3d_ml(met0, met0->pl, met0->vl,
2138 met1, met1->pl, met1->vl,
2139 tm, x[2], x[0], x[1], &v[i]);
2140 intpol_met_time_3d_ml(met0, met0->pl, met0->wl,
2141 met1, met1->pl, met1->wl,
2142 tm, x[2], x[0], x[1], &w[i]);
2143 }
2144
2145 /* Get mean wind... */
2146 double k = 1.0;
2147 if (ctl->advect == 2)
2148 k = (i == 0 ? 0.0 : 1.0);
2149 else if (ctl->advect == 4)
2150 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2151 um += k * u[i];
2152 vm += k * v[i];
2153 wm += k * w[i];
2154 }
2155
2156 /* Set new position... */
2157 atm->time[ip] += cache->dt[ip];
2158 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2159 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2160 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2161 atm->p[ip] += cache->dt[ip] * wm;
2162 }
2163 }
2164
2165 /* Use zetadot vertical velocity... */
2166 else if (ctl->advect_vert_coord == 1) {
2167
2168 /* Loop over particles... */
2169 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2170
2171 /* Convert pressure to zeta... */
2173
2174 // TODO: can we use intpol_met_time_3d_ml instead of intpol_met_4d_coord?
2175
2176 intpol_met_4d_coord(met0, met0->pl, met0->zetal, met1,
2177 met1->pl, met1->zetal, atm->time[ip], atm->p[ip],
2178 atm->lon[ip], atm->lat[ip],
2179 &atm->q[ctl->qnt_zeta][ip], ci, cw, 1);
2180
2181 /* Init... */
2182 double dts, u[4], um = 0, v[4], vm = 0, zeta_dot[4],
2183 zeta_dotm = 0, x[3] = { 0, 0, 0 };
2184
2185 /* Loop over integration nodes... */
2186 for (int i = 0; i < ctl->advect; i++) {
2187
2188 /* Set position... */
2189 if (i == 0) {
2190 dts = 0.0;
2191 x[0] = atm->lon[ip];
2192 x[1] = atm->lat[ip];
2193 x[2] = atm->q[ctl->qnt_zeta][ip];
2194 } else {
2195 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2196 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2197 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2198 x[2] = atm->q[ctl->qnt_zeta][ip] + dts * zeta_dot[i - 1];
2199 }
2200 const double tm = atm->time[ip] + dts;
2201
2202 /* Interpolate meteo data... */
2203 intpol_met_4d_coord(met0, met0->zetal, met0->ul, met1, met1->zetal,
2204 met1->ul, tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2205 intpol_met_4d_coord(met0, met0->zetal, met0->vl, met1, met1->zetal,
2206 met1->vl, tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2207 intpol_met_4d_coord(met0, met0->zetal, met0->zeta_dotl, met1,
2208 met1->zetal, met1->zeta_dotl, tm, x[2], x[0],
2209 x[1], &zeta_dot[i], ci, cw, 0);
2210
2211 /* Get mean wind... */
2212 double k = 1.0;
2213 if (ctl->advect == 2)
2214 k = (i == 0 ? 0.0 : 1.0);
2215 else if (ctl->advect == 4)
2216 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2217 um += k * u[i];
2218 vm += k * v[i];
2219 zeta_dotm += k * zeta_dot[i];
2220 }
2221
2222 /* Set new position... */
2223 atm->time[ip] += cache->dt[ip];
2224 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2225 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2226 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2227 atm->q[ctl->qnt_zeta][ip] += cache->dt[ip] * zeta_dotm;
2228
2229 /* Convert zeta to pressure... */
2230 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2231 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2232 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2233 }
2234 }
2235}
2236
2237/*****************************************************************************/
2238
2240 const ctl_t *ctl,
2241 const cache_t *cache,
2242 met_t *met0,
2243 met_t *met1,
2244 atm_t *atm) {
2245
2246 /* Check parameters... */
2247 if (ctl->advect_vert_coord != 1)
2248 return;
2249
2250 /* Set timer... */
2251 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS", NVTX_GPU);
2252
2253 /* Loop over particles... */
2254 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
2255
2256 /* Initialize pressure consistent with zeta... */
2258 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2259 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2260 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2261 }
2262}
2263
2264/*****************************************************************************/
2265
2267 const ctl_t *ctl,
2268 const cache_t *cache,
2269 const clim_t *clim,
2270 met_t *met0,
2271 met_t *met1,
2272 atm_t *atm) {
2273
2274 /* Set timer... */
2275 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS", NVTX_GPU);
2276
2277 /* Check quantity flags... */
2278 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2279 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2280 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2281 return;
2282
2283 /* Loop over particles... */
2284 PARTICLE_LOOP(0, atm->np, 1,
2285 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2286
2287 /* Check latitude and pressure range... */
2288 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2289 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2290 continue;
2291
2292 /* Check surface layer... */
2293 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2294 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2295
2296 /* Get surface pressure... */
2297 double ps;
2299 INTPOL_2D(ps, 1);
2300
2301 /* Check pressure... */
2302 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2303 continue;
2304
2305 /* Check height... */
2306 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2307 continue;
2308
2309 /* Check zeta range... */
2310 if (ctl->bound_zetas > 0) {
2311 double t;
2312 INTPOL_3D(t, 1);
2313 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2314 continue;
2315 }
2316
2317 /* Check planetary boundary layer... */
2318 if (ctl->bound_pbl) {
2319 double pbl;
2320 INTPOL_2D(pbl, 0);
2321 if (atm->p[ip] < pbl)
2322 continue;
2323 }
2324 }
2325
2326 /* Set mass and volume mixing ratio... */
2327 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2328 atm->q[ctl->qnt_m][ip] =
2329 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2330 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2331 atm->q[ctl->qnt_vmr][ip] =
2332 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2333
2334 /* Set CFC-10 volume mixing ratio... */
2335 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2336 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2337
2338 /* Set CFC-11 volume mixing ratio... */
2339 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2340 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2341
2342 /* Set CFC-12 volume mixing ratio... */
2343 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2344 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2345
2346 /* Set N2O volume mixing ratio... */
2347 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2348 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2349
2350 /* Set SF6 volume mixing ratio... */
2351 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2352 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2353
2354 /* Set age of air... */
2355 if (ctl->qnt_aoa >= 0)
2356 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2357 }
2358}
2359
2360/*****************************************************************************/
2361
2363 const ctl_t *ctl,
2364 met_t *met0,
2365 met_t *met1,
2366 atm_t *atm,
2367 const double tt) {
2368
2369 /* Check quantities... */
2370 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
2371 return;
2372 if (ctl->molmass <= 0)
2373 ERRMSG("Molar mass is not defined!");
2374
2375 /* Set timer... */
2376 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS", NVTX_GPU);
2377
2378 /* Allocate... */
2379 const int np = atm->np;
2380 const int nz = ctl->chemgrid_nz;
2381 const int nx = ctl->chemgrid_nx;
2382 const int ny = ctl->chemgrid_ny;
2383 const int ngrid = nx * ny * nz;
2384
2385 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2386 double *restrict const press =
2387 (double *) malloc((size_t) nz * sizeof(double));
2388 double *restrict const mass =
2389 (double *) calloc((size_t) ngrid, sizeof(double));
2390 double *restrict const area =
2391 (double *) malloc((size_t) ny * sizeof(double));
2392 double *restrict const lon =
2393 (double *) malloc((size_t) nx * sizeof(double));
2394 double *restrict const lat =
2395 (double *) malloc((size_t) ny * sizeof(double));
2396
2397 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2398 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2399 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2400
2401 /* Set grid box size... */
2402 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2403 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2404 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2405
2406 /* Set vertical coordinates... */
2407#ifdef _OPENACC
2408#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])
2409#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2410#pragma acc parallel loop independent gang vector
2411#else
2412#pragma omp parallel for default(shared)
2413#endif
2414 for (int iz = 0; iz < nz; iz++) {
2415 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2416 press[iz] = P(z[iz]);
2417 }
2418
2419 /* Set time interval for output... */
2420 const double t0 = tt - 0.5 * ctl->dt_mod;
2421 const double t1 = tt + 0.5 * ctl->dt_mod;
2422
2423 /* Get indices... */
2424#ifdef _OPENACC
2425#pragma acc parallel loop independent gang vector
2426#else
2427#pragma omp parallel for default(shared)
2428#endif
2429 for (int ip = 0; ip < np; ip++) {
2430 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2431 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2432 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2433 if (atm->time[ip] < t0 || atm->time[ip] > t1
2434 || ixs[ip] < 0 || ixs[ip] >= nx
2435 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2436 izs[ip] = -1;
2437 }
2438
2439 /* Set horizontal coordinates... */
2440#ifdef _OPENACC
2441#pragma acc parallel loop independent gang vector
2442#else
2443#pragma omp parallel for default(shared)
2444#endif
2445 for (int ix = 0; ix < nx; ix++)
2446 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
2447#ifdef _OPENACC
2448#pragma acc parallel loop independent gang vector
2449#else
2450#pragma omp parallel for default(shared)
2451#endif
2452 for (int iy = 0; iy < ny; iy++) {
2453 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
2454 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
2455 }
2456
2457 /* Get mass per grid box... */
2458#ifdef _OPENACC
2459#pragma acc parallel loop independent gang vector
2460#endif
2461 for (int ip = 0; ip < np; ip++)
2462 if (izs[ip] >= 0)
2463#ifdef _OPENACC
2464#pragma acc atomic update
2465#endif
2466 mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)]
2467 += atm->q[ctl->qnt_m][ip];
2468
2469 /* Assign grid data to air parcels ... */
2470#ifdef _OPENACC
2471#pragma acc parallel loop independent gang vector
2472#else
2473#pragma omp parallel for default(shared)
2474#endif
2475 for (int ip = 0; ip < np; ip++)
2476 if (izs[ip] >= 0) {
2477
2478 /* Interpolate temperature... */
2479 double temp;
2481 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt, press[izs[ip]],
2482 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
2483
2484 /* Set mass... */
2485 const double m = mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)];
2486
2487 /* Calculate volume mixing ratio... */
2488 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
2489 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
2490 }
2491#ifdef _OPENACC
2492#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
2493#endif
2494
2495 /* Free... */
2496 free(mass);
2497 free(lon);
2498 free(lat);
2499 free(area);
2500 free(z);
2501 free(press);
2502 free(ixs);
2503 free(iys);
2504 free(izs);
2505}
2506
2507/*****************************************************************************/
2508
2510 const ctl_t *ctl,
2511 const cache_t *cache,
2512 const clim_t *clim,
2513 met_t *met0,
2514 met_t *met1,
2515 atm_t *atm) {
2516
2517 /* Set timer... */
2518 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS", NVTX_GPU);
2519
2520 /* Loop over particles... */
2521 PARTICLE_LOOP(0, atm->np, 0,
2522 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2523
2524 /* Set H2O and O3 using meteo data... */
2526 if (ctl->qnt_Ch2o >= 0) {
2527 double h2o;
2528 INTPOL_3D(h2o, 1);
2529 SET_ATM(qnt_Ch2o, h2o);
2530 }
2531 if (ctl->qnt_Co3 >= 0) {
2532 double o3;
2533 INTPOL_3D(o3, 1);
2534 SET_ATM(qnt_Co3, o3);
2535 }
2536
2537 /* Set radical species... */
2538 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
2539 atm->lon[ip], atm->lat[ip], atm->p[ip]));
2540 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
2541 atm->lat[ip], atm->p[ip]));
2542 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
2543 atm->lat[ip], atm->p[ip]));
2544 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
2545 atm->lat[ip], atm->p[ip]));
2546 }
2547}
2548
2549/*****************************************************************************/
2550
2552 const ctl_t *ctl,
2553 cache_t *cache,
2554 met_t *met0,
2555 met_t *met1,
2556 atm_t *atm) {
2557
2558 /* Set timer... */
2559 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
2560
2561 /* Create random numbers... */
2562 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
2563
2564 /* Loop over particles... */
2565 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2566
2567 /* Interpolate CAPE... */
2568 double ps;
2570 INTPOL_2D(ps, 1);
2571
2572 /* Initialize pressure range for vertical mixing... */
2573 double pbot = ps, ptop = ps;
2574
2575 /* Mixing in the PBL... */
2576 if (ctl->conv_mix_pbl) {
2577
2578 /* Interpolate PBL... */
2579 double pbl;
2580 INTPOL_2D(pbl, 0);
2581
2582 /* Set pressure range... */
2583 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
2584 }
2585
2586 /* Convective mixing... */
2587 if (ctl->conv_cape >= 0) {
2588
2589 /* Interpolate CAPE, CIN, and equilibrium level... */
2590 double cape, cin, pel;
2591 INTPOL_2D(cape, 0);
2592 INTPOL_2D(cin, 0);
2593 INTPOL_2D(pel, 0);
2594
2595 /* Set pressure range... */
2596 if (isfinite(cape) && cape >= ctl->conv_cape
2597 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
2598 ptop = GSL_MIN(ptop, pel);
2599 }
2600
2601 /* Apply vertical mixing... */
2602 if (ptop != pbot && atm->p[ip] >= ptop) {
2603
2604 /* Get density range... */
2605 double tbot, ttop;
2606 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2607 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
2608 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2609 ptop, atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
2610 const double rhobot = pbot / tbot;
2611 const double rhotop = ptop / ttop;
2612
2613 /* Get new density... */
2614 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
2615
2616 /* Get pressure... */
2617 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
2618 }
2619 }
2620}
2621
2622/*****************************************************************************/
2623
2625 const ctl_t *ctl,
2626 const cache_t *cache,
2627 const clim_t *clim,
2628 atm_t *atm) {
2629
2630 /* Set timer... */
2631 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
2632
2633 /* Check quantity flags... */
2634 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2635 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2636
2637 /* Loop over particles... */
2638 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
2639
2640 /* Get weighting factor... */
2641 const double w = tropo_weight(clim, atm, ip);
2642
2643 /* Set lifetime... */
2644 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
2645
2646 /* Calculate exponential decay... */
2647 const double aux = exp(-cache->dt[ip] / tdec);
2648 if (ctl->qnt_m >= 0) {
2649 if (ctl->qnt_mloss_decay >= 0)
2650 atm->q[ctl->qnt_mloss_decay][ip]
2651 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2652 atm->q[ctl->qnt_m][ip] *= aux;
2653 if (ctl->qnt_loss_rate >= 0)
2654 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
2655 }
2656 if (ctl->qnt_vmr >= 0)
2657 atm->q[ctl->qnt_vmr][ip] *= aux;
2658 }
2659}
2660
2661/*****************************************************************************/
2662
2664 const ctl_t *ctl,
2665 cache_t *cache,
2666 met_t *met0,
2667 met_t *met1,
2668 atm_t *atm) {
2669
2670 /* Set timer... */
2671 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS", NVTX_GPU);
2672
2673 /* Create random numbers... */
2674 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2675
2676 /* Loop over particles... */
2677 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2678
2679 /* Get indices... */
2680 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
2681 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
2682 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
2683
2684 /* Get standard deviations of local wind data... */
2685 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
2686 for (int i = 0; i < 2; i++)
2687 for (int j = 0; j < 2; j++)
2688 for (int k = 0; k < 2; k++) {
2689 umean += met0->u[ix + i][iy + j][iz + k];
2690 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
2691 vmean += met0->v[ix + i][iy + j][iz + k];
2692 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
2693 wmean += met0->w[ix + i][iy + j][iz + k];
2694 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
2695
2696 umean += met1->u[ix + i][iy + j][iz + k];
2697 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
2698 vmean += met1->v[ix + i][iy + j][iz + k];
2699 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
2700 wmean += met1->w[ix + i][iy + j][iz + k];
2701 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
2702 }
2703 usig = usig / 16.f - SQR(umean / 16.f);
2704 usig = (usig > 0 ? sqrtf(usig) : 0);
2705 vsig = vsig / 16.f - SQR(vmean / 16.f);
2706 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
2707 wsig = wsig / 16.f - SQR(wmean / 16.f);
2708 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
2709
2710 /* Set temporal correlations for mesoscale fluctuations... */
2711 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
2712 const double r2 = sqrt(1 - r * r);
2713
2714 /* Calculate horizontal mesoscale wind fluctuations... */
2715 if (ctl->turb_mesox > 0) {
2716 cache->uvwp[ip][0] =
2717 (float) (r * cache->uvwp[ip][0] +
2718 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
2719 atm->lon[ip] +=
2720 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2721
2722 cache->uvwp[ip][1] =
2723 (float) (r * cache->uvwp[ip][1] +
2724 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
2725 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2726 }
2727
2728 /* Calculate vertical mesoscale wind fluctuations... */
2729 if (ctl->turb_mesoz > 0) {
2730 cache->uvwp[ip][2] =
2731 (float) (r * cache->uvwp[ip][2] +
2732 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
2733 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
2734 }
2735 }
2736}
2737
2738/*****************************************************************************/
2739
2741 const ctl_t *ctl,
2742 cache_t *cache,
2743 met_t *met0,
2744 met_t *met1,
2745 atm_t *atm) {
2746
2747 /* Set timer... */
2748 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS", NVTX_GPU);
2749
2750 /* Create random numbers... */
2751 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2752
2753 /* Loop over particles... */
2754 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2755
2756 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
2757 tau_u = 300., tau_w = 100.;
2758
2759 /* Get surface and PBL pressure... */
2760 double pbl, ps;
2762 INTPOL_2D(ps, 1);
2763 INTPOL_2D(pbl, 0);
2764
2765 /* Boundary layer... */
2766 if (atm->p[ip] >= pbl) {
2767
2768 /* Calculate heights... */
2769 const double p = MIN(atm->p[ip], ps);
2770 const double zs = Z(ps);
2771 const double z = 1e3 * (Z(p) - zs);
2772 const double zi = 1e3 * (Z(pbl) - zs);
2773 const double zratio = z / zi;
2774
2775 /* Calculate friction velocity... */
2776 double ess, nss, h2o, t;
2777 INTPOL_2D(ess, 0);
2778 INTPOL_2D(nss, 0);
2779 INTPOL_3D(t, 1);
2780 INTPOL_3D(h2o, 0);
2781 const double rho = RHO(p, TVIRT(t, h2o));
2782 const double tau = sqrt(SQR(ess) + SQR(nss));
2783 const double ustar = sqrt(tau / rho);
2784
2785 /* Get surface sensible heat flux... */
2786 double shf;
2787 INTPOL_2D(shf, 1);
2788
2789 /* Stable or neutral conditions... */
2790 if (shf <= 0) {
2791
2792 /* Calcalute turbulent velocity variances... */
2793 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
2794 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
2795
2796 /* Calculate derivative dsig_w/dz... */
2797 dsigw_dz = -1.3 * ustar / zi;
2798
2799 /* Calcalute Lagrangian timescales... */
2800 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
2801 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
2802 }
2803
2804 /* Unstable conditions... */
2805 else {
2806
2807 /* Convective velocity... */
2808 const double wstar =
2809 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
2810
2811 /* Calcalute turbulent velocity variances... */
2812 sig_u = 1e-2
2813 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
2814 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
2815 * pow(zratio, 2.0 / 3.0)
2816 + (1.8 - 1.4 * zratio) * SQR(ustar));
2817
2818 /* Calculate derivative dsig_w/dz... */
2819 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
2820 * (0.8 *
2821 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
2822 - 1.8 * pow(zratio, 2.0 / 3.0)));
2823
2824 /* Calcalute Lagrangian timescales... */
2825 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
2826 const double eps =
2827 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
2828 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
2829 tau_u = 2 * SQR(sig_u) / (C0 * eps);
2830 tau_w = 2 * SQR(sig_w) / (C0 * eps);
2831 }
2832 }
2833
2834 /* Set minimum values... */
2835 sig_u = MAX(sig_u, 0.25);
2836 sig_w = MAX(sig_w, 0.1);
2837 tau_u = MAX(tau_u, 300.);
2838 tau_w = MAX(tau_w, 100.);
2839
2840 /* Update perturbations... */
2841 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
2842 const double ru2 = sqrt(1.0 - SQR(ru));
2843 cache->uvwp[ip][0]
2844 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
2845 cache->uvwp[ip][1]
2846 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
2847
2848 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
2849 const double rw2 = sqrt(1.0 - SQR(rw));
2850 cache->uvwp[ip][2]
2851 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
2852 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
2853
2854 /* Calculate new air parcel position... */
2855 atm->lon[ip] +=
2856 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2857 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2858 atm->p[ip] +=
2859 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
2860 }
2861}
2862
2863/*****************************************************************************/
2864
2866 const ctl_t *ctl,
2867 cache_t *cache,
2868 const clim_t *clim,
2869 met_t *met0,
2870 met_t *met1,
2871 atm_t *atm) {
2872
2873 /* Set timer... */
2874 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS", NVTX_GPU);
2875
2876 /* Create random numbers... */
2877 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2878
2879 /* Loop over particles... */
2880 PARTICLE_LOOP(0, atm->np, 1,
2881 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2882
2883 /* Get PBL and surface pressure... */
2884 double pbl, ps;
2886 INTPOL_2D(pbl, 1);
2887 INTPOL_2D(ps, 0);
2888
2889 /* Get weighting factors... */
2890 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
2891 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
2892 const double wstrat = 1.0 - wpbl - wtrop;
2893
2894 /* Set diffusivity... */
2895 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
2896 + wstrat * ctl->turb_dx_strat;
2897 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
2898 + wstrat * ctl->turb_dz_strat;
2899
2900 /* Horizontal turbulent diffusion... */
2901 if (dx > 0) {
2902 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
2903 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
2904 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
2905 }
2906
2907 /* Vertical turbulent diffusion... */
2908 if (dz > 0) {
2909 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
2910 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
2911 }
2912 }
2913}
2914
2915/*****************************************************************************/
2916
2918 const ctl_t *ctl,
2919 const cache_t *cache,
2920 met_t *met0,
2921 met_t *met1,
2922 atm_t *atm) {
2923
2924 /* Set timer... */
2925 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS", NVTX_GPU);
2926
2927 /* Check quantity flags... */
2928 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2929 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2930
2931 /* Loop over particles... */
2932 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2933
2934 /* Get surface pressure... */
2935 double ps;
2937 INTPOL_2D(ps, 1);
2938
2939 /* Check whether particle is above the surface layer... */
2940 if (atm->p[ip] < ps - ctl->dry_depo_dp)
2941 continue;
2942
2943 /* Set depth of surface layer... */
2944 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
2945
2946 /* Calculate sedimentation velocity for particles... */
2947 double v_dep;
2948 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
2949
2950 /* Get temperature... */
2951 double t;
2952 INTPOL_3D(t, 1);
2953
2954 /* Set deposition velocity... */
2955 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
2956 atm->q[ctl->qnt_rhop][ip]);
2957 }
2958
2959 /* Use explicit sedimentation velocity for gases... */
2960 else
2961 v_dep = ctl->dry_depo_vdep;
2962
2963 /* Calculate loss of mass based on deposition velocity... */
2964 const double aux = exp(-cache->dt[ip] * v_dep / dz);
2965 if (ctl->qnt_m >= 0) {
2966 if (ctl->qnt_mloss_dry >= 0)
2967 atm->q[ctl->qnt_mloss_dry][ip]
2968 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2969 atm->q[ctl->qnt_m][ip] *= aux;
2970 if (ctl->qnt_loss_rate >= 0)
2971 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
2972 }
2973 if (ctl->qnt_vmr >= 0)
2974 atm->q[ctl->qnt_vmr][ip] *= aux;
2975 }
2976}
2977
2978/*****************************************************************************/
2979
2981 const ctl_t *ctl,
2982 const cache_t *cache,
2983 const clim_t *clim,
2984 met_t *met0,
2985 met_t *met1,
2986 atm_t *atm) {
2987
2988 /* Set timer... */
2989 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS", NVTX_GPU);
2990
2991 /* Check quantity flags... */
2992 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2993 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2994
2995 /* Parameter of SO2 correction... */
2996 const double a = 3.12541941e-06;
2997 const double b = -5.72532259e-01;
2998 const double low = pow(1. / a, 1. / b);
2999
3000 /* Loop over particles... */
3001 PARTICLE_LOOP(0, atm->np, 1,
3002 "acc data present(ctl,cache,ctl,met0,met1,atm)") {
3003
3004 /* Check whether particle is inside cloud... */
3005 double lwc, rwc;
3007 INTPOL_3D(lwc, 1);
3008 INTPOL_3D(rwc, 0);
3009 if (!(lwc > 0 || rwc > 0))
3010 continue;
3011
3012 /* Get temperature... */
3013 double t;
3014 INTPOL_3D(t, 0);
3015
3016 /* Get molecular density... */
3017 const double M = MOLEC_DENS(atm->p[ip], t);
3018
3019 /* Reaction rate (Berglen et al., 2004)... */
3020 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3021
3022 /* Henry constant of SO2... */
3023 const double H_SO2 =
3024 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3025 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3026
3027 /* Henry constant of H2O2... */
3028 const double H_h2o2 =
3029 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3030
3031 /* Correction factor for high SO2 concentration
3032 (if qnt_Cx is defined, the correction is switched on)... */
3033 double cor = 1.0;
3034 if (ctl->qnt_Cx >= 0)
3035 cor = atm->q[ctl->qnt_Cx][ip] >
3036 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3037
3038 const double h2o2 = H_h2o2
3039 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3040 * M * cor * 1000. / AVO; /* unit: mol/L */
3041
3042 /* Volume water content in cloud [m^3 m^(-3)]... */
3043 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3044 const double CWC = (lwc + rwc) * rho_air / 1e3;
3045
3046 /* Calculate exponential decay (Rolph et al., 1992)... */
3047 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3048 const double aux = exp(-cache->dt[ip] * rate_coef);
3049 if (ctl->qnt_m >= 0) {
3050 if (ctl->qnt_mloss_h2o2 >= 0)
3051 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3052 atm->q[ctl->qnt_m][ip] *= aux;
3053 if (ctl->qnt_loss_rate >= 0)
3054 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3055 }
3056 if (ctl->qnt_vmr >= 0)
3057 atm->q[ctl->qnt_vmr][ip] *= aux;
3058 }
3059}
3060
3061/*****************************************************************************/
3062
3064 const ctl_t *ctl,
3065 cache_t *cache,
3066 met_t *met0,
3067 met_t *met1,
3068 atm_t *atm) {
3069
3070 double t;
3071
3072 /* Set timer... */
3073 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS", NVTX_GPU);
3074
3075 /* Save pressure... */
3076 if (ctl->isosurf == 1) {
3077 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
3078 cache->iso_var[ip] = atm->p[ip];
3079 }
3080 }
3081
3082 /* Save density... */
3083 else if (ctl->isosurf == 2) {
3084 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3086 INTPOL_3D(t, 1);
3087 cache->iso_var[ip] = atm->p[ip] / t;
3088 }
3089 }
3090
3091 /* Save potential temperature... */
3092 else if (ctl->isosurf == 3) {
3093 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3095 INTPOL_3D(t, 1);
3096 cache->iso_var[ip] = THETA(atm->p[ip], t);
3097 }
3098 }
3099
3100 /* Read balloon pressure data... */
3101 else if (ctl->isosurf == 4) {
3102
3103 /* Write info... */
3104 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3105
3106 /* Open file... */
3107 FILE *in;
3108 if (!(in = fopen(ctl->balloon, "r")))
3109 ERRMSG("Cannot open file!");
3110
3111 /* Read pressure time series... */
3112 char line[LEN];
3113 while (fgets(line, LEN, in))
3114 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3115 &(cache->iso_ps[cache->iso_n])) == 2)
3116 if ((++cache->iso_n) > NP)
3117 ERRMSG("Too many data points!");
3118
3119 /* Check number of points... */
3120 if (cache->iso_n < 1)
3121 ERRMSG("Could not read any data!");
3122
3123 /* Close file... */
3124 fclose(in);
3125
3126 /* Update of cache data on device... */
3127 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
3128 }
3129}
3130
3131/*****************************************************************************/
3132
3134 const ctl_t *ctl,
3135 const cache_t *cache,
3136 met_t *met0,
3137 met_t *met1,
3138 atm_t *atm) {
3139
3140 /* Set timer... */
3141 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3142
3143 /* Loop over particles... */
3144 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
3145
3146 /* Init... */
3147 double t;
3149
3150 /* Restore pressure... */
3151 if (ctl->isosurf == 1)
3152 atm->p[ip] = cache->iso_var[ip];
3153
3154 /* Restore density... */
3155 else if (ctl->isosurf == 2) {
3156 INTPOL_3D(t, 1);
3157 atm->p[ip] = cache->iso_var[ip] * t;
3158 }
3159
3160 /* Restore potential temperature... */
3161 else if (ctl->isosurf == 3) {
3162 INTPOL_3D(t, 1);
3163 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3164 }
3165
3166 /* Interpolate pressure... */
3167 else if (ctl->isosurf == 4) {
3168 if (atm->time[ip] <= cache->iso_ts[0])
3169 atm->p[ip] = cache->iso_ps[0];
3170 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3171 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3172 else {
3173 int idx = locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3174 atm->p[ip] = LIN(cache->iso_ts[idx], cache->iso_ps[idx],
3175 cache->iso_ts[idx + 1], cache->iso_ps[idx + 1],
3176 atm->time[ip]);
3177 }
3178 }
3179 }
3180}
3181
3182/*****************************************************************************/
3183
3184#ifdef KPP
3185void module_kpp_chem(
3186 ctl_t *ctl,
3187 cache_t *cache,
3188 clim_t *clim,
3189 met_t *met0,
3190 met_t *met1,
3191 atm_t *atm) {
3192
3193 /* Set timer... */
3194 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS", NVTX_GPU);
3195
3196 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
3197 double rtol[1] = { 1.0e-3 };
3198 double atol[1] = { 1.0 };
3199
3200 /* Loop over particles... */
3201#ifdef _OPENACC
3202#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
3203#endif
3204 PARTICLE_LOOP(0, atm->np, 1,
3205 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
3206
3207 /* Initialize... */
3208 double var[nvar], fix[nfix], rconst[nreact];
3209 for (int i = 0; i < nvar; i++)
3210 var[i] = 0.0;
3211 for (int i = 0; i < nfix; i++)
3212 fix[i] = 0.0;
3213 for (int i = 0; i < nreact; i++)
3214 rconst[i] = 0.0;
3215 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
3216
3217 /* Integrate... */
3218 double rpar[20];
3219 int ipar[20];
3220 for (int i = 0; i < 20; i++) {
3221 ipar[i] = 0;
3222 rpar[i] = 0.0;
3223 }
3224 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) */
3225 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
3226 ipar[3] = 4; /* choice of the method:Rodas3 */
3227 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
3228 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
3229
3230 /* Save results.. */
3231 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
3232 }
3233}
3234#endif
3235
3236/*****************************************************************************/
3237
3239 const ctl_t *ctl,
3240 const cache_t *cache,
3241 const clim_t *clim,
3242 met_t *met0,
3243 met_t *met1,
3244 atm_t *atm) {
3245
3246 /* Set timer... */
3247 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
3248
3249 /* Check quantity flags... */
3250 if (ctl->qnt_tsts >= 0)
3251 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3252 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3253
3254 /* Loop over particles... */
3255 PARTICLE_LOOP(0, atm->np, 0,
3256 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3257
3258 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb, cl,
3259 plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot, o3, lwc,
3260 rwc, iwc, swc, cc, z, zt;
3261
3262 /* Interpolate meteo data... */
3264 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3265
3266 /* Set quantities... */
3267 SET_ATM(qnt_ps, ps);
3268 SET_ATM(qnt_ts, ts);
3269 SET_ATM(qnt_zs, zs);
3270 SET_ATM(qnt_us, us);
3271 SET_ATM(qnt_vs, vs);
3272 SET_ATM(qnt_ess, ess);
3273 SET_ATM(qnt_nss, nss);
3274 SET_ATM(qnt_shf, shf);
3275 SET_ATM(qnt_lsm, lsm);
3276 SET_ATM(qnt_sst, sst);
3277 SET_ATM(qnt_pbl, pbl);
3278 SET_ATM(qnt_pt, pt);
3279 SET_ATM(qnt_tt, tt);
3280 SET_ATM(qnt_zt, zt);
3281 SET_ATM(qnt_h2ot, h2ot);
3282 SET_ATM(qnt_zg, z);
3283 SET_ATM(qnt_p, atm->p[ip]);
3284 SET_ATM(qnt_t, t);
3285 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3286 SET_ATM(qnt_u, u);
3287 SET_ATM(qnt_v, v);
3288 SET_ATM(qnt_w, w);
3289 SET_ATM(qnt_h2o, h2o);
3290 SET_ATM(qnt_o3, o3);
3291 SET_ATM(qnt_lwc, lwc);
3292 SET_ATM(qnt_rwc, rwc);
3293 SET_ATM(qnt_iwc, iwc);
3294 SET_ATM(qnt_swc, swc);
3295 SET_ATM(qnt_cc, cc);
3296 SET_ATM(qnt_pct, pct);
3297 SET_ATM(qnt_pcb, pcb);
3298 SET_ATM(qnt_cl, cl);
3299 SET_ATM(qnt_plcl, plcl);
3300 SET_ATM(qnt_plfc, plfc);
3301 SET_ATM(qnt_pel, pel);
3302 SET_ATM(qnt_cape, cape);
3303 SET_ATM(qnt_cin, cin);
3304 SET_ATM(qnt_o3c, o3c);
3305 SET_ATM(qnt_hno3,
3306 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3307 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3308 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3309 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3310 atm->lat[ip], atm->p[ip]));
3311 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3312 atm->lat[ip], atm->p[ip]));
3313 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3314 atm->lat[ip], atm->p[ip]));
3315 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3316 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3317 SET_ATM(qnt_psat, PSAT(t));
3318 SET_ATM(qnt_psice, PSICE(t));
3319 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3320 SET_ATM(qnt_sh, SH(h2o));
3321 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3322 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3323 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3324 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3325 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3326 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3327 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3328 SET_ATM(qnt_pv, pv);
3329 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3330 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3331 SET_ATM(qnt_tnat,
3332 nat_temperature(atm->p[ip], h2o,
3333 clim_zm(&clim->hno3, atm->time[ip],
3334 atm->lat[ip], atm->p[ip])));
3335 SET_ATM(qnt_tsts,
3336 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3337 }
3338}
3339
3340/*****************************************************************************/
3341
3343 const ctl_t *ctl,
3344 const clim_t *clim,
3345 atm_t *atm,
3346 const double t) {
3347
3348 /* Set timer... */
3349 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
3350
3351 /* Allocate... */
3352 const int np = atm->np;
3353 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3354 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3355 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3356
3357 /* Set grid box size... */
3358 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3359 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3360 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3361
3362 /* Set time interval... */
3363 const double t0 = t - 0.5 * ctl->dt_mod;
3364 const double t1 = t + 0.5 * ctl->dt_mod;
3365
3366 /* Get indices... */
3367#ifdef _OPENACC
3368#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3369#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3370#pragma acc parallel loop independent gang vector
3371#else
3372#pragma omp parallel for default(shared)
3373#endif
3374 for (int ip = 0; ip < np; ip++) {
3375 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3376 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3377 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3378 if (atm->time[ip] < t0 || atm->time[ip] > t1
3379 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3380 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3381 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3382 izs[ip] = -1;
3383 }
3384
3385 /* Calculate interparcel mixing... */
3386 if (ctl->qnt_m >= 0)
3387 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_m);
3388 if (ctl->qnt_vmr >= 0)
3389 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_vmr);
3390 if (ctl->qnt_Ch2o >= 0)
3391 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o);
3392 if (ctl->qnt_Co3 >= 0)
3393 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3);
3394 if (ctl->qnt_Cco >= 0)
3395 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cco);
3396 if (ctl->qnt_Coh >= 0)
3397 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Coh);
3398 if (ctl->qnt_Ch >= 0)
3399 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch);
3400 if (ctl->qnt_Cho2 >= 0)
3401 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cho2);
3402 if (ctl->qnt_Ch2o2 >= 0)
3403 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o2);
3404 if (ctl->qnt_Co1d >= 0)
3405 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co1d);
3406 if (ctl->qnt_Co3p >= 0)
3407 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3p);
3408 if (ctl->qnt_Cccl4 >= 0)
3409 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl4);
3410 if (ctl->qnt_Cccl3f >= 0)
3411 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl3f);
3412 if (ctl->qnt_Cccl2f2 >= 0)
3413 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl2f2);
3414 if (ctl->qnt_Cn2o >= 0)
3415 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cn2o);
3416 if (ctl->qnt_Csf6 >= 0)
3417 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Csf6);
3418 if (ctl->qnt_aoa >= 0)
3419 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_aoa);
3420
3421 /* Free... */
3422#ifdef _OPENACC
3423#pragma acc exit data delete(ixs,iys,izs)
3424#endif
3425 free(ixs);
3426 free(iys);
3427 free(izs);
3428}
3429
3430/*****************************************************************************/
3431
3433 const ctl_t *ctl,
3434 const clim_t *clim,
3435 atm_t *atm,
3436 const int *ixs,
3437 const int *iys,
3438 const int *izs,
3439 const int qnt_idx) {
3440
3441 /* Allocate... */
3442 const int np = atm->np;
3443 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
3444 double *restrict const cmean =
3445 (double *) malloc((size_t) ngrid * sizeof(double));
3446 int *restrict const count = (int *) malloc((size_t) ngrid * sizeof(int));
3447
3448 /* Init... */
3449#ifdef _OPENACC
3450#pragma acc enter data create(cmean[0:ngrid],count[0:ngrid])
3451#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
3452#pragma acc parallel loop independent gang vector
3453#else
3454#ifdef __NVCOMPILER
3455#pragma novector
3456#endif
3457#pragma omp parallel for
3458#endif
3459 for (int i = 0; i < ngrid; i++) {
3460 count[i] = 0;
3461 cmean[i] = 0;
3462 }
3463
3464 /* Loop over particles... */
3465#ifdef _OPENACC
3466#pragma acc parallel loop independent gang vector
3467#endif
3468 for (int ip = 0; ip < np; ip++)
3469 if (izs[ip] >= 0) {
3470 int idx = ARRAY_3D
3471 (ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz);
3472#ifdef _OPENACC
3473#pragma acc atomic update
3474#endif
3475 cmean[idx] += atm->q[qnt_idx][ip];
3476#ifdef _OPENACC
3477#pragma acc atomic update
3478#endif
3479 count[idx]++;
3480 }
3481#ifdef _OPENACC
3482#pragma acc parallel loop independent gang vector
3483#else
3484#ifdef __NVCOMPILER
3485#pragma novector
3486#endif
3487#pragma omp parallel for
3488#endif
3489 for (int i = 0; i < ngrid; i++)
3490 if (count[i] > 0)
3491 cmean[i] /= count[i];
3492
3493 /* Calculate interparcel mixing... */
3494#ifdef _OPENACC
3495#pragma acc parallel loop independent gang vector
3496#else
3497#pragma omp parallel for
3498#endif
3499 for (int ip = 0; ip < np; ip++)
3500 if (izs[ip] >= 0) {
3501
3502 /* Set mixing parameter... */
3503 double mixparam = 1.0;
3504 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
3505 double w = tropo_weight(clim, atm, ip);
3506 mixparam = w * ctl->mixing_trop + (1 - w) * ctl->mixing_strat;
3507 }
3508
3509 /* Adjust quantity... */
3510 atm->q[qnt_idx][ip] +=
3511 (cmean
3512 [ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz)]
3513 - atm->q[qnt_idx][ip]) * mixparam;
3514 }
3515
3516 /* Free... */
3517#ifdef _OPENACC
3518#pragma acc exit data delete(cmean,count)
3519#endif
3520 free(cmean);
3521 free(count);
3522}
3523
3524/*****************************************************************************/
3525
3527 const ctl_t *ctl,
3528 const cache_t *cache,
3529 const clim_t *clim,
3530 met_t *met0,
3531 met_t *met1,
3532 atm_t *atm) {
3533
3534 /* Set timer... */
3535 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS", NVTX_GPU);
3536
3537 /* Check quantity flags... */
3538 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3539 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3540
3541 /* Parameter of SO2 correction... */
3542 const double a = 4.71572206e-08;
3543 const double b = -8.28782867e-01;
3544 const double low = pow(1. / a, 1. / b);
3545
3546 /* Loop over particles... */
3547 PARTICLE_LOOP(0, atm->np, 1,
3548 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3549
3550 /* Get temperature... */
3551 double t;
3553 INTPOL_3D(t, 1);
3554
3555 /* Calculate molecular density... */
3556 const double M = MOLEC_DENS(atm->p[ip], t);
3557
3558 /* Use constant reaction rate... */
3559 double k = NAN;
3560 if (ctl->oh_chem_reaction == 1)
3561 k = ctl->oh_chem[0];
3562
3563 /* Calculate bimolecular reaction rate... */
3564 else if (ctl->oh_chem_reaction == 2)
3565 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
3566
3567 /* Calculate termolecular reaction rate... */
3568 if (ctl->oh_chem_reaction == 3) {
3569
3570 /* Calculate rate coefficient for X + OH + M -> XOH + M
3571 (JPL Publication 19-05) ... */
3572 const double k0 =
3573 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
3574 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
3575 const double ki =
3576 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
3577 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
3578 const double c = log10(k0 * M / ki);
3579 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
3580 }
3581
3582 /* Correction factor for high SO2 concentration
3583 (if qnt_Cx is defined, the correction is switched on)... */
3584 double cor = 1;
3585 if (ctl->qnt_Cx >= 0)
3586 cor =
3587 atm->q[ctl->qnt_Cx][ip] >
3588 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3589
3590 /* Calculate exponential decay... */
3591 const double rate_coef =
3592 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
3593 atm->lat[ip], atm->p[ip]) * M * cor;
3594 const double aux = exp(-cache->dt[ip] * rate_coef);
3595 if (ctl->qnt_m >= 0) {
3596 if (ctl->qnt_mloss_oh >= 0)
3597 atm->q[ctl->qnt_mloss_oh][ip]
3598 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3599 atm->q[ctl->qnt_m][ip] *= aux;
3600 if (ctl->qnt_loss_rate >= 0)
3601 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3602 }
3603 if (ctl->qnt_vmr >= 0)
3604 atm->q[ctl->qnt_vmr][ip] *= aux;
3605 }
3606}
3607
3608/*****************************************************************************/
3609
3611 const cache_t *cache,
3612 met_t *met0,
3613 met_t *met1,
3614 atm_t *atm) {
3615
3616 /* Set timer... */
3617 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
3618
3619 /* Loop over particles... */
3620 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
3621
3622 /* Init... */
3623 double ps;
3625
3626 /* Calculate modulo... */
3627 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
3628 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
3629
3630 /* Check latitude... */
3631 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
3632 if (atm->lat[ip] > 90) {
3633 atm->lat[ip] = 180 - atm->lat[ip];
3634 atm->lon[ip] += 180;
3635 }
3636 if (atm->lat[ip] < -90) {
3637 atm->lat[ip] = -180 - atm->lat[ip];
3638 atm->lon[ip] += 180;
3639 }
3640 }
3641
3642 /* Check longitude... */
3643 while (atm->lon[ip] < -180)
3644 atm->lon[ip] += 360;
3645 while (atm->lon[ip] >= 180)
3646 atm->lon[ip] -= 360;
3647
3648 /* Check pressure... */
3649 if (atm->p[ip] < met0->p[met0->np - 1]) {
3650 atm->p[ip] = met0->p[met0->np - 1];
3651 } else if (atm->p[ip] > 300.) {
3652 INTPOL_2D(ps, 1);
3653 if (atm->p[ip] > ps)
3654 atm->p[ip] = ps;
3655 }
3656 }
3657}
3658
3659/*****************************************************************************/
3660
3662 const int ntask) {
3663
3664 /* Initialize GSL random number generators... */
3665 gsl_rng_env_setup();
3666 if (omp_get_max_threads() > NTHREADS)
3667 ERRMSG("Too many threads!");
3668 for (int i = 0; i < NTHREADS; i++) {
3669 rng[i] = gsl_rng_alloc(gsl_rng_default);
3670 gsl_rng_set(rng[i], gsl_rng_default_seed
3671 + (long unsigned) (ntask * NTHREADS + i));
3672 }
3673
3674 /* Initialize cuRAND random number generators... */
3675#ifdef CURAND
3676 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
3677 CURAND_STATUS_SUCCESS)
3678 ERRMSG("Cannot create random number generator!");
3679 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
3680 CURAND_STATUS_SUCCESS)
3681 ERRMSG("Cannot set seed for random number generator!");
3682 if (curandSetStream
3683 (rng_curand,
3684 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
3685 CURAND_STATUS_SUCCESS)
3686 ERRMSG("Cannot set stream for random number generator!");
3687#endif
3688}
3689
3690/*****************************************************************************/
3691
3693 const ctl_t *ctl,
3694 double *rs,
3695 const size_t n,
3696 const int method) {
3697
3698 /* Use GSL random number generators... */
3699 if (ctl->rng_type == 0) {
3700
3701 /* Uniform distribution... */
3702 if (method == 0) {
3703#pragma omp parallel for default(shared)
3704 for (size_t i = 0; i < n; ++i)
3705 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
3706 }
3707
3708 /* Normal distribution... */
3709 else if (method == 1) {
3710#pragma omp parallel for default(shared)
3711 for (size_t i = 0; i < n; ++i)
3712 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
3713 }
3714
3715 /* Update of random numbers on device... */
3716#ifdef _OPENACC
3717 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
3718#pragma acc update device(rs[:n])
3719#endif
3720 }
3721
3722 /* Use Squares random number generator (Widynski, 2022)... */
3723 else if (ctl->rng_type == 1) {
3724
3725 /* Set key (don't change this!)... */
3726 const uint64_t key = 0xc8e4fd154ce32f6d;
3727
3728 /* Uniform distribution... */
3729#ifdef _OPENACC
3730#pragma acc data present(rs)
3731#pragma acc parallel loop independent gang vector
3732#else
3733#pragma omp parallel for default(shared)
3734#endif
3735 for (size_t i = 0; i < n + 1; ++i) {
3736 uint64_t r, t, x, y, z;
3737 y = x = (rng_ctr + i) * key;
3738 z = y + key;
3739 x = x * x + y;
3740 x = (x >> 32) | (x << 32);
3741 x = x * x + z;
3742 x = (x >> 32) | (x << 32);
3743 x = x * x + y;
3744 x = (x >> 32) | (x << 32);
3745 t = x = x * x + z;
3746 x = (x >> 32) | (x << 32);
3747 r = t ^ ((x * x + y) >> 32);
3748 rs[i] = (double) r / (double) UINT64_MAX;
3749 }
3750 rng_ctr += n + 1;
3751
3752 /* Normal distribution... */
3753 if (method == 1) {
3754#ifdef _OPENACC
3755#pragma acc parallel loop independent gang vector
3756#else
3757#pragma omp parallel for default(shared)
3758#endif
3759 for (size_t i = 0; i < n; i += 2) {
3760 const double r = sqrt(-2.0 * log(rs[i]));
3761 const double phi = 2.0 * M_PI * rs[i + 1];
3762 rs[i] = r * cosf((float) phi);
3763 rs[i + 1] = r * sinf((float) phi);
3764 }
3765 }
3766 }
3767
3768 /* Use cuRAND random number generators... */
3769 else if (ctl->rng_type == 2) {
3770#ifdef CURAND
3771#pragma acc host_data use_device(rs)
3772 {
3773
3774 /* Uniform distribution... */
3775 if (method == 0) {
3776 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
3777 CURAND_STATUS_SUCCESS)
3778 ERRMSG("Cannot create random numbers!");
3779 }
3780
3781 /* Normal distribution... */
3782 else if (method == 1) {
3783 if (curandGenerateNormalDouble
3784 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
3785 1.0) != CURAND_STATUS_SUCCESS)
3786 ERRMSG("Cannot create random numbers!");
3787 }
3788 }
3789#else
3790 ERRMSG("MPTRAC was compiled without cuRAND!");
3791#endif
3792 }
3793}
3794
3795/*****************************************************************************/
3796
3798 const ctl_t *ctl,
3799 const cache_t *cache,
3800 met_t *met0,
3801 met_t *met1,
3802 atm_t *atm) {
3803
3804 /* Set timer... */
3805 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
3806
3807 /* Loop over particles... */
3808 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3809
3810 /* Get temperature... */
3811 double t;
3813 INTPOL_3D(t, 1);
3814
3815 /* Sedimentation velocity... */
3816 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3817 atm->q[ctl->qnt_rhop][ip]);
3818
3819 /* Calculate pressure change... */
3820 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
3821 }
3822}
3823
3824/*****************************************************************************/
3825
3827 const ctl_t *ctl,
3828 met_t *met0,
3829 atm_t *atm) {
3830
3831 /* Set timer... */
3832 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
3833
3834 /* Allocate... */
3835 const int np = atm->np;
3836 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
3837 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
3838
3839#ifdef _OPENACC
3840#pragma acc enter data create(a[0:np],p[0:np])
3841#pragma acc data present(ctl,met0,atm,a,p)
3842#endif
3843
3844 /* Get box index... */
3845#ifdef _OPENACC
3846#pragma acc parallel loop independent gang vector
3847#else
3848#pragma omp parallel for default(shared)
3849#endif
3850 for (int ip = 0; ip < np; ip++) {
3851 a[ip] =
3852 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
3853 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
3854 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
3855 p[ip] = ip;
3856 }
3857
3858 /* Sorting... */
3859#ifdef _OPENACC
3860#pragma acc host_data use_device(a,p)
3861#endif
3862#ifdef THRUST
3863 thrustSortWrapper(a, np, p);
3864#else
3865 ERRMSG("MPTRAC was compiled without Thrust library!");
3866#endif
3867
3868 /* Sort data... */
3869 module_sort_help(atm->time, p, np);
3870 module_sort_help(atm->p, p, np);
3871 module_sort_help(atm->lon, p, np);
3872 module_sort_help(atm->lat, p, np);
3873 for (int iq = 0; iq < ctl->nq; iq++)
3874 module_sort_help(atm->q[iq], p, np);
3875
3876 /* Free... */
3877#ifdef _OPENACC
3878#pragma acc exit data delete(a,p)
3879#endif
3880 free(a);
3881 free(p);
3882}
3883
3884/*****************************************************************************/
3885
3887 double *a,
3888 const int *p,
3889 const int np) {
3890
3891 /* Allocate... */
3892 double *restrict const help =
3893 (double *) malloc((size_t) np * sizeof(double));
3894
3895 /* Reordering of array... */
3896#ifdef _OPENACC
3897#pragma acc enter data create(help[0:np])
3898#pragma acc data present(a,p,help)
3899#pragma acc parallel loop independent gang vector
3900#else
3901#pragma omp parallel for default(shared)
3902#endif
3903 for (int ip = 0; ip < np; ip++)
3904 help[ip] = a[p[ip]];
3905#ifdef _OPENACC
3906#pragma acc parallel loop independent gang vector
3907#else
3908#pragma omp parallel for default(shared)
3909#endif
3910 for (int ip = 0; ip < np; ip++)
3911 a[ip] = help[ip];
3912
3913 /* Free... */
3914#ifdef _OPENACC
3915#pragma acc exit data delete(help)
3916#endif
3917 free(help);
3918}
3919
3920/*****************************************************************************/
3921
3923 const ctl_t *ctl,
3924 cache_t *cache,
3925 met_t *met0,
3926 atm_t *atm,
3927 const double t) {
3928
3929 /* Set timer... */
3930 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
3931
3932 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
3933 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
3934
3935 const int local =
3936 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
3937
3938 /* Loop over particles... */
3939 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
3940
3941 /* Set time step for each air parcel... */
3942 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
3943 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
3944 && ctl->direction * (atm->time[ip] - t) < 0))
3945 cache->dt[ip] = t - atm->time[ip];
3946 else
3947 cache->dt[ip] = 0.0;
3948
3949 /* Check horizontal boundaries of local meteo data... */
3950 if (local && (atm->lon[ip] <= met0->lon[0]
3951 || atm->lon[ip] >= met0->lon[met0->nx - 1]
3952 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
3953 cache->dt[ip] = 0.0;
3954 }
3955}
3956
3957/*****************************************************************************/
3958
3960 ctl_t *ctl,
3961 const atm_t *atm) {
3962
3963 /* Set timer... */
3964 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS", NVTX_GPU);
3965
3966 /* Set start time... */
3967 if (ctl->direction == 1) {
3968 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3969 if (ctl->t_stop > 1e99)
3970 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3971 } else {
3972 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3973 if (ctl->t_stop > 1e99)
3974 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3975 }
3976
3977 /* Check time interval... */
3978 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
3979 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
3980
3981 /* Round start time... */
3982 if (ctl->direction == 1)
3983 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
3984 else
3985 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
3986}
3987
3988/*****************************************************************************/
3989
3991 const ctl_t *ctl,
3992 const cache_t *cache,
3993 const clim_t *clim,
3994 met_t *met0,
3995 met_t *met1,
3996 atm_t *atm) {
3997
3998 /* Set timer... */
3999 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS", NVTX_GPU);
4000
4001 /* Loop over particles... */
4002 PARTICLE_LOOP(0, atm->np, 1,
4003 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4004
4005 /* Get temperature... */
4006 double t;
4008 INTPOL_3D(t, 1);
4009
4010 /* Get molecular density... */
4011 const double M = MOLEC_DENS(atm->p[ip], t);
4012
4013 /* Get total column ozone... */
4014 double o3c;
4015 INTPOL_2D(o3c, 1);
4016
4017 /* Get solar zenith angle... */
4018 const double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
4019
4020 /* Get O(1D) volume mixing ratio... */
4021 const double o1d =
4022 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4023
4024 /* Reactions for CFC-10... */
4025 if (ctl->qnt_Cccl4 >= 0) {
4026 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4027 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4028 atm->p[ip], sza, o3c);
4029 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4030 }
4031
4032 /* Reactions for CFC-11... */
4033 if (ctl->qnt_Cccl3f >= 0) {
4034 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4035 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4036 atm->p[ip], sza, o3c);
4037 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4038 }
4039
4040 /* Reactions for CFC-12... */
4041 if (ctl->qnt_Cccl2f2 >= 0) {
4042 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4043 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4044 atm->p[ip], sza, o3c);
4045 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4046 }
4047
4048 /* Reactions for N2O... */
4049 if (ctl->qnt_Cn2o >= 0) {
4050 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4051 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4052 atm->p[ip], sza, o3c);
4053 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4054 }
4055 }
4056}
4057
4058/*****************************************************************************/
4059
4061 const ctl_t *ctl,
4062 const cache_t *cache,
4063 met_t *met0,
4064 met_t *met1,
4065 atm_t *atm) {
4066
4067 /* Set timer... */
4068 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS", NVTX_GPU);
4069
4070 /* Check quantity flags... */
4071 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4072 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4073
4074 /* Loop over particles... */
4075 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4076
4077 /* Check whether particle is below cloud top... */
4078 double pct;
4080 INTPOL_2D(pct, 1);
4081 if (!isfinite(pct) || atm->p[ip] <= pct)
4082 continue;
4083
4084 /* Get cloud bottom pressure... */
4085 double pcb;
4086 INTPOL_2D(pcb, 0);
4087
4088 /* Estimate precipitation rate (Pisso et al., 2019)... */
4089 double cl;
4090 INTPOL_2D(cl, 0);
4091 const double Is =
4092 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4093 if (Is < 0.01)
4094 continue;
4095
4096 /* Check whether particle is inside or below cloud... */
4097 double lwc, rwc, iwc, swc;
4098 INTPOL_3D(lwc, 1);
4099 INTPOL_3D(rwc, 0);
4100 INTPOL_3D(iwc, 0);
4101 INTPOL_3D(swc, 0);
4102 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4103
4104 /* Get temperature... */
4105 double t;
4106 INTPOL_3D(t, 0);
4107
4108 /* Calculate in-cloud scavenging coefficient... */
4109 double lambda = 0;
4110 if (inside) {
4111
4112 /* Calculate retention factor... */
4113 double eta;
4114 if (t > 273.15)
4115 eta = 1;
4116 else if (t <= 238.15)
4117 eta = ctl->wet_depo_ic_ret_ratio;
4118 else
4119 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4120
4121 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4122 if (ctl->wet_depo_ic_a > 0)
4123 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4124
4125 /* Use Henry's law for gases... */
4126 else if (ctl->wet_depo_ic_h[0] > 0) {
4127
4128 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4129 double h = ctl->wet_depo_ic_h[0]
4130 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4131
4132 /* Use effective Henry's constant for SO2
4133 (Berglen, 2004; Simpson, 2012)... */
4134 if (ctl->wet_depo_so2_ph > 0) {
4135 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
4136 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4137 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4138 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
4139 }
4140
4141 /* Estimate depth of cloud layer... */
4142 const double dz = 1e3 * (Z(pct) - Z(pcb));
4143
4144 /* Calculate scavenging coefficient... */
4145 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4146 }
4147 }
4148
4149 /* Calculate below-cloud scavenging coefficient... */
4150 else {
4151
4152 /* Calculate retention factor... */
4153 double eta;
4154 if (t > 270)
4155 eta = 1;
4156 else
4157 eta = ctl->wet_depo_bc_ret_ratio;
4158
4159 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4160 if (ctl->wet_depo_bc_a > 0)
4161 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4162
4163 /* Use Henry's law for gases... */
4164 else if (ctl->wet_depo_bc_h[0] > 0) {
4165
4166 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4167 const double h = ctl->wet_depo_bc_h[0]
4168 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4169
4170 /* Estimate depth of cloud layer... */
4171 const double dz = 1e3 * (Z(pct) - Z(pcb));
4172
4173 /* Calculate scavenging coefficient... */
4174 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4175 }
4176 }
4177
4178 /* Calculate exponential decay of mass... */
4179 const double aux = exp(-cache->dt[ip] * lambda);
4180 if (ctl->qnt_m >= 0) {
4181 if (ctl->qnt_mloss_wet >= 0)
4182 atm->q[ctl->qnt_mloss_wet][ip]
4183 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4184 atm->q[ctl->qnt_m][ip] *= aux;
4185 if (ctl->qnt_loss_rate >= 0)
4186 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4187 }
4188 if (ctl->qnt_vmr >= 0)
4189 atm->q[ctl->qnt_vmr][ip] *= aux;
4190 }
4191}
4192
4193/*****************************************************************************/
4194
4196 ctl_t **ctl,
4197 cache_t **cache,
4198 clim_t **clim,
4199 met_t **met0,
4200 met_t **met1,
4201 atm_t **atm) {
4202
4203 /* Initialize GPU... */
4204#ifdef _OPENACC
4205 SELECT_TIMER("ACC_INIT", "INIT", NVTX_GPU);
4206 int rank = 0;
4207#ifdef MPI
4208 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
4209#endif
4210 if (acc_get_num_devices(acc_device_nvidia) <= 0)
4211 ERRMSG("Not running on a GPU device!");
4212 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
4213 acc_device_nvidia);
4214 acc_device_t device_type = acc_get_device_type();
4215 acc_init(device_type);
4216#endif
4217
4218 /* Allocate... */
4219 SELECT_TIMER("ALLOC", "MEMORY", NVTX_CPU);
4220 ALLOC(*ctl, ctl_t, 1);
4221 ALLOC(*cache, cache_t, 1);
4222 ALLOC(*clim, clim_t, 1);
4223 ALLOC(*met0, met_t, 1);
4224 ALLOC(*met1, met_t, 1);
4225 ALLOC(*atm, atm_t, 1);
4226
4227 /* Create data region on GPU... */
4228#ifdef _OPENACC
4229 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY", NVTX_GPU);
4230 ctl_t *ctlup = *ctl;
4231 cache_t *cacheup = *cache;
4232 clim_t *climup = *clim;
4233 met_t *met0up = *met0;
4234 met_t *met1up = *met1;
4235 atm_t *atmup = *atm;
4236#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
4237#endif
4238}
4239
4240/*****************************************************************************/
4241
4243 ctl_t *ctl,
4244 cache_t *cache,
4245 clim_t *clim,
4246 met_t *met0,
4247 met_t *met1,
4248 atm_t *atm) {
4249
4250 /* Delete data region on GPU... */
4251#ifdef _OPENACC
4252 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY", NVTX_GPU);
4253#pragma acc exit data delete (ctl,cache,clim,met0,met1,atm)
4254#endif
4255
4256 /* Free... */
4257 SELECT_TIMER("FREE", "MEMORY", NVTX_CPU);
4258 free(atm);
4259 free(ctl);
4260 free(cache);
4261 free(clim);
4262 free(met0);
4263 free(met1);
4264}
4265
4266/*****************************************************************************/
4267
4269 ctl_t *ctl,
4270 clim_t *clim,
4271 const double t,
4272 met_t **met0,
4273 met_t **met1) {
4274
4275 static int init;
4276
4277 met_t *mets;
4278
4279 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
4280
4281 /* Set timer... */
4282 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4283
4284 /* Init... */
4285 if (t == ctl->t_start || !init) {
4286 init = 1;
4287
4288 /* Read meteo data... */
4289 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
4290 ctl->metbase, ctl->dt_met, filename);
4291 if (!mptrac_read_met(filename, ctl, clim, *met0))
4292 ERRMSG("Cannot open file!");
4293
4294 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
4295 ctl->metbase, ctl->dt_met, filename);
4296 if (!mptrac_read_met(filename, ctl, clim, *met1))
4297 ERRMSG("Cannot open file!");
4298
4299 /* Update GPU... */
4300 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
4301 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4302
4303 /* Caching... */
4304 if (ctl->met_cache && t != ctl->t_stop) {
4305 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
4306 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
4307 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4308 LOG(1, "Caching: %s", cachefile);
4309 if (system(cmd) != 0)
4310 WARN("Caching command failed!");
4311 }
4312 }
4313
4314 /* Read new data for forward trajectories... */
4315 if (t > (*met1)->time) {
4316
4317 /* Pointer swap... */
4318 mets = *met1;
4319 *met1 = *met0;
4320 *met0 = mets;
4321
4322 /* Read new meteo data... */
4323 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
4324 if (!mptrac_read_met(filename, ctl, clim, *met1))
4325 ERRMSG("Cannot open file!");
4326
4327 /* Update GPU... */
4328 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
4329 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4330
4331 /* Caching... */
4332 if (ctl->met_cache && t != ctl->t_stop) {
4333 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
4334 cachefile);
4335 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4336 LOG(1, "Caching: %s", cachefile);
4337 if (system(cmd) != 0)
4338 WARN("Caching command failed!");
4339 }
4340 }
4341
4342 /* Read new data for backward trajectories... */
4343 if (t < (*met0)->time) {
4344
4345 /* Pointer swap... */
4346 mets = *met1;
4347 *met1 = *met0;
4348 *met0 = mets;
4349
4350 /* Read new meteo data... */
4351 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
4352 if (!mptrac_read_met(filename, ctl, clim, *met0))
4353 ERRMSG("Cannot open file!");
4354
4355 /* Update GPU... */
4356 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
4357 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4358
4359 /* Caching... */
4360 if (ctl->met_cache && t != ctl->t_stop) {
4361 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
4362 cachefile);
4363 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4364 LOG(1, "Caching: %s", cachefile);
4365 if (system(cmd) != 0)
4366 WARN("Caching command failed!");
4367 }
4368 }
4369
4370 /* Check that grids are consistent... */
4371 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
4372 if ((*met0)->nx != (*met1)->nx
4373 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
4374 ERRMSG("Meteo grid dimensions do not match!");
4375 for (int ix = 0; ix < (*met0)->nx; ix++)
4376 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
4377 ERRMSG("Meteo grid longitudes do not match!");
4378 for (int iy = 0; iy < (*met0)->ny; iy++)
4379 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
4380 ERRMSG("Meteo grid latitudes do not match!");
4381 for (int ip = 0; ip < (*met0)->np; ip++)
4382 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
4383 ERRMSG("Meteo grid pressure levels do not match!");
4384 }
4385}
4386
4387/*****************************************************************************/
4388
4390 ctl_t *ctl,
4391 cache_t *cache,
4392 clim_t *clim,
4393 atm_t *atm,
4394 const int ntask) {
4395
4396 /* Initialize timesteps... */
4397 module_timesteps_init(ctl, atm);
4398
4399 /* Initialize random number generator... */
4400 module_rng_init(ntask);
4401
4402 /* Update GPU memory... */
4403 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
4404}
4405
4406/*****************************************************************************/
4407
4409 const char *filename,
4410 const ctl_t *ctl,
4411 atm_t *atm) {
4412
4413 int result;
4414
4415 /* Set timer... */
4416 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
4417
4418 /* Init... */
4419 atm->np = 0;
4420
4421 /* Write info... */
4422 LOG(1, "Read atmospheric data: %s", filename);
4423
4424 /* Read ASCII data... */
4425 if (ctl->atm_type == 0)
4426 result = read_atm_asc(filename, ctl, atm);
4427
4428 /* Read binary data... */
4429 else if (ctl->atm_type == 1)
4430 result = read_atm_bin(filename, ctl, atm);
4431
4432 /* Read netCDF data... */
4433 else if (ctl->atm_type == 2)
4434 result = read_atm_nc(filename, ctl, atm);
4435
4436 /* Read CLaMS data... */
4437 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
4438 result = read_atm_clams(filename, ctl, atm);
4439
4440 /* Error... */
4441 else
4442 ERRMSG("Atmospheric data type not supported!");
4443
4444 /* Check result... */
4445 if (result != 1)
4446 return 0;
4447
4448 /* Check number of air parcels... */
4449 if (atm->np < 1)
4450 ERRMSG("Can not read any data!");
4451
4452 /* Write info... */
4453 double mini, maxi;
4454 LOG(2, "Number of particles: %d", atm->np);
4455 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
4456 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
4457 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
4458 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
4459 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
4460 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
4461 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
4462 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
4463 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
4464 for (int iq = 0; iq < ctl->nq; iq++) {
4465 char msg[5 * LEN];
4466 sprintf(msg, "Quantity %s range: %s ... %s %s",
4467 ctl->qnt_name[iq], ctl->qnt_format[iq],
4468 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
4469 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
4470 LOG(2, msg, mini, maxi);
4471 }
4472
4473 /* Return success... */
4474 return 1;
4475}
4476
4477/*****************************************************************************/
4478
4480 const ctl_t *ctl,
4481 clim_t *clim) {
4482
4483 /* Set timer... */
4484 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
4485
4486 /* Init tropopause climatology... */
4487 clim_tropo_init(clim);
4488
4489 /* Read photolysis rates... */
4490 if (ctl->clim_photo[0] != '-')
4491 read_clim_photo(ctl->clim_photo, &clim->photo);
4492
4493 /* Read HNO3 climatology... */
4494 if (ctl->clim_hno3_filename[0] != '-')
4495 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
4496
4497 /* Read OH climatology... */
4498 if (ctl->clim_oh_filename[0] != '-') {
4499 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
4500 if (ctl->oh_chem_beta > 0)
4501 clim_oh_diurnal_correction(ctl, clim);
4502 }
4503
4504 /* Read H2O2 climatology... */
4505 if (ctl->clim_h2o2_filename[0] != '-')
4506 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
4507
4508 /* Read HO2 climatology... */
4509 if (ctl->clim_ho2_filename[0] != '-')
4510 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
4511
4512 /* Read O(1D) climatology... */
4513 if (ctl->clim_o1d_filename[0] != '-')
4514 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
4515
4516 /* Read CFC-10 time series... */
4517 if (ctl->clim_ccl4_timeseries[0] != '-')
4519
4520 /* Read CFC-11 time series... */
4521 if (ctl->clim_ccl3f_timeseries[0] != '-')
4523
4524 /* Read CFC-12 time series... */
4525 if (ctl->clim_ccl2f2_timeseries[0] != '-')
4527
4528 /* Read N2O time series... */
4529 if (ctl->clim_n2o_timeseries[0] != '-')
4530 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
4531
4532 /* Read SF6 time series... */
4533 if (ctl->clim_sf6_timeseries[0] != '-')
4534 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
4535}
4536
4537/*****************************************************************************/
4538
4540 const char *filename,
4541 int argc,
4542 char *argv[],
4543 ctl_t *ctl) {
4544
4545 /* Set timer... */
4546 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
4547
4548 /* Write info... */
4549 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
4550 "(executable: %s | version: %s | compiled: %s, %s)\n",
4551 argv[0], VERSION, __DATE__, __TIME__);
4552
4553 /* Initialize quantity indices... */
4554 ctl->qnt_idx = -1;
4555 ctl->qnt_ens = -1;
4556 ctl->qnt_stat = -1;
4557 ctl->qnt_m = -1;
4558 ctl->qnt_vmr = -1;
4559 ctl->qnt_rp = -1;
4560 ctl->qnt_rhop = -1;
4561 ctl->qnt_ps = -1;
4562 ctl->qnt_ts = -1;
4563 ctl->qnt_zs = -1;
4564 ctl->qnt_us = -1;
4565 ctl->qnt_vs = -1;
4566 ctl->qnt_ess = -1;
4567 ctl->qnt_nss = -1;
4568 ctl->qnt_shf = -1;
4569 ctl->qnt_lsm = -1;
4570 ctl->qnt_sst = -1;
4571 ctl->qnt_pbl = -1;
4572 ctl->qnt_pt = -1;
4573 ctl->qnt_tt = -1;
4574 ctl->qnt_zt = -1;
4575 ctl->qnt_h2ot = -1;
4576 ctl->qnt_zg = -1;
4577 ctl->qnt_p = -1;
4578 ctl->qnt_t = -1;
4579 ctl->qnt_rho = -1;
4580 ctl->qnt_u = -1;
4581 ctl->qnt_v = -1;
4582 ctl->qnt_w = -1;
4583 ctl->qnt_h2o = -1;
4584 ctl->qnt_o3 = -1;
4585 ctl->qnt_lwc = -1;
4586 ctl->qnt_rwc = -1;
4587 ctl->qnt_iwc = -1;
4588 ctl->qnt_swc = -1;
4589 ctl->qnt_cc = -1;
4590 ctl->qnt_pct = -1;
4591 ctl->qnt_pcb = -1;
4592 ctl->qnt_cl = -1;
4593 ctl->qnt_plcl = -1;
4594 ctl->qnt_plfc = -1;
4595 ctl->qnt_pel = -1;
4596 ctl->qnt_cape = -1;
4597 ctl->qnt_cin = -1;
4598 ctl->qnt_o3c = -1;
4599 ctl->qnt_hno3 = -1;
4600 ctl->qnt_oh = -1;
4601 ctl->qnt_h2o2 = -1;
4602 ctl->qnt_ho2 = -1;
4603 ctl->qnt_o1d = -1;
4604 ctl->qnt_mloss_oh = -1;
4605 ctl->qnt_mloss_h2o2 = -1;
4606 ctl->qnt_mloss_kpp = -1;
4607 ctl->qnt_mloss_wet = -1;
4608 ctl->qnt_mloss_dry = -1;
4609 ctl->qnt_mloss_decay = -1;
4610 ctl->qnt_loss_rate = -1;
4611 ctl->qnt_psat = -1;
4612 ctl->qnt_psice = -1;
4613 ctl->qnt_pw = -1;
4614 ctl->qnt_sh = -1;
4615 ctl->qnt_rh = -1;
4616 ctl->qnt_rhice = -1;
4617 ctl->qnt_theta = -1;
4618 ctl->qnt_zeta = -1;
4619 ctl->qnt_zeta_d = -1;
4620 ctl->qnt_tvirt = -1;
4621 ctl->qnt_lapse = -1;
4622 ctl->qnt_vh = -1;
4623 ctl->qnt_vz = -1;
4624 ctl->qnt_pv = -1;
4625 ctl->qnt_tdew = -1;
4626 ctl->qnt_tice = -1;
4627 ctl->qnt_tsts = -1;
4628 ctl->qnt_tnat = -1;
4629 ctl->qnt_Cx = -1;
4630 ctl->qnt_Ch2o = -1;
4631 ctl->qnt_Co3 = -1;
4632 ctl->qnt_Cco = -1;
4633 ctl->qnt_Coh = -1;
4634 ctl->qnt_Ch = -1;
4635 ctl->qnt_Cho2 = -1;
4636 ctl->qnt_Ch2o2 = -1;
4637 ctl->qnt_Co1d = -1;
4638 ctl->qnt_Co3p = -1;
4639 ctl->qnt_Cccl4 = -1;
4640 ctl->qnt_Cccl3f = -1;
4641 ctl->qnt_Cccl2f2 = -1;
4642 ctl->qnt_Cn2o = -1;
4643 ctl->qnt_Csf6 = -1;
4644 ctl->qnt_aoa = -1;
4645
4646 /* Read quantities... */
4647 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
4648 if (ctl->nq > NQ)
4649 ERRMSG("Too many quantities!");
4650 for (int iq = 0; iq < ctl->nq; iq++) {
4651
4652 /* Read quantity name and format... */
4653 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
4654 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
4655 ctl->qnt_longname[iq]);
4656 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
4657 ctl->qnt_format[iq]);
4658 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
4659 sprintf(ctl->qnt_format[iq], "%%.2f");
4660
4661 /* Try to identify quantity... */
4662 SET_QNT(qnt_idx, "idx", "particle index", "-")
4663 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
4664 SET_QNT(qnt_stat, "stat", "station flag", "-")
4665 SET_QNT(qnt_m, "m", "mass", "kg")
4666 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
4667 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
4668 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
4669 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
4670 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
4671 SET_QNT(qnt_zs, "zs", "surface height", "km")
4672 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
4673 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
4674 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
4675 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
4676 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
4677 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
4678 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
4679 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
4680 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
4681 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
4682 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
4683 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
4684 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
4685 SET_QNT(qnt_p, "p", "pressure", "hPa")
4686 SET_QNT(qnt_t, "t", "temperature", "K")
4687 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
4688 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
4689 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
4690 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
4691 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
4692 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
4693 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
4694 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
4695 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
4696 SET_QNT(qnt_swc, "iwc", "cloud snow water content", "kg/kg")
4697 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
4698 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
4699 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
4700 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
4701 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
4702 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
4703 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
4704 SET_QNT(qnt_cape, "cape", "convective available potential energy",
4705 "J/kg")
4706 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
4707 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
4708 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
4709 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
4710 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
4711 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
4712 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
4713 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
4714 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2", "mass loss due to H2O2 chemistry",
4715 "kg")
4716 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
4717 "kg")
4718 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
4719 "kg")
4720 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
4721 "kg")
4722 SET_QNT(qnt_mloss_decay, "mloss_decay",
4723 "mass loss due to exponential decay", "kg")
4724 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
4725 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
4726 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
4727 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
4728 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
4729 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
4730 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
4731 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
4732 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
4733 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
4734 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
4735 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
4736 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
4737 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
4738 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
4739 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
4740 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
4741 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
4742 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
4743 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
4744 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
4745 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
4746 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
4747 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
4748 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
4749 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
4750 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
4751 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
4752 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
4753 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
4754 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
4755 "ppv")
4756 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
4757 "ppv")
4758 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
4759 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
4760 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
4761 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
4762 }
4763
4764 /* Vertical coordinates and velocities... */
4765 ctl->advect_vert_coord =
4766 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
4767 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 2)
4768 ERRMSG("Set ADVECT_VERT_COORD to 0, 1, or 2!");
4769 ctl->met_vert_coord =
4770 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
4771 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
4772 ERRMSG("Set MET_VERT_COORD to 0, 1, 2, 3, or 4!");
4773 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
4774 ERRMSG("Please add zeta to your quantities for diabatic calculations!");
4775 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
4776 ERRMSG
4777 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
4778
4779 /* Time steps of simulation... */
4780 ctl->direction =
4781 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
4782 if (ctl->direction != -1 && ctl->direction != 1)
4783 ERRMSG("Set DIRECTION to -1 or 1!");
4784 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
4785 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
4786
4787 /* Meteo data... */
4788 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
4789 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
4790 ctl->met_convention =
4791 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
4792 ctl->met_type =
4793 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
4794 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
4795 ERRMSG
4796 ("Please use meteo files in netcdf format for diabatic calculations.");
4797 ctl->met_clams =
4798 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
4799 ctl->met_nc_scale =
4800 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
4801 ctl->met_nc_level =
4802 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
4803 ctl->met_nc_quant =
4804 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
4805 ctl->met_zfp_prec =
4806 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", -1, "8", NULL);
4807 ctl->met_zfp_tol_t =
4808 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_T", -1, "5.0", NULL);
4809 ctl->met_zfp_tol_z =
4810 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_Z", -1, "0.5", NULL);
4811 ctl->met_cms_batch =
4812 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
4813 ctl->met_cms_zstd =
4814 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
4815 ctl->met_cms_heur =
4816 (int) scan_ctl(filename, argc, argv, "MET_CMS_HEUR", -1, "1", NULL);
4817 ctl->met_cms_eps_z =
4818 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
4819 ctl->met_cms_eps_t =
4820 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
4821 ctl->met_cms_eps_u =
4822 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
4823 ctl->met_cms_eps_v =
4824 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
4825 ctl->met_cms_eps_w =
4826 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
4827 ctl->met_cms_eps_pv =
4828 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
4829 ctl->met_cms_eps_h2o =
4830 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
4831 ctl->met_cms_eps_o3 =
4832 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
4833 ctl->met_cms_eps_lwc =
4834 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
4835 ctl->met_cms_eps_rwc =
4836 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
4837 ctl->met_cms_eps_iwc =
4838 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
4839 ctl->met_cms_eps_swc =
4840 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
4841 ctl->met_cms_eps_cc =
4842 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
4843 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
4844 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
4845 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
4846 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
4847 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
4848 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
4849 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
4850 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
4851 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
4852 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
4853 ctl->met_detrend =
4854 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
4855 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
4856 if (ctl->met_np > EP)
4857 ERRMSG("Too many pressure levels!");
4858 ctl->met_press_level_def =
4859 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
4860 NULL);
4861 if (ctl->met_press_level_def >= 0) {
4862 level_definitions(ctl);
4863 } else {
4864 if (ctl->met_np > 0) {
4865 for (int ip = 0; ip < ctl->met_np; ip++)
4866 ctl->met_p[ip] =
4867 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
4868 }
4869 }
4870 ctl->met_nlev =
4871 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
4872 if (ctl->met_nlev > EP)
4873 ERRMSG("Too many model levels!");
4874 for (int ip = 0; ip < ctl->met_nlev; ip++) {
4875 ctl->met_lev_hyam[ip] =
4876 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
4877 ctl->met_lev_hybm[ip] =
4878 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
4879 }
4880 ctl->met_geopot_sx =
4881 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
4882 ctl->met_geopot_sy =
4883 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
4884 ctl->met_relhum =
4885 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
4886 ctl->met_cape =
4887 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
4888 if (ctl->met_cape < 0 || ctl->met_cape > 1)
4889 ERRMSG("Set MET_CAPE to 0 or 1!");
4890 ctl->met_pbl =
4891 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
4892 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
4893 ERRMSG("Set MET_PBL to 0 ... 3!");
4894 ctl->met_pbl_min =
4895 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
4896 ctl->met_pbl_max =
4897 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
4898 ctl->met_tropo =
4899 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
4900 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
4901 ERRMSG("Set MET_TROPO to 0 ... 5!");
4902 ctl->met_tropo_pv =
4903 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
4904 ctl->met_tropo_theta =
4905 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
4906 ctl->met_tropo_spline =
4907 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
4908 ctl->met_dt_out =
4909 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
4910 ctl->met_cache =
4911 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
4912 ctl->met_mpi_share =
4913 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
4914
4915 /* Sorting... */
4916 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
4917
4918 /* Isosurface parameters... */
4919 ctl->isosurf =
4920 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
4921 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
4922
4923 /* Random number generator... */
4924 ctl->rng_type =
4925 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
4926 if (ctl->rng_type < 0 || ctl->rng_type > 2)
4927 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
4928
4929 /* Advection parameters... */
4930 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
4931 if (!(ctl->advect == 0 || ctl->advect == 1
4932 || ctl->advect == 2 || ctl->advect == 4))
4933 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
4934
4935 /* Diffusion parameters... */
4936 ctl->diffusion
4937 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
4938 if (ctl->diffusion < 0 || ctl->diffusion > 2)
4939 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
4940 ctl->turb_dx_pbl =
4941 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
4942 ctl->turb_dx_trop =
4943 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
4944 ctl->turb_dx_strat =
4945 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
4946 ctl->turb_dz_pbl =
4947 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
4948 ctl->turb_dz_trop =
4949 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
4950 ctl->turb_dz_strat =
4951 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
4952 ctl->turb_mesox =
4953 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
4954 ctl->turb_mesoz =
4955 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
4956
4957 /* Convection... */
4958 ctl->conv_mix_pbl
4959 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
4960 ctl->conv_pbl_trans
4961 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
4962 ctl->conv_cape
4963 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
4964 ctl->conv_cin
4965 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
4966 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
4967
4968 /* Boundary conditions... */
4969 ctl->bound_mass =
4970 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
4971 ctl->bound_mass_trend =
4972 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
4973 ctl->bound_vmr =
4974 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
4975 ctl->bound_vmr_trend =
4976 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
4977 ctl->bound_lat0 =
4978 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
4979 ctl->bound_lat1 =
4980 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
4981 ctl->bound_p0 =
4982 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
4983 ctl->bound_p1 =
4984 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
4985 ctl->bound_dps =
4986 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
4987 ctl->bound_dzs =
4988 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
4989 ctl->bound_zetas =
4990 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
4991 ctl->bound_pbl =
4992 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
4993
4994 /* Species parameters... */
4995 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
4996 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
4997 ctl->molmass = 120.907;
4998 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
4999 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5000 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5001 ctl->molmass = 137.359;
5002 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5003 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5004 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5005 ctl->molmass = 16.043;
5006 ctl->oh_chem_reaction = 2;
5007 ctl->oh_chem[0] = 2.45e-12;
5008 ctl->oh_chem[1] = 1775;
5009 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5010 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5011 } else if (strcasecmp(ctl->species, "CO") == 0) {
5012 ctl->molmass = 28.01;
5013 ctl->oh_chem_reaction = 3;
5014 ctl->oh_chem[0] = 6.9e-33;
5015 ctl->oh_chem[1] = 2.1;
5016 ctl->oh_chem[2] = 1.1e-12;
5017 ctl->oh_chem[3] = -1.3;
5018 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5019 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5020 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5021 ctl->molmass = 44.009;
5022 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5023 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5024 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5025 ctl->molmass = 18.01528;
5026 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5027 ctl->molmass = 44.013;
5028 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5029 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5030 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5031 ctl->molmass = 17.031;
5032 ctl->oh_chem_reaction = 2;
5033 ctl->oh_chem[0] = 1.7e-12;
5034 ctl->oh_chem[1] = 710;
5035 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
5036 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
5037 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
5038 ctl->molmass = 63.012;
5039 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
5040 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
5041 } else if (strcasecmp(ctl->species, "NO") == 0) {
5042 ctl->molmass = 30.006;
5043 ctl->oh_chem_reaction = 3;
5044 ctl->oh_chem[0] = 7.1e-31;
5045 ctl->oh_chem[1] = 2.6;
5046 ctl->oh_chem[2] = 3.6e-11;
5047 ctl->oh_chem[3] = 0.1;
5048 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
5049 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5050 } else if (strcasecmp(ctl->species, "NO2") == 0) {
5051 ctl->molmass = 46.005;
5052 ctl->oh_chem_reaction = 3;
5053 ctl->oh_chem[0] = 1.8e-30;
5054 ctl->oh_chem[1] = 3.0;
5055 ctl->oh_chem[2] = 2.8e-11;
5056 ctl->oh_chem[3] = 0.0;
5057 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
5058 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5059 } else if (strcasecmp(ctl->species, "O3") == 0) {
5060 ctl->molmass = 47.997;
5061 ctl->oh_chem_reaction = 2;
5062 ctl->oh_chem[0] = 1.7e-12;
5063 ctl->oh_chem[1] = 940;
5064 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
5065 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
5066 } else if (strcasecmp(ctl->species, "SF6") == 0) {
5067 ctl->molmass = 146.048;
5068 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
5069 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
5070 } else if (strcasecmp(ctl->species, "SO2") == 0) {
5071 ctl->molmass = 64.066;
5072 ctl->oh_chem_reaction = 3;
5073 ctl->oh_chem[0] = 2.9e-31;
5074 ctl->oh_chem[1] = 4.1;
5075 ctl->oh_chem[2] = 1.7e-12;
5076 ctl->oh_chem[3] = -0.2;
5077 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
5078 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
5079 }
5080
5081 /* Molar mass... */
5082 char defstr[LEN];
5083 sprintf(defstr, "%g", ctl->molmass);
5084 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
5085
5086 /* OH chemistry... */
5087 sprintf(defstr, "%d", ctl->oh_chem_reaction);
5088 ctl->oh_chem_reaction =
5089 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
5090 NULL);
5091 for (int ip = 0; ip < 4; ip++) {
5092 sprintf(defstr, "%g", ctl->oh_chem[ip]);
5093 ctl->oh_chem[ip] =
5094 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
5095 }
5096 ctl->oh_chem_beta =
5097 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
5098
5099 /* H2O2 chemistry... */
5100 ctl->h2o2_chem_reaction =
5101 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
5102
5103 /* KPP chemistry... */
5104 ctl->kpp_chem =
5105 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
5106 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
5107
5108 /* First order tracer chemistry... */
5109 ctl->tracer_chem =
5110 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
5111
5112 /* Wet deposition... */
5113 for (int ip = 0; ip < 2; ip++) {
5114 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
5115 ctl->wet_depo_ic_h[ip] =
5116 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
5117 }
5118 for (int ip = 0; ip < 1; ip++) {
5119 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
5120 ctl->wet_depo_bc_h[ip] =
5121 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
5122 }
5123 ctl->wet_depo_so2_ph =
5124 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
5125 ctl->wet_depo_ic_a =
5126 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
5127 ctl->wet_depo_ic_b =
5128 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
5129 ctl->wet_depo_bc_a =
5130 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
5131 ctl->wet_depo_bc_b =
5132 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
5133 ctl->wet_depo_pre[0] =
5134 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
5135 ctl->wet_depo_pre[1] =
5136 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
5138 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
5140 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
5141
5142 /* Dry deposition... */
5143 ctl->dry_depo_vdep =
5144 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
5145 ctl->dry_depo_dp =
5146 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
5147
5148 /* Climatological data... */
5149 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
5150 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
5151 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
5152 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
5153 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
5154 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
5155 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
5156 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
5157 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
5158 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
5159 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
5160 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
5161 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
5162 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
5163 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
5164 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
5165 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
5166 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
5167 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
5168 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
5169 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
5170 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
5171
5172 /* Mixing... */
5173 ctl->mixing_dt =
5174 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
5175 ctl->mixing_trop =
5176 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
5177 ctl->mixing_strat =
5178 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
5179 ctl->mixing_z0 =
5180 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
5181 ctl->mixing_z1 =
5182 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
5183 ctl->mixing_nz =
5184 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
5185 ctl->mixing_lon0 =
5186 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
5187 ctl->mixing_lon1 =
5188 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
5189 ctl->mixing_nx =
5190 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
5191 ctl->mixing_lat0 =
5192 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
5193 ctl->mixing_lat1 =
5194 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
5195 ctl->mixing_ny =
5196 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
5197
5198 /* Chemistry grid... */
5199 ctl->chemgrid_z0 =
5200 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
5201 ctl->chemgrid_z1 =
5202 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
5203 ctl->chemgrid_nz =
5204 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
5205 ctl->chemgrid_lon0 =
5206 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
5207 ctl->chemgrid_lon1 =
5208 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
5209 ctl->chemgrid_nx =
5210 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
5211 ctl->chemgrid_lat0 =
5212 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
5213 ctl->chemgrid_lat1 =
5214 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
5215 ctl->chemgrid_ny =
5216 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
5217
5218 /* Exponential decay... */
5219 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
5220 ctl->tdec_strat
5221 = scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
5222
5223 /* PSC analysis... */
5224 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
5225 ctl->psc_hno3 =
5226 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
5227
5228 /* Output of atmospheric data... */
5229 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
5230 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
5231 ctl->atm_dt_out =
5232 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
5233 ctl->atm_filter =
5234 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
5235 ctl->atm_stride =
5236 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
5237 ctl->atm_type =
5238 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
5239 ctl->atm_type_out =
5240 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
5241 if (ctl->atm_type_out == -1)
5242 ctl->atm_type_out = ctl->atm_type;
5243 ctl->atm_nc_level =
5244 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
5245 for (int iq = 0; iq < ctl->nq; iq++)
5246 ctl->atm_nc_quant[iq] =
5247 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
5248 ctl->obs_type =
5249 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
5250
5251 /* Output of CSI data... */
5252 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
5253 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
5254 ctl->csi_dt_out =
5255 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
5256 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
5257 ctl->csi_obsmin =
5258 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
5259 ctl->csi_modmin =
5260 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
5261 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
5262 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
5263 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
5264 ctl->csi_lon0 =
5265 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
5266 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
5267 ctl->csi_nx =
5268 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
5269 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
5270 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
5271 ctl->csi_ny =
5272 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
5273
5274 /* Output of ensemble data... */
5275 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
5276 ctl->ens_dt_out =
5277 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
5278
5279 /* Output of grid data... */
5280 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
5281 ctl->grid_basename);
5282 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
5283 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
5284 ctl->grid_dt_out =
5285 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
5286 ctl->grid_sparse =
5287 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
5288 ctl->grid_nc_level =
5289 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
5290 for (int iq = 0; iq < ctl->nq; iq++)
5291 ctl->grid_nc_quant[iq] =
5292 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
5293 ctl->grid_stddev =
5294 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
5295 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
5296 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
5297 ctl->grid_nz =
5298 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
5299 ctl->grid_lon0 =
5300 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
5301 ctl->grid_lon1 =
5302 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
5303 ctl->grid_nx =
5304 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
5305 ctl->grid_lat0 =
5306 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
5307 ctl->grid_lat1 =
5308 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
5309 ctl->grid_ny =
5310 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
5311 ctl->grid_type =
5312 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
5313
5314 /* Output of profile data... */
5315 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
5316 ctl->prof_basename);
5317 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
5318 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
5319 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
5320 ctl->prof_nz =
5321 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
5322 ctl->prof_lon0 =
5323 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
5324 ctl->prof_lon1 =
5325 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
5326 ctl->prof_nx =
5327 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
5328 ctl->prof_lat0 =
5329 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
5330 ctl->prof_lat1 =
5331 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
5332 ctl->prof_ny =
5333 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
5334
5335 /* Output of sample data... */
5336 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
5337 ctl->sample_basename);
5338 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
5339 ctl->sample_kernel);
5340 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
5341 ctl->sample_obsfile);
5342 ctl->sample_dx =
5343 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
5344 ctl->sample_dz =
5345 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
5346
5347 /* Output of station data... */
5348 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
5349 ctl->stat_basename);
5350 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
5351 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
5352 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
5353 ctl->stat_t0 =
5354 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
5355 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
5356
5357 /* Output of VTK data... */
5358 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
5359 ctl->vtk_dt_out =
5360 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
5361 ctl->vtk_stride =
5362 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
5363 ctl->vtk_scale =
5364 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
5365 ctl->vtk_offset =
5366 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
5367 ctl->vtk_sphere =
5368 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
5369}
5370
5371/*****************************************************************************/
5372
5374 const char *filename,
5375 const ctl_t *ctl,
5376 const clim_t *clim,
5377 met_t *met) {
5378
5379 /* Write info... */
5380 LOG(1, "Read meteo data: %s", filename);
5381
5382 /* Set rank... */
5383 int rank = 0;
5384#ifdef MPI
5385 if (ctl->met_mpi_share)
5386 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5387#endif
5388
5389 /* Check rank... */
5390 if (!ctl->met_mpi_share || rank == 0) {
5391
5392 /* Read netCDF data... */
5393 if (ctl->met_type == 0) {
5394 if (read_met_nc(filename, ctl, clim, met) != 1)
5395 return 0;
5396 }
5397
5398 /* Read binary data... */
5399 else if (ctl->met_type >= 1 && ctl->met_type <= 5) {
5400 if (read_met_bin(filename, ctl, met) != 1)
5401 return 0;
5402 }
5403
5404 /* Not implemented... */
5405 else
5406 ERRMSG("MET_TYPE not implemented!");
5407 }
5408
5409 /* Broadcast data via MPI... */
5410#ifdef MPI
5411 if (ctl->met_mpi_share) {
5412
5413 /* Set timer... */
5414 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
5415 LOG(2, "Broadcast data on rank %d...", rank);
5416
5417 /* Broadcast... */
5418 broadcast_large_data(met, sizeof(met_t));
5419 }
5420#endif
5421
5422 /* Return success... */
5423 return 1;
5424}
5425
5426/*****************************************************************************/
5427
5429 ctl_t *ctl,
5430 cache_t *cache,
5431 clim_t *clim,
5432 met_t **met0,
5433 met_t **met1,
5434 atm_t *atm,
5435 double t) {
5436
5437 /* Initialize modules... */
5438 if (t == ctl->t_start) {
5439
5440 /* Initialize isosurface data... */
5441 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5442 module_isosurf_init(ctl, cache, *met0, *met1, atm);
5443
5444 /* Initialize advection... */
5445 module_advect_init(ctl, cache, *met0, *met1, atm);
5446
5447 /* Initialize chemistry... */
5448 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
5449 }
5450
5451 /* Set time steps of air parcels... */
5452 module_timesteps(ctl, cache, *met0, atm, t);
5453
5454 /* Sort particles... */
5455 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
5456 module_sort(ctl, *met0, atm);
5457
5458 /* Check positions (initial)... */
5459 module_position(cache, *met0, *met1, atm);
5460
5461 /* Advection... */
5462 if (ctl->advect > 0)
5463 module_advect(ctl, cache, *met0, *met1, atm);
5464
5465 /* Turbulent diffusion... */
5466 if (ctl->diffusion == 1
5467 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
5468 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
5469 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
5470 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
5471
5472 /* Mesoscale diffusion... */
5473 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
5474 module_diff_meso(ctl, cache, *met0, *met1, atm);
5475
5476 /* Diffusion... */
5477 if (ctl->diffusion == 2)
5478 module_diff_pbl(ctl, cache, *met0, *met1, atm);
5479
5480 /* Convection... */
5481 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
5482 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
5483 module_convection(ctl, cache, *met0, *met1, atm);
5484
5485 /* Sedimentation... */
5486 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
5487 module_sedi(ctl, cache, *met0, *met1, atm);
5488
5489 /* Isosurface... */
5490 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5491 module_isosurf(ctl, cache, *met0, *met1, atm);
5492
5493 /* Check positions (final)... */
5494 module_position(cache, *met0, *met1, atm);
5495
5496 /* Interpolate meteo data... */
5497 if (ctl->met_dt_out > 0
5498 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
5499 module_meteo(ctl, cache, clim, *met0, *met1, atm);
5500
5501 /* Check boundary conditions (initial)... */
5502 if ((ctl->bound_lat0 < ctl->bound_lat1)
5503 && (ctl->bound_p0 > ctl->bound_p1))
5504 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5505
5506 /* Initialize quantity of total loss rate... */
5507 if (ctl->qnt_loss_rate >= 0) {
5508 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
5509 atm->q[ctl->qnt_loss_rate][ip] = 0;
5510 }
5511 }
5512
5513 /* Decay of particle mass... */
5514 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
5515 module_decay(ctl, cache, clim, atm);
5516
5517 /* Interparcel mixing... */
5518 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
5519 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
5520 module_mixing(ctl, clim, atm, t);
5521
5522 /* Calculate the tracer vmr in the chemistry grid... */
5523 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
5524 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
5525 module_chem_grid(ctl, *met0, *met1, atm, t);
5526
5527 /* OH chemistry... */
5528 if (ctl->oh_chem_reaction != 0)
5529 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
5530
5531 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
5532 if (ctl->h2o2_chem_reaction != 0)
5533 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
5534
5535 /* First-order tracer chemistry... */
5536 if (ctl->tracer_chem)
5537 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
5538
5539 /* KPP chemistry... */
5540 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
5541#ifdef KPP
5542 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
5543#else
5544 ERRMSG("Code was compiled without KPP!");
5545#endif
5546 }
5547
5548 /* Wet deposition... */
5549 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
5550 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
5551 module_wet_depo(ctl, cache, *met0, *met1, atm);
5552
5553 /* Dry deposition... */
5554 if (ctl->dry_depo_vdep > 0)
5555 module_dry_depo(ctl, cache, *met0, *met1, atm);
5556
5557 /* Check boundary conditions (final)... */
5558 if ((ctl->bound_lat0 < ctl->bound_lat1)
5559 && (ctl->bound_p0 > ctl->bound_p1))
5560 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5561}
5562
5563/*****************************************************************************/
5564
5566 const ctl_t *ctl,
5567 const cache_t *cache,
5568 const clim_t *clim,
5569 met_t **met0,
5570 met_t **met1,
5571 const atm_t *atm) {
5572
5573 /* Update GPU... */
5574 if (ctl != NULL) {
5575#ifdef _OPENACC
5576 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5577#pragma acc update device(ctl[:1])
5578#endif
5579 }
5580
5581 if (cache != NULL) {
5582#ifdef _OPENACC
5583 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5584#pragma acc update device(cache[:1])
5585#endif
5586 }
5587
5588 if (clim != NULL) {
5589#ifdef _OPENACC
5590 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5591#pragma acc update device(clim[:1])
5592#endif
5593 }
5594
5595 if (met0 != NULL) {
5596#ifdef _OPENACC
5597 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5598 met_t *met0up = *met0;
5599#pragma acc update device(met0up[:1])
5600#endif
5601 }
5602
5603 if (met1 != NULL) {
5604#ifdef _OPENACC
5605 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5606 met_t *met1up = *met1;
5607#pragma acc update device(met1up[:1])
5608#endif
5609 }
5610
5611 if (atm != NULL) {
5612#ifdef _OPENACC
5613 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5614#pragma acc update device(atm[:1])
5615#endif
5616 }
5617}
5618
5619/*****************************************************************************/
5620
5622 const ctl_t *ctl,
5623 const cache_t *cache,
5624 const clim_t *clim,
5625 met_t **met0,
5626 met_t **met1,
5627 const atm_t *atm) {
5628
5629 /* Update GPU... */
5630 if (ctl != NULL) {
5631#ifdef _OPENACC
5632 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5633#pragma acc update host(ctl[:1])
5634#endif
5635 }
5636
5637 if (cache != NULL) {
5638#ifdef _OPENACC
5639 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5640#pragma acc update host(cache[:1])
5641#endif
5642 }
5643
5644 if (clim != NULL) {
5645#ifdef _OPENACC
5646 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5647#pragma acc update host(clim[:1])
5648#endif
5649 }
5650
5651 if (met0 != NULL) {
5652#ifdef _OPENACC
5653 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5654 met_t *met0up = *met0;
5655#pragma acc update host(met0up[:1])
5656#endif
5657 }
5658
5659 if (met1 != NULL) {
5660#ifdef _OPENACC
5661 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5662 met_t *met1up = *met1;
5663#pragma acc update host(met1up[:1])
5664#endif
5665 }
5666
5667 if (atm != NULL) {
5668#ifdef _OPENACC
5669 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5670#pragma acc update host(atm[:1])
5671#endif
5672 }
5673}
5674
5675/*****************************************************************************/
5676
5678 const char *filename,
5679 const ctl_t *ctl,
5680 const atm_t *atm,
5681 const double t) {
5682
5683 /* Set timer... */
5684 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
5685
5686 /* Write info... */
5687 LOG(1, "Write atmospheric data: %s", filename);
5688
5689 /* Write ASCII data... */
5690 if (ctl->atm_type_out == 0)
5691 write_atm_asc(filename, ctl, atm, t);
5692
5693 /* Write binary data... */
5694 else if (ctl->atm_type_out == 1)
5695 write_atm_bin(filename, ctl, atm);
5696
5697 /* Write netCDF data... */
5698 else if (ctl->atm_type_out == 2)
5699 write_atm_nc(filename, ctl, atm);
5700
5701 /* Write CLaMS trajectory data... */
5702 else if (ctl->atm_type_out == 3)
5703 write_atm_clams_traj(filename, ctl, atm, t);
5704
5705 /* Write CLaMS pos data... */
5706 else if (ctl->atm_type_out == 4)
5707 write_atm_clams(filename, ctl, atm);
5708
5709 /* Error... */
5710 else
5711 ERRMSG("Atmospheric data type not supported!");
5712
5713 /* Write info... */
5714 double mini, maxi;
5715 LOG(2, "Number of particles: %d", atm->np);
5716 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5717 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5718 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5719 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5720 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5721 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5722 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5723 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5724 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5725 for (int iq = 0; iq < ctl->nq; iq++) {
5726 char msg[5 * LEN];
5727 sprintf(msg, "Quantity %s range: %s ... %s %s",
5728 ctl->qnt_name[iq], ctl->qnt_format[iq],
5729 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5730 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5731 LOG(2, msg, mini, maxi);
5732 }
5733}
5734
5735/*****************************************************************************/
5736
5738 const char *filename,
5739 const ctl_t *ctl,
5740 met_t *met) {
5741
5742 /* Set timer... */
5743 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
5744
5745 /* Write info... */
5746 LOG(1, "Write meteo data: %s", filename);
5747
5748 /* Check compression flags... */
5749#ifndef ZFP
5750 if (ctl->met_type == 3)
5751 ERRMSG("MPTRAC was compiled without zfp compression!");
5752#endif
5753#ifndef ZSTD
5754 if (ctl->met_type == 4)
5755 ERRMSG("MPTRAC was compiled without zstd compression!");
5756#endif
5757#ifndef CMS
5758 if (ctl->met_type == 5)
5759 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
5760#endif
5761
5762 /* Write netCDF data... */
5763 if (ctl->met_type == 0)
5764 write_met_nc(filename, ctl, met);
5765
5766 /* Write binary data... */
5767 else if (ctl->met_type >= 1 && ctl->met_type <= 5)
5768 write_met_bin(filename, ctl, met);
5769
5770 /* Not implemented... */
5771 else
5772 ERRMSG("MET_TYPE not implemented!");
5773}
5774
5775/*****************************************************************************/
5776
5778 const char *dirname,
5779 const ctl_t *ctl,
5780 met_t *met0,
5781 met_t *met1,
5782 atm_t *atm,
5783 const double t) {
5784
5785 char ext[10], filename[2 * LEN];
5786
5787 double r;
5788
5789 int year, mon, day, hour, min, sec;
5790
5791 /* Get time... */
5792 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
5793
5794 /* Update host... */
5795 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
5796 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
5797 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
5798 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
5799 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
5800 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
5801 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
5802
5803 /* Write atmospheric data... */
5804 if (ctl->atm_basename[0] != '-' &&
5805 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
5806 if (ctl->atm_type_out == 0)
5807 sprintf(ext, "tab");
5808 else if (ctl->atm_type_out == 1)
5809 sprintf(ext, "bin");
5810 else if (ctl->atm_type_out == 2)
5811 sprintf(ext, "nc");
5812 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
5813 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
5814 mptrac_write_atm(filename, ctl, atm, t);
5815 }
5816
5817 /* Write gridded data... */
5818 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
5819 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
5820 dirname, ctl->grid_basename, year, mon, day, hour, min,
5821 ctl->grid_type == 0 ? "tab" : "nc");
5822 write_grid(filename, ctl, met0, met1, atm, t);
5823 }
5824
5825 /* Write CSI data... */
5826 if (ctl->csi_basename[0] != '-') {
5827 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
5828 write_csi(filename, ctl, atm, t);
5829 }
5830
5831 /* Write ensemble data... */
5832 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
5833 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
5834 dirname, ctl->ens_basename, year, mon, day, hour, min);
5835 write_ens(filename, ctl, atm, t);
5836 }
5837
5838 /* Write profile data... */
5839 if (ctl->prof_basename[0] != '-') {
5840 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
5841 write_prof(filename, ctl, met0, met1, atm, t);
5842 }
5843
5844 /* Write sample data... */
5845 if (ctl->sample_basename[0] != '-') {
5846 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
5847 write_sample(filename, ctl, met0, met1, atm, t);
5848 }
5849
5850 /* Write station data... */
5851 if (ctl->stat_basename[0] != '-') {
5852 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
5853 write_station(filename, ctl, atm, t);
5854 }
5855
5856 /* Write VTK data... */
5857 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
5858 static int nvtk;
5859 if (t == ctl->t_start)
5860 nvtk = 0;
5861 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
5862 write_vtk(filename, ctl, atm, t);
5863 }
5864}
5865
5866/*****************************************************************************/
5867
5869 const double p,
5870 const double h2o,
5871 const double hno3) {
5872
5873 /* Check water vapor volume mixing ratio... */
5874 const double h2o_help = MAX(h2o, 0.1e-6);
5875
5876 /* Calculate T_NAT... */
5877 const double p_hno3 = hno3 * p / 1.333224;
5878 const double p_h2o = h2o_help * p / 1.333224;
5879 const double a = 0.009179 - 0.00088 * log10(p_h2o);
5880 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
5881 const double c = -11397.0 / a;
5882 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
5883 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
5884 if (x2 > 0)
5885 tnat = x2;
5886
5887 return tnat;
5888}
5889
5890/*****************************************************************************/
5891
5893 const ctl_t *ctl,
5894 const atm_t *atm,
5895 const int ip,
5896 const double pbl,
5897 const double ps) {
5898
5899 /* Get pressure range... */
5900 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
5901 const double p0 = pbl;
5902
5903 /* Get weighting factor... */
5904 if (atm->p[ip] > p0)
5905 return 1;
5906 else if (atm->p[ip] < p1)
5907 return 0;
5908 else
5909 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
5910}
5911
5912/*****************************************************************************/
5913
5915 const char *filename,
5916 const ctl_t *ctl,
5917 atm_t *atm) {
5918
5919 /* Open file... */
5920 FILE *in;
5921 if (!(in = fopen(filename, "r"))) {
5922 WARN("Cannot open file!");
5923 return 0;
5924 }
5925
5926 /* Read line... */
5927 char line[LEN];
5928 while (fgets(line, LEN, in)) {
5929
5930 /* Read data... */
5931 char *tok;
5932 TOK(line, tok, "%lg", atm->time[atm->np]);
5933 TOK(NULL, tok, "%lg", atm->p[atm->np]);
5934 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
5935 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
5936 for (int iq = 0; iq < ctl->nq; iq++)
5937 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
5938
5939 /* Convert altitude to pressure... */
5940 atm->p[atm->np] = P(atm->p[atm->np]);
5941
5942 /* Increment data point counter... */
5943 if ((++atm->np) > NP)
5944 ERRMSG("Too many data points!");
5945 }
5946
5947 /* Close file... */
5948 fclose(in);
5949
5950 /* Return success... */
5951 return 1;
5952}
5953
5954/*****************************************************************************/
5955
5957 const char *filename,
5958 const ctl_t *ctl,
5959 atm_t *atm) {
5960
5961 /* Open file... */
5962 FILE *in;
5963 if (!(in = fopen(filename, "r")))
5964 return 0;
5965
5966 /* Check version of binary data... */
5967 int version;
5968 FREAD(&version, int,
5969 1,
5970 in);
5971 if (version != 100)
5972 ERRMSG("Wrong version of binary data!");
5973
5974 /* Read data... */
5975 FREAD(&atm->np, int,
5976 1,
5977 in);
5978 FREAD(atm->time, double,
5979 (size_t) atm->np,
5980 in);
5981 FREAD(atm->p, double,
5982 (size_t) atm->np,
5983 in);
5984 FREAD(atm->lon, double,
5985 (size_t) atm->np,
5986 in);
5987 FREAD(atm->lat, double,
5988 (size_t) atm->np,
5989 in);
5990 for (int iq = 0; iq < ctl->nq; iq++)
5991 FREAD(atm->q[iq], double,
5992 (size_t) atm->np,
5993 in);
5994
5995 /* Read final flag... */
5996 int final;
5997 FREAD(&final, int,
5998 1,
5999 in);
6000 if (final != 999)
6001 ERRMSG("Error while reading binary data!");
6002
6003 /* Close file... */
6004 fclose(in);
6005
6006 /* Return success... */
6007 return 1;
6008}
6009
6010/*****************************************************************************/
6011
6013 const char *filename,
6014 const ctl_t *ctl,
6015 atm_t *atm) {
6016
6017 int ncid, varid;
6018
6019 /* Open file... */
6020 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6021 return 0;
6022
6023 /* Get dimensions... */
6024 NC_INQ_DIM("NPARTS", &atm->np, 1, NP);
6025
6026 /* Get time... */
6027 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
6028 NC(nc_get_var_double(ncid, varid, atm->time));
6029 } else {
6030 WARN("TIME_INIT not found use time instead!");
6031 double time_init;
6032 NC_GET_DOUBLE("time", &time_init, 1);
6033 for (int ip = 0; ip < atm->np; ip++) {
6034 atm->time[ip] = time_init;
6035 }
6036 }
6037
6038 /* Read zeta coordinate, pressure is optional... */
6039 if (ctl->advect_vert_coord == 1) {
6040 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
6041 NC_GET_DOUBLE("PRESS", atm->p, 0);
6042 }
6043
6044 /* Read pressure, zeta coordinate is optional... */
6045 else {
6046 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
6047 NC(nc_get_var_double(ncid, varid, atm->p));
6048 } else {
6049 WARN("PRESS_INIT not found use PRESS instead!");
6050 nc_inq_varid(ncid, "PRESS", &varid);
6051 NC(nc_get_var_double(ncid, varid, atm->p));
6052 }
6053 }
6054
6055 /* Read longitude and latitude... */
6056 NC_GET_DOUBLE("LON", atm->lon, 1);
6057 NC_GET_DOUBLE("LAT", atm->lat, 1);
6058
6059 /* Close file... */
6060 NC(nc_close(ncid));
6061
6062 /* Return success... */
6063 return 1;
6064}
6065
6066/*****************************************************************************/
6067
6069 const char *filename,
6070 const ctl_t *ctl,
6071 atm_t *atm) {
6072
6073 int ncid, varid;
6074
6075 /* Open file... */
6076 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6077 return 0;
6078
6079 /* Get dimensions... */
6080 NC_INQ_DIM("obs", &atm->np, 1, NP);
6081
6082 /* Read geolocations... */
6083 NC_GET_DOUBLE("time", atm->time, 1);
6084 NC_GET_DOUBLE("press", atm->p, 1);
6085 NC_GET_DOUBLE("lon", atm->lon, 1);
6086 NC_GET_DOUBLE("lat", atm->lat, 1);
6087
6088 /* Read variables... */
6089 for (int iq = 0; iq < ctl->nq; iq++)
6090 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6091
6092 /* Close file... */
6093 NC(nc_close(ncid));
6094
6095 /* Return success... */
6096 return 1;
6097}
6098
6099/*****************************************************************************/
6100
6102 const char *filename,
6103 clim_photo_t *photo) {
6104
6105 int ncid, varid;
6106
6107 /* Write info... */
6108 LOG(1, "Read photolysis rates: %s", filename);
6109
6110 /* Open netCDF file... */
6111 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6112 WARN("Photolysis rate data are missing!");
6113 return;
6114 }
6115
6116 /* Read pressure data... */
6117 NC_INQ_DIM("press", &photo->np, 2, CP);
6118 NC_GET_DOUBLE("press", photo->p, 1);
6119 if (photo->p[0] < photo->p[1])
6120 ERRMSG("Pressure data are not descending!");
6121
6122 /* Read total column ozone data... */
6123 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3);
6124 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
6125 if (photo->o3c[0] > photo->o3c[1])
6126 ERRMSG("Total column ozone data are not ascending!");
6127
6128 /* Read solar zenith angle data... */
6129 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA);
6130 NC_GET_DOUBLE("sza", photo->sza, 1);
6131 if (photo->sza[0] > photo->sza[1])
6132 ERRMSG("Solar zenith angle data are not ascending!");
6133
6134 /* Read data... */
6135 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
6136 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
6137 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
6138 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
6139 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
6140 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
6141 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
6142 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
6143 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
6144
6145 /* Close netCDF file... */
6146 NC(nc_close(ncid));
6147
6148 /* Write info... */
6149 LOG(2, "Number of pressure levels: %d", photo->np);
6150 LOG(2, "Altitude levels: %g, %g ... %g km",
6151 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
6152 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6153 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
6154 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
6155 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
6156 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
6157 RAD2DEG(photo->sza[photo->nsza - 1]));
6158 LOG(2, "Number of total column ozone values: %d", photo->no3c);
6159 LOG(2, "Total column ozone: %g, %g ... %g DU",
6160 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
6161 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
6162 photo->n2o[0][0][0], photo->n2o[1][0][0],
6163 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6164 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
6165 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
6166 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6167 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
6168 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
6169 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6170 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
6171 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
6172 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6173 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
6174 photo->o2[0][0][0], photo->o2[1][0][0],
6175 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6176 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
6177 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
6178 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6179 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
6180 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
6181 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6182 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
6183 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
6184 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6185 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
6186 photo->h2o[0][0][0], photo->h2o[1][0][0],
6187 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6188}
6189
6190/*****************************************************************************/
6191
6193 const int ncid,
6194 const char *varname,
6195 const clim_photo_t *photo,
6196 double var[CP][CSZA][CO3]) {
6197
6198 /* Allocate... */
6199 double *help;
6200 ALLOC(help, double,
6201 photo->np * photo->nsza * photo->no3c);
6202
6203 /* Read varible... */
6204 int varid;
6205 NC_GET_DOUBLE(varname, help, 1);
6206
6207 /* Copy data... */
6208 for (int ip = 0; ip < photo->np; ip++)
6209 for (int is = 0; is < photo->nsza; is++)
6210 for (int io = 0; io < photo->no3c; io++)
6211 var[ip][is][io] =
6212 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
6213
6214 /* Free... */
6215 free(help);
6216}
6217
6218/*****************************************************************************/
6219
6221 const char *filename,
6222 clim_ts_t *ts) {
6223
6224 /* Write info... */
6225 LOG(1, "Read climatological time series: %s", filename);
6226
6227 /* Open file... */
6228 FILE *in;
6229 if (!(in = fopen(filename, "r"))) {
6230 WARN("Cannot open file!");
6231 return 0;
6232 }
6233
6234 /* Read data... */
6235 char line[LEN];
6236 int nh = 0;
6237 while (fgets(line, LEN, in))
6238 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
6239
6240 /* Convert years to seconds... */
6241 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
6242
6243 /* Check data... */
6244 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
6245 ERRMSG("Time series must be ascending!");
6246
6247 /* Count time steps... */
6248 if ((++nh) >= CTS)
6249 ERRMSG("Too many data points!");
6250 }
6251
6252 /* Close file... */
6253 fclose(in);
6254
6255 /* Check number of data points... */
6256 ts->ntime = nh;
6257 if (nh < 2)
6258 ERRMSG("Not enough data points!");
6259
6260 /* Write info... */
6261 LOG(2, "Number of time steps: %d", ts->ntime);
6262 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
6263 ts->time[nh - 1]);
6264 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
6265 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
6266 (size_t) nh));
6267
6268 /* Exit success... */
6269 return 1;
6270}
6271
6272/*****************************************************************************/
6273
6275 const char *filename,
6276 const char *varname,
6277 clim_zm_t *zm) {
6278
6279 int ncid, varid, it, iy, iz, iz2, nt;
6280
6281 double *help, varmin = 1e99, varmax = -1e99;
6282
6283 /* Write info... */
6284 LOG(1, "Read %s data: %s", varname, filename);
6285
6286 /* Open netCDF file... */
6287 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6288 WARN("%s climatology data are missing!", varname);
6289 return;
6290 }
6291
6292 /* Read pressure data... */
6293 NC_INQ_DIM("press", &zm->np, 2, CP);
6294 NC_GET_DOUBLE("press", zm->p, 1);
6295 if (zm->p[0] < zm->p[1])
6296 ERRMSG("Pressure data are not descending!");
6297
6298 /* Read latitudes... */
6299 NC_INQ_DIM("lat", &zm->nlat, 2, CY);
6300 NC_GET_DOUBLE("lat", zm->lat, 1);
6301 if (zm->lat[0] > zm->lat[1])
6302 ERRMSG("Latitude data are not ascending!");
6303
6304 /* Set time data (for monthly means)... */
6305 zm->ntime = 12;
6306 zm->time[0] = 1209600.00;
6307 zm->time[1] = 3888000.00;
6308 zm->time[2] = 6393600.00;
6309 zm->time[3] = 9072000.00;
6310 zm->time[4] = 11664000.00;
6311 zm->time[5] = 14342400.00;
6312 zm->time[6] = 16934400.00;
6313 zm->time[7] = 19612800.00;
6314 zm->time[8] = 22291200.00;
6315 zm->time[9] = 24883200.00;
6316 zm->time[10] = 27561600.00;
6317 zm->time[11] = 30153600.00;
6318
6319 /* Check number of timesteps... */
6320 NC_INQ_DIM("time", &nt, 12, 12);
6321
6322 /* Read data... */
6323 ALLOC(help, double,
6324 zm->nlat * zm->np * zm->ntime);
6325 NC_GET_DOUBLE(varname, help, 1);
6326 for (it = 0; it < zm->ntime; it++)
6327 for (iz = 0; iz < zm->np; iz++)
6328 for (iy = 0; iy < zm->nlat; iy++)
6329 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
6330 free(help);
6331
6332 /* Fix data gaps... */
6333 for (it = 0; it < zm->ntime; it++)
6334 for (iy = 0; iy < zm->nlat; iy++)
6335 for (iz = 0; iz < zm->np; iz++) {
6336 if (zm->vmr[it][iz][iy] < 0) {
6337 for (iz2 = 0; iz2 < zm->np; iz2++)
6338 if (zm->vmr[it][iz2][iy] >= 0) {
6339 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6340 break;
6341 }
6342 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
6343 if (zm->vmr[it][iz2][iy] >= 0) {
6344 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6345 break;
6346 }
6347 }
6348 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
6349 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
6350 }
6351
6352 /* Close netCDF file... */
6353 NC(nc_close(ncid));
6354
6355 /* Write info... */
6356 LOG(2, "Number of time steps: %d", zm->ntime);
6357 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
6358 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
6359 LOG(2, "Number of pressure levels: %d", zm->np);
6360 LOG(2, "Altitude levels: %g, %g ... %g km",
6361 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
6362 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
6363 zm->p[1], zm->p[zm->np - 1]);
6364 LOG(2, "Number of latitudes: %d", zm->nlat);
6365 LOG(2, "Latitudes: %g, %g ... %g deg",
6366 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
6367 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
6368 varmax);
6369}
6370
6371/*****************************************************************************/
6372
6374 const char *filename,
6375 double kz[EP],
6376 double kw[EP],
6377 int *nk) {
6378
6379 /* Write info... */
6380 LOG(1, "Read kernel function: %s", filename);
6381
6382 /* Open file... */
6383 FILE *in;
6384 if (!(in = fopen(filename, "r")))
6385 ERRMSG("Cannot open file!");
6386
6387 /* Read data... */
6388 char line[LEN];
6389 int n = 0;
6390 while (fgets(line, LEN, in))
6391 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
6392 if (n > 0 && kz[n] < kz[n - 1])
6393 ERRMSG("Height levels must be ascending!");
6394 if ((++n) >= EP)
6395 ERRMSG("Too many height levels!");
6396 }
6397
6398 /* Close file... */
6399 fclose(in);
6400
6401 /* Check number of data points... */
6402 *nk = n;
6403 if (n < 2)
6404 ERRMSG("Not enough height levels!");
6405
6406 /* Normalize kernel function... */
6407 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
6408 for (int iz = 0; iz < n; iz++)
6409 kw[iz] /= kmax;
6410}
6411
6412/*****************************************************************************/
6413
6415 const char *filename,
6416 const ctl_t *ctl,
6417 met_t *met) {
6418
6419 FILE *in;
6420
6421 double r;
6422
6423 int year, mon, day, hour, min, sec;
6424
6425 /* Set timer... */
6426 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
6427
6428 /* Open file... */
6429 if (!(in = fopen(filename, "r"))) {
6430 WARN("Cannot open file!");
6431 return 0;
6432 }
6433
6434 /* Check type of binary data... */
6435 int met_type;
6436 FREAD(&met_type, int,
6437 1,
6438 in);
6439 if (met_type != ctl->met_type)
6440 ERRMSG("Wrong MET_TYPE of binary data!");
6441
6442 /* Check version of binary data... */
6443 int version;
6444 FREAD(&version, int,
6445 1,
6446 in);
6447 if (version != 103)
6448 ERRMSG("Wrong version of binary data!");
6449
6450 /* Read time... */
6451 FREAD(&met->time, double,
6452 1,
6453 in);
6454 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
6455 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
6456 met->time, year, mon, day, hour, min);
6457 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
6458 || day < 1 || day > 31 || hour < 0 || hour > 23)
6459 ERRMSG("Error while reading time!");
6460
6461 /* Read dimensions... */
6462 FREAD(&met->nx, int,
6463 1,
6464 in);
6465 LOG(2, "Number of longitudes: %d", met->nx);
6466 if (met->nx < 2 || met->nx > EX)
6467 ERRMSG("Number of longitudes out of range!");
6468
6469 FREAD(&met->ny, int,
6470 1,
6471 in);
6472 LOG(2, "Number of latitudes: %d", met->ny);
6473 if (met->ny < 2 || met->ny > EY)
6474 ERRMSG("Number of latitudes out of range!");
6475
6476 FREAD(&met->np, int,
6477 1,
6478 in);
6479 LOG(2, "Number of levels: %d", met->np);
6480 if (met->np < 2 || met->np > EP)
6481 ERRMSG("Number of levels out of range!");
6482
6483 /* Read grid... */
6484 FREAD(met->lon, double,
6485 (size_t) met->nx,
6486 in);
6487 LOG(2, "Longitudes: %g, %g ... %g deg",
6488 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
6489
6490 FREAD(met->lat, double,
6491 (size_t) met->ny,
6492 in);
6493 LOG(2, "Latitudes: %g, %g ... %g deg",
6494 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
6495
6496 FREAD(met->p, double,
6497 (size_t) met->np,
6498 in);
6499 LOG(2, "Altitude levels: %g, %g ... %g km",
6500 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
6501 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6502 met->p[0], met->p[1], met->p[met->np - 1]);
6503
6504 /* Read surface data... */
6505 read_met_bin_2d(in, met, met->ps, "PS");
6506 read_met_bin_2d(in, met, met->ts, "TS");
6507 read_met_bin_2d(in, met, met->zs, "ZS");
6508 read_met_bin_2d(in, met, met->us, "US");
6509 read_met_bin_2d(in, met, met->vs, "VS");
6510 read_met_bin_2d(in, met, met->ess, "ESS");
6511 read_met_bin_2d(in, met, met->nss, "NSS");
6512 read_met_bin_2d(in, met, met->shf, "SHF");
6513 read_met_bin_2d(in, met, met->lsm, "LSM");
6514 read_met_bin_2d(in, met, met->sst, "SST");
6515 read_met_bin_2d(in, met, met->pbl, "PBL");
6516 read_met_bin_2d(in, met, met->pt, "PT");
6517 read_met_bin_2d(in, met, met->tt, "TT");
6518 read_met_bin_2d(in, met, met->zt, "ZT");
6519 read_met_bin_2d(in, met, met->h2ot, "H2OT");
6520 read_met_bin_2d(in, met, met->pct, "PCT");
6521 read_met_bin_2d(in, met, met->pcb, "PCB");
6522 read_met_bin_2d(in, met, met->cl, "CL");
6523 read_met_bin_2d(in, met, met->plcl, "PLCL");
6524 read_met_bin_2d(in, met, met->plfc, "PLFC");
6525 read_met_bin_2d(in, met, met->pel, "PEL");
6526 read_met_bin_2d(in, met, met->cape, "CAPE");
6527 read_met_bin_2d(in, met, met->cin, "CIN");
6528 read_met_bin_2d(in, met, met->o3c, "O3C");
6529
6530 /* Read level data... */
6531 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
6532 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
6533 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
6534 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
6535 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
6536 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
6537 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
6538 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
6539 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
6540 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
6541 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
6542 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
6543 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
6544
6545 /* Read final flag... */
6546 int final;
6547 FREAD(&final, int,
6548 1,
6549 in);
6550 if (final != 999)
6551 ERRMSG("Error while reading binary data!");
6552
6553 /* Close file... */
6554 fclose(in);
6555
6556 /* Return success... */
6557 return 1;
6558}
6559
6560/*****************************************************************************/
6561
6563 FILE *in,
6564 const met_t *met,
6565 float var[EX][EY],
6566 const char *varname) {
6567
6568 float *help;
6569
6570 /* Allocate... */
6571 ALLOC(help, float,
6572 EX * EY);
6573
6574 /* Read uncompressed... */
6575 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
6576 FREAD(help, float,
6577 (size_t) (met->nx * met->ny),
6578 in);
6579
6580 /* Copy data... */
6581 for (int ix = 0; ix < met->nx; ix++)
6582 for (int iy = 0; iy < met->ny; iy++)
6583 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
6584
6585 /* Free... */
6586 free(help);
6587}
6588
6589/*****************************************************************************/
6590
6592 FILE *in,
6593 const ctl_t *ctl,
6594 const met_t *met,
6595 float var[EX][EY][EP],
6596 const char *varname,
6597 const float bound_min,
6598 const float bound_max) {
6599
6600 float *help;
6601
6602 /* Allocate... */
6603 ALLOC(help, float,
6604 EX * EY * EP);
6605
6606 /* Read uncompressed data... */
6607 if (ctl->met_type == 1) {
6608 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
6609 FREAD(help, float,
6610 (size_t) (met->nx * met->ny * met->np),
6611 in);
6612 }
6613
6614 /* Read packed data... */
6615 else if (ctl->met_type == 2)
6616 compress_pck(varname, help, (size_t) (met->ny * met->nx),
6617 (size_t) met->np, 1, in);
6618
6619 /* Read zfp data... */
6620 else if (ctl->met_type == 3) {
6621#ifdef ZFP
6622 int precision;
6623 FREAD(&precision, int,
6624 1,
6625 in);
6626
6627 double tolerance;
6628 FREAD(&tolerance, double,
6629 1,
6630 in);
6631
6632 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
6633 tolerance, 1, in);
6634#else
6635 ERRMSG("MPTRAC was compiled without zfp compression!");
6636#endif
6637 }
6638
6639 /* Read zstd data... */
6640 else if (ctl->met_type == 4) {
6641#ifdef ZSTD
6642 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
6643 in);
6644#else
6645 ERRMSG("MPTRAC was compiled without zstd compression!");
6646#endif
6647 }
6648
6649 /* Read cmultiscale data... */
6650 else if (ctl->met_type == 5) {
6651#ifdef CMS
6652 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
6653 (size_t) met->np, 1, in);
6654#else
6655 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6656#endif
6657 }
6658
6659 /* Copy data... */
6660#pragma omp parallel for default(shared) collapse(2)
6661 for (int ix = 0; ix < met->nx; ix++)
6662 for (int iy = 0; iy < met->ny; iy++)
6663 for (int ip = 0; ip < met->np; ip++) {
6664 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
6665 if (var[ix][iy][ip] < bound_min)
6666 var[ix][iy][ip] = bound_min;
6667 else if (var[ix][iy][ip] > bound_max)
6668 var[ix][iy][ip] = bound_max;
6669 }
6670
6671 /* Free... */
6672 free(help);
6673}
6674
6675/*****************************************************************************/
6676
6678 const ctl_t *ctl,
6679 const clim_t *clim,
6680 met_t *met) {
6681
6682 /* Check parameters... */
6683 if (ctl->met_cape != 1)
6684 return;
6685
6686 /* Set timer... */
6687 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
6688 LOG(2, "Calculate CAPE...");
6689
6690 /* Vertical spacing (about 100 m)... */
6691 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
6692
6693 /* Loop over columns... */
6694#pragma omp parallel for default(shared) collapse(2)
6695 for (int ix = 0; ix < met->nx; ix++)
6696 for (int iy = 0; iy < met->ny; iy++) {
6697
6698 /* Get potential temperature and water vapor at lowest 50 hPa... */
6699 int n = 0;
6700 double h2o = 0, t, theta = 0;
6701 double pbot = MIN(met->ps[ix][iy], met->p[0]);
6702 double ptop = pbot - 50.;
6703 for (int ip = 0; ip < met->np; ip++) {
6704 if (met->p[ip] <= pbot) {
6705 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
6706 h2o += met->h2o[ix][iy][ip];
6707 n++;
6708 }
6709 if (met->p[ip] < ptop && n > 0)
6710 break;
6711 }
6712 theta /= n;
6713 h2o /= n;
6714
6715 /* Cannot compute anything if water vapor is missing... */
6716 met->plcl[ix][iy] = NAN;
6717 met->plfc[ix][iy] = NAN;
6718 met->pel[ix][iy] = NAN;
6719 met->cape[ix][iy] = NAN;
6720 met->cin[ix][iy] = NAN;
6721 if (h2o <= 0)
6722 continue;
6723
6724 /* Find lifted condensation level (LCL)... */
6725 ptop = P(20.);
6726 pbot = met->ps[ix][iy];
6727 do {
6728 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
6729 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
6730 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
6731 ptop = met->plcl[ix][iy];
6732 else
6733 pbot = met->plcl[ix][iy];
6734 } while (pbot - ptop > 0.1);
6735
6736 /* Calculate CIN up to LCL... */
6738 double dcape, dz, h2o_env, t_env;
6739 double p = met->ps[ix][iy];
6740 met->cape[ix][iy] = met->cin[ix][iy] = 0;
6741 do {
6742 dz = dz0 * TVIRT(t, h2o);
6743 p /= pfac;
6744 t = theta / pow(1000. / p, 0.286);
6745 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6746 &t_env, ci, cw, 1);
6747 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6748 &h2o_env, ci, cw, 0);
6749 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6750 TVIRT(t_env, h2o_env) * dz;
6751 if (dcape < 0)
6752 met->cin[ix][iy] += fabsf((float) dcape);
6753 } while (p > met->plcl[ix][iy]);
6754
6755 /* Calculate level of free convection (LFC), equilibrium level (EL),
6756 and convective available potential energy (CAPE)... */
6757 dcape = 0;
6758 p = met->plcl[ix][iy];
6759 t = theta / pow(1000. / p, 0.286);
6760 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
6761 do {
6762 dz = dz0 * TVIRT(t, h2o);
6763 p /= pfac;
6764 t -= lapse_rate(t, h2o) * dz;
6765 double psat = PSAT(t);
6766 h2o = psat / (p - (1. - EPS) * psat);
6767 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6768 &t_env, ci, cw, 1);
6769 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6770 &h2o_env, ci, cw, 0);
6771 double dcape_old = dcape;
6772 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6773 TVIRT(t_env, h2o_env) * dz;
6774 if (dcape > 0) {
6775 met->cape[ix][iy] += (float) dcape;
6776 if (!isfinite(met->plfc[ix][iy]))
6777 met->plfc[ix][iy] = (float) p;
6778 } else if (dcape_old > 0)
6779 met->pel[ix][iy] = (float) p;
6780 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
6781 met->cin[ix][iy] += fabsf((float) dcape);
6782 } while (p > ptop);
6783
6784 /* Check results... */
6785 if (!isfinite(met->plfc[ix][iy]))
6786 met->cin[ix][iy] = NAN;
6787 }
6788}
6789
6790/*****************************************************************************/
6791
6793 met_t *met) {
6794
6795 /* Set timer... */
6796 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
6797 LOG(2, "Calculate cloud data...");
6798
6799 /* Thresholds for cloud detection... */
6800 const double ccmin = 0.01, cwmin = 1e-6;
6801
6802 /* Loop over columns... */
6803#pragma omp parallel for default(shared) collapse(2)
6804 for (int ix = 0; ix < met->nx; ix++)
6805 for (int iy = 0; iy < met->ny; iy++) {
6806
6807 /* Init... */
6808 met->pct[ix][iy] = NAN;
6809 met->pcb[ix][iy] = NAN;
6810 met->cl[ix][iy] = 0;
6811
6812 /* Loop over pressure levels... */
6813 for (int ip = 0; ip < met->np - 1; ip++) {
6814
6815 /* Check pressure... */
6816 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
6817 continue;
6818
6819 /* Check ice water and liquid water content... */
6820 if (met->cc[ix][iy][ip] > ccmin
6821 && (met->iwc[ix][iy][ip] > cwmin
6822 || met->rwc[ix][iy][ip] > cwmin
6823 || met->lwc[ix][iy][ip] > cwmin
6824 || met->swc[ix][iy][ip] > cwmin)) {
6825
6826 /* Get cloud top pressure ... */
6827 met->pct[ix][iy]
6828 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
6829
6830 /* Get cloud bottom pressure ... */
6831 if (!isfinite(met->pcb[ix][iy]))
6832 met->pcb[ix][iy]
6833 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
6834 }
6835
6836 /* Get cloud water... */
6837 met->cl[ix][iy] += (float)
6838 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
6839 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
6840 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
6841 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
6842 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
6843 }
6844 }
6845}
6846
6847/*****************************************************************************/
6848
6850 const ctl_t *ctl,
6851 met_t *met) {
6852
6853 met_t *help;
6854
6855 /* Check parameters... */
6856 if (ctl->met_detrend <= 0)
6857 return;
6858
6859 /* Set timer... */
6860 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
6861 LOG(2, "Detrend meteo data...");
6862
6863 /* Allocate... */
6864 ALLOC(help, met_t, 1);
6865
6866 /* Calculate standard deviation... */
6867 const double sigma = ctl->met_detrend / 2.355;
6868 const double tssq = 2. * SQR(sigma);
6869
6870 /* Calculate box size in latitude... */
6871 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
6872 sy = MIN(MAX(1, sy), met->ny / 2);
6873
6874 /* Calculate background... */
6875#pragma omp parallel for default(shared) collapse(2)
6876 for (int ix = 0; ix < met->nx; ix++) {
6877 for (int iy = 0; iy < met->ny; iy++) {
6878
6879 /* Calculate Cartesian coordinates... */
6880 double x0[3];
6881 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
6882
6883 /* Calculate box size in longitude... */
6884 int sx =
6885 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
6886 fabs(met->lon[1] - met->lon[0]));
6887 sx = MIN(MAX(1, sx), met->nx / 2);
6888
6889 /* Init... */
6890 float wsum = 0;
6891 for (int ip = 0; ip < met->np; ip++) {
6892 help->t[ix][iy][ip] = 0;
6893 help->u[ix][iy][ip] = 0;
6894 help->v[ix][iy][ip] = 0;
6895 help->w[ix][iy][ip] = 0;
6896 }
6897
6898 /* Loop over neighboring grid points... */
6899 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
6900 int ix3 = ix2;
6901 if (ix3 < 0)
6902 ix3 += met->nx;
6903 else if (ix3 >= met->nx)
6904 ix3 -= met->nx;
6905 for (int iy2 = MAX(iy - sy, 0);
6906 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
6907
6908 /* Calculate Cartesian coordinates... */
6909 double x1[3];
6910 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
6911
6912 /* Calculate weighting factor... */
6913 const float w = (float) exp(-DIST2(x0, x1) / tssq);
6914
6915 /* Add data... */
6916 wsum += w;
6917 for (int ip = 0; ip < met->np; ip++) {
6918 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
6919 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
6920 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
6921 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
6922 }
6923 }
6924 }
6925
6926 /* Normalize... */
6927 for (int ip = 0; ip < met->np; ip++) {
6928 help->t[ix][iy][ip] /= wsum;
6929 help->u[ix][iy][ip] /= wsum;
6930 help->v[ix][iy][ip] /= wsum;
6931 help->w[ix][iy][ip] /= wsum;
6932 }
6933 }
6934 }
6935
6936 /* Subtract background... */
6937#pragma omp parallel for default(shared) collapse(3)
6938 for (int ix = 0; ix < met->nx; ix++)
6939 for (int iy = 0; iy < met->ny; iy++)
6940 for (int ip = 0; ip < met->np; ip++) {
6941 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
6942 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
6943 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
6944 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
6945 }
6946
6947 /* Free... */
6948 free(help);
6949}
6950
6951/*****************************************************************************/
6952
6954 met_t *met) {
6955
6956 /* Set timer... */
6957 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
6958 LOG(2, "Extrapolate meteo data...");
6959
6960 /* Loop over columns... */
6961#pragma omp parallel for default(shared) collapse(2)
6962 for (int ix = 0; ix < met->nx; ix++)
6963 for (int iy = 0; iy < met->ny; iy++) {
6964
6965 /* Find lowest valid data point... */
6966 int ip0;
6967 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
6968 if (!isfinite(met->t[ix][iy][ip0])
6969 || !isfinite(met->u[ix][iy][ip0])
6970 || !isfinite(met->v[ix][iy][ip0])
6971 || !isfinite(met->w[ix][iy][ip0]))
6972 break;
6973
6974 /* Extrapolate... */
6975 for (int ip = ip0; ip >= 0; ip--) {
6976 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
6977 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
6978 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
6979 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
6980 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
6981 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
6982 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
6983 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
6984 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
6985 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
6986 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
6987 }
6988 }
6989}
6990
6991/*****************************************************************************/
6992
6994 const ctl_t *ctl,
6995 met_t *met) {
6996
6997 float *help;
6998
6999 double logp[EP];
7000
7001 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
7002
7003 /* Set timer... */
7004 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
7005 LOG(2, "Calculate geopotential heights...");
7006
7007 /* Allocate... */
7008 ALLOC(help, float,
7009 EX * EY * EP);
7010
7011 /* Calculate log pressure... */
7012#pragma omp parallel for default(shared)
7013 for (int ip = 0; ip < met->np; ip++)
7014 logp[ip] = log(met->p[ip]);
7015
7016 /* Apply hydrostatic equation to calculate geopotential heights... */
7017#pragma omp parallel for default(shared) collapse(2)
7018 for (int ix = 0; ix < met->nx; ix++)
7019 for (int iy = 0; iy < met->ny; iy++) {
7020
7021 /* Get surface height and pressure... */
7022 const double zs = met->zs[ix][iy];
7023 const double lnps = log(met->ps[ix][iy]);
7024
7025 /* Get temperature and water vapor at the surface... */
7026 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
7027 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
7028 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
7029 const double h2os =
7030 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
7031 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
7032
7033 /* Upper part of profile... */
7034 met->z[ix][iy][ip0 + 1]
7035 = (float) (zs +
7036 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
7037 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
7038 for (int ip = ip0 + 2; ip < met->np; ip++)
7039 met->z[ix][iy][ip]
7040 = (float) (met->z[ix][iy][ip - 1] +
7041 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
7042 met->h2o[ix][iy][ip - 1], logp[ip],
7043 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7044
7045 /* Lower part of profile... */
7046 met->z[ix][iy][ip0]
7047 = (float) (zs +
7048 ZDIFF(lnps, ts, h2os, logp[ip0],
7049 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
7050 for (int ip = ip0 - 1; ip >= 0; ip--)
7051 met->z[ix][iy][ip]
7052 = (float) (met->z[ix][iy][ip + 1] +
7053 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
7054 met->h2o[ix][iy][ip + 1], logp[ip],
7055 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7056 }
7057
7058 /* Check control parameters... */
7059 if (dx == 0 || dy == 0)
7060 return;
7061
7062 /* Default smoothing parameters... */
7063 if (dx < 0 || dy < 0) {
7064 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
7065 dx = 3;
7066 dy = 2;
7067 } else {
7068 dx = 6;
7069 dy = 4;
7070 }
7071 }
7072
7073 /* Calculate weights for smoothing... */
7074 float ws[dx + 1][dy + 1];
7075#pragma omp parallel for default(shared) collapse(2)
7076 for (int ix = 0; ix <= dx; ix++)
7077 for (int iy = 0; iy < dy; iy++)
7078 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
7079 * (1.0f - (float) iy / (float) dy);
7080
7081 /* Copy data... */
7082#pragma omp parallel for default(shared) collapse(3)
7083 for (int ix = 0; ix < met->nx; ix++)
7084 for (int iy = 0; iy < met->ny; iy++)
7085 for (int ip = 0; ip < met->np; ip++)
7086 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
7087
7088 /* Horizontal smoothing... */
7089#pragma omp parallel for default(shared) collapse(3)
7090 for (int ip = 0; ip < met->np; ip++)
7091 for (int ix = 0; ix < met->nx; ix++)
7092 for (int iy = 0; iy < met->ny; iy++) {
7093 float res = 0, wsum = 0;
7094 int iy0 = MAX(iy - dy + 1, 0);
7095 int iy1 = MIN(iy + dy - 1, met->ny - 1);
7096 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
7097 int ix3 = ix2;
7098 if (ix3 < 0)
7099 ix3 += met->nx;
7100 else if (ix3 >= met->nx)
7101 ix3 -= met->nx;
7102 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
7103 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
7104 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
7105 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
7106 wsum += w;
7107 }
7108 }
7109 if (wsum > 0)
7110 met->z[ix][iy][ip] = res / wsum;
7111 else
7112 met->z[ix][iy][ip] = NAN;
7113 }
7114
7115 /* Free... */
7116 free(help);
7117}
7118
7119/*****************************************************************************/
7120
7122 const char *filename,
7123 const int ncid,
7124 const ctl_t *ctl,
7125 met_t *met) {
7126
7127 char levname[LEN], tstr[10];
7128
7129 double rtime = 0, r, r2;
7130
7131 int varid, year2, mon2, day2, hour2, min2, sec2,
7132 year, mon, day, hour, min, sec;
7133
7134 size_t np;
7135
7136 /* Set timer... */
7137 SELECT_TIMER("READ_MET_GRID", "INPUT", NVTX_READ);
7138 LOG(2, "Read meteo grid information...");
7139
7140 /* MPTRAC meteo files... */
7141 if (ctl->met_clams == 0) {
7142
7143 /* Get time from filename... */
7144 met->time = time_from_filename(filename, 16);
7145
7146 /* Check time information from data file... */
7147 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7148 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
7149 NC(nc_get_var_double(ncid, varid, &rtime));
7150 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
7151 WARN("Time information in meteo file does not match filename!");
7152 } else
7153 WARN("Time information in meteo file is missing!");
7154 }
7155
7156 /* CLaMS meteo files... */
7157 else {
7158
7159 /* Read time from file... */
7160 NC_GET_DOUBLE("time", &rtime, 0);
7161
7162 /* Get time from filename (considering the century)... */
7163 if (rtime < 0)
7164 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
7165 else
7166 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
7167 year = atoi(tstr);
7168 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
7169 mon = atoi(tstr);
7170 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
7171 day = atoi(tstr);
7172 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
7173 hour = atoi(tstr);
7174 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
7175 }
7176
7177 /* Check time... */
7178 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7179 || day < 1 || day > 31 || hour < 0 || hour > 23)
7180 ERRMSG("Cannot read time from filename!");
7181 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
7182 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7183 met->time, year2, mon2, day2, hour2, min2);
7184
7185 /* Get grid dimensions... */
7186 NC_INQ_DIM("lon", &met->nx, 2, EX);
7187 LOG(2, "Number of longitudes: %d", met->nx);
7188
7189 NC_INQ_DIM("lat", &met->ny, 2, EY);
7190 LOG(2, "Number of latitudes: %d", met->ny);
7191
7192 int dimid2;
7193 sprintf(levname, "lev");
7194 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7195 sprintf(levname, "plev");
7196 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7197 sprintf(levname, "hybrid");
7198
7199 NC_INQ_DIM(levname, &met->np, 1, EP);
7200 if (met->np == 1) {
7201 sprintf(levname, "lev_2");
7202 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR) {
7203 sprintf(levname, "plev");
7204 NC(nc_inq_dimid(ncid, levname, &dimid2));
7205 }
7206 NC(nc_inq_dimlen(ncid, dimid2, &np));
7207 met->np = (int) np;
7208 }
7209 LOG(2, "Number of levels: %d", met->np);
7210 if (met->np < 2 || met->np > EP)
7211 ERRMSG("Number of levels out of range!");
7212
7213 /* Read longitudes and latitudes... */
7214 NC_GET_DOUBLE("lon", met->lon, 1);
7215 LOG(2, "Longitudes: %g, %g ... %g deg",
7216 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7217 NC_GET_DOUBLE("lat", met->lat, 1);
7218 LOG(2, "Latitudes: %g, %g ... %g deg",
7219 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7220
7221 /* Check grid spacing... */
7222 for (int ix = 2; ix < met->nx; ix++)
7223 if (fabs
7224 (fabs(met->lon[ix] - met->lon[ix - 1]) -
7225 fabs(met->lon[1] - met->lon[0])) > 0.001)
7226 ERRMSG("No regular grid spacing in longitudes!");
7227 for (int iy = 2; iy < met->ny; iy++)
7228 if (fabs
7229 (fabs(met->lat[iy] - met->lat[iy - 1]) -
7230 fabs(met->lat[1] - met->lat[0])) > 0.001) {
7231 WARN("No regular grid spacing in latitudes!");
7232 break;
7233 }
7234
7235 /* Read pressure levels... */
7236 if (ctl->met_np <= 0) {
7237 NC_GET_DOUBLE(levname, met->p, 1);
7238 for (int ip = 0; ip < met->np; ip++)
7239 met->p[ip] /= 100.;
7240 LOG(2, "Altitude levels: %g, %g ... %g km",
7241 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7242 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7243 met->p[0], met->p[1], met->p[met->np - 1]);
7244 }
7245
7246 /* Read hybrid levels... */
7247 if (strcasecmp(levname, "hybrid") == 0)
7248 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
7249}
7250
7251/*****************************************************************************/
7252
7254 const int ncid,
7255 const ctl_t *ctl,
7256 met_t *met) {
7257
7258 /* Set timer... */
7259 SELECT_TIMER("READ_MET_LEVELS", "INPUT", NVTX_READ);
7260 LOG(2, "Read level data...");
7261
7262 /* Read temperature... */
7263 if (!read_met_nc_3d(ncid, "t", "T", "temp", "TEMP", ctl, met, met->t, 1.0))
7264 ERRMSG("Cannot read temperature!");
7265
7266 /* Read horizontal wind and vertical velocity... */
7267 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, met->u, 1.0))
7268 ERRMSG("Cannot read zonal wind!");
7269 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, met->v, 1.0))
7270 ERRMSG("Cannot read meridional wind!");
7271 if (!read_met_nc_3d
7272 (ncid, "w", "W", "omega", "OMEGA", ctl, met, met->w, 0.01f))
7273 WARN("Cannot read vertical velocity!");
7274
7275 /* Read water vapor... */
7276 if (!ctl->met_relhum) {
7277 if (!read_met_nc_3d
7278 (ncid, "q", "Q", "sh", "SH", ctl, met, met->h2o, (float) (MA / MH2O)))
7279 WARN("Cannot read specific humidity!");
7280 } else {
7281 if (!read_met_nc_3d
7282 (ncid, "rh", "RH", NULL, NULL, ctl, met, met->h2o, 0.01f))
7283 WARN("Cannot read relative humidity!");
7284#pragma omp parallel for default(shared) collapse(2)
7285 for (int ix = 0; ix < met->nx; ix++)
7286 for (int iy = 0; iy < met->ny; iy++)
7287 for (int ip = 0; ip < met->np; ip++) {
7288 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
7289 met->h2o[ix][iy][ip] =
7290 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
7291 }
7292 }
7293
7294 /* Read ozone... */
7295 if (!read_met_nc_3d
7296 (ncid, "o3", "O3", NULL, NULL, ctl, met, met->o3, (float) (MA / MO3)))
7297 WARN("Cannot read ozone data!");
7298
7299 /* Read cloud data... */
7300 if (!read_met_nc_3d
7301 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, met->lwc, 1.0))
7302 WARN("Cannot read cloud liquid water content!");
7303 if (!read_met_nc_3d
7304 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, met->rwc, 1.0))
7305 WARN("Cannot read cloud rain water content!");
7306 if (!read_met_nc_3d
7307 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, met->iwc, 1.0))
7308 WARN("Cannot read cloud ice water content!");
7309 if (!read_met_nc_3d
7310 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, met->swc, 1.0))
7311 WARN("Cannot read cloud snow water content!");
7312 if (!read_met_nc_3d(ncid, "cc", "CC", NULL, NULL, ctl, met, met->cc, 1.0))
7313 WARN("Cannot read cloud cover!");
7314
7315 /* Read zeta and zeta_dot... */
7316 if (!read_met_nc_3d
7317 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, met->zetal, 1.0))
7318 WARN("Cannot read ZETA!");
7319 if (!read_met_nc_3d
7320 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
7321 NULL, ctl, met, met->zeta_dotl, 0.00001157407f))
7322 WARN("Cannot read ZETA_DOT!");
7323
7324 /* Store velocities on model levels... */
7325 if (ctl->met_vert_coord != 0) {
7326 for (int ix = 0; ix < met->nx; ix++)
7327 for (int iy = 0; iy < met->ny; iy++)
7328 for (int ip = 0; ip < met->np; ip++) {
7329 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
7330 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
7331 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
7332 }
7333
7334 /* Save number of model levels... */
7335 met->npl = met->np;
7336 }
7337
7338 /* Get pressure on model levels... */
7339 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
7340
7341 /* Read 3-D pressure field... */
7342 if (ctl->met_vert_coord == 1) {
7343 if (!read_met_nc_3d
7344 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, met->pl,
7345 0.01f))
7346 if (!read_met_nc_3d
7347 (ncid, "press", "PRESS", NULL, NULL, ctl, met, met->pl, 1.0))
7348 ERRMSG("Cannot read pressure on model levels!");
7349 }
7350
7351 /* Use a and b coefficients for full levels... */
7352 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
7353
7354 /* Grid level coefficients... */
7355 double hyam[EP], hybm[EP];
7356
7357 /* Read coefficients... */
7358 if (ctl->met_vert_coord == 2) {
7359 int varid;
7360 NC_GET_DOUBLE("hyam", hyam, 1);
7361 NC_GET_DOUBLE("hybm", hybm, 1);
7362 }
7363
7364 /* Use control parameters... */
7365 else if (ctl->met_vert_coord == 3) {
7366
7367 /* Check number of levels... */
7368 if (met->np != ctl->met_nlev)
7369 ERRMSG("Mismatch in number of model levels!");
7370
7371 /* Copy parameters... */
7372 for (int ip = 0; ip < met->np; ip++) {
7373 hyam[ip] = ctl->met_lev_hyam[ip];
7374 hybm[ip] = ctl->met_lev_hybm[ip];
7375 }
7376 }
7377
7378 /* Calculate pressure... */
7379 for (int ix = 0; ix < met->nx; ix++)
7380 for (int iy = 0; iy < met->ny; iy++)
7381 for (int ip = 0; ip < met->np; ip++)
7382 met->pl[ix][iy][ip] =
7383 (float) (hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy]);
7384 }
7385
7386 /* Use a and b coefficients for half levels... */
7387 else if (ctl->met_vert_coord == 4) {
7388
7389 /* Grid level coefficients... */
7390 double hyam[EP], hybm[EP];
7391
7392 /* Use control parameters... */
7393 for (int ip = 0; ip < met->np + 1; ip++) {
7394 hyam[ip] = ctl->met_lev_hyam[ip];
7395 hybm[ip] = ctl->met_lev_hybm[ip];
7396 }
7397
7398 /* Check number of levels... */
7399 if (met->np + 1 != ctl->met_nlev)
7400 ERRMSG("Mismatch in number of model levels!");
7401
7402 /* Calculate pressure... */
7403#pragma omp parallel for default(shared) collapse(2)
7404 for (int ix = 0; ix < met->nx; ix++)
7405 for (int iy = 0; iy < met->ny; iy++)
7406 for (int ip = 0; ip < met->np; ip++) {
7407 double p0 = hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy];
7408 double p1 = hyam[ip + 1] / 100. + hybm[ip + 1] * met->ps[ix][iy];
7409 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
7410 }
7411 }
7412
7413 /* Check ordering of pressure levels... */
7414 for (int ix = 0; ix < met->nx; ix++)
7415 for (int iy = 0; iy < met->ny; iy++)
7416 for (int ip = 1; ip < met->np; ip++)
7417 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
7418 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
7419 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
7420 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
7421 ERRMSG("Pressure profiles are not monotonic!");
7422 }
7423
7424 /* Interpolate from model levels to pressure levels... */
7425 if (ctl->met_np > 0) {
7426
7427 /* Interpolate variables... */
7428 read_met_ml2pl(ctl, met, met->t, "T");
7429 read_met_ml2pl(ctl, met, met->u, "U");
7430 read_met_ml2pl(ctl, met, met->v, "V");
7431 read_met_ml2pl(ctl, met, met->w, "W");
7432 read_met_ml2pl(ctl, met, met->h2o, "H2O");
7433 read_met_ml2pl(ctl, met, met->o3, "O3");
7434 read_met_ml2pl(ctl, met, met->lwc, "LWC");
7435 read_met_ml2pl(ctl, met, met->rwc, "RWC");
7436 read_met_ml2pl(ctl, met, met->iwc, "IWC");
7437 read_met_ml2pl(ctl, met, met->swc, "SWC");
7438 read_met_ml2pl(ctl, met, met->cc, "CC");
7439
7440 /* Set new pressure levels... */
7441 met->np = ctl->met_np;
7442 for (int ip = 0; ip < met->np; ip++)
7443 met->p[ip] = ctl->met_p[ip];
7444 }
7445
7446 /* Check ordering of pressure levels... */
7447 for (int ip = 1; ip < met->np; ip++)
7448 if (met->p[ip - 1] < met->p[ip])
7449 ERRMSG("Pressure levels must be descending!");
7450}
7451
7452/*****************************************************************************/
7453
7455 const ctl_t *ctl,
7456 const met_t *met,
7457 float var[EX][EY][EP],
7458 const char *varname) {
7459
7460 double aux[EP], p[EP];
7461
7462 /* Set timer... */
7463 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
7464 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
7465
7466 /* Loop over columns... */
7467#pragma omp parallel for default(shared) private(aux,p) collapse(2)
7468 for (int ix = 0; ix < met->nx; ix++)
7469 for (int iy = 0; iy < met->ny; iy++) {
7470
7471 /* Copy pressure profile... */
7472 for (int ip = 0; ip < met->np; ip++)
7473 p[ip] = met->pl[ix][iy][ip];
7474
7475 /* Interpolate... */
7476 for (int ip = 0; ip < ctl->met_np; ip++) {
7477 double pt = ctl->met_p[ip];
7478 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
7479 pt = p[0];
7480 else if ((pt > p[met->np - 1] && p[1] > p[0])
7481 || (pt < p[met->np - 1] && p[1] < p[0]))
7482 pt = p[met->np - 1];
7483 int ip2 = locate_irr(p, met->np, pt);
7484 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
7485 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
7486 }
7487
7488 /* Copy data... */
7489 for (int ip = 0; ip < ctl->met_np; ip++)
7490 var[ix][iy][ip] = (float) aux[ip];
7491 }
7492}
7493
7494/*****************************************************************************/
7495
7497 const ctl_t *ctl,
7498 met_t *met) {
7499
7500 /* Check parameters... */
7501 if (ctl->advect_vert_coord != 1)
7502 return;
7503
7504 /* Set timer... */
7505 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
7506 LOG(2, "Make zeta profiles monotone...");
7507
7508 /* Create monotone zeta profiles... */
7509#pragma omp parallel for default(shared) collapse(2)
7510 for (int i = 0; i < met->nx; i++)
7511 for (int j = 0; j < met->ny; j++) {
7512 int k = 1;
7513
7514 while (k < met->npl) { /* Check if there is an inversion at level k... */
7515 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
7516 /* Find the upper level k+l over the inversion... */
7517 int l = 0;
7518 do {
7519 l++;
7520 }
7521 while ((met->zetal[i][j][k - 1] >=
7522 met->zetal[i][j][k + l]) & (k + l < met->npl));
7523
7524 /* Interpolate linear between the top and bottom
7525 of the inversion... */
7526 float s =
7527 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
7528 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
7529
7530 for (int m = k; m < k + l; m++) {
7531 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
7532 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
7533 }
7534
7535 /* Search for more inversions above the last inversion ... */
7536 k = k + l;
7537 } else {
7538 k++;
7539 }
7540 }
7541 }
7542
7543 /* Create monotone pressure profiles... */
7544#pragma omp parallel for default(shared) collapse(2)
7545 for (int i = 0; i < met->nx; i++)
7546 for (int j = 0; j < met->ny; j++) {
7547 int k = 1;
7548
7549 while (k < met->npl) { /* Check if there is an inversion at level k... */
7550 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
7551
7552 /* Find the upper level k+l over the inversion... */
7553 int l = 0;
7554 do {
7555 l++;
7556 }
7557 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
7558 met->npl));
7559
7560 /* Interpolate linear between the top and bottom
7561 of the inversion... */
7562 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
7563 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
7564
7565 for (int m = k; m < k + l; m++) {
7566 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
7567 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
7568 }
7569
7570 /* Search for more inversions above the last inversion ... */
7571 k += l;
7572 } else {
7573 k++;
7574 }
7575 }
7576 }
7577}
7578
7579/*****************************************************************************/
7580
7582 const char *filename,
7583 const ctl_t *ctl,
7584 const clim_t *clim,
7585 met_t *met) {
7586
7587 int ncid;
7588
7589 /* Open netCDF file... */
7590 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7591 WARN("Cannot open file!");
7592 return 0;
7593 }
7594
7595 /* Read coordinates of meteo data... */
7596 read_met_grid(filename, ncid, ctl, met);
7597
7598 /* Read surface data... */
7599 read_met_surface(ncid, ctl, met);
7600
7601 /* Read meteo data on vertical levels... */
7602 read_met_levels(ncid, ctl, met);
7603
7604 /* Extrapolate data for lower boundary... */
7606
7607 /* Fix polar winds... */
7609
7610 /* Create periodic boundary conditions... */
7611 read_met_periodic(met);
7612
7613 /* Downsampling... */
7614 read_met_sample(ctl, met);
7615
7616 /* Calculate geopotential heights... */
7617 read_met_geopot(ctl, met);
7618
7619 /* Calculate potential vorticity... */
7620 read_met_pv(met);
7621
7622 /* Calculate boundary layer data... */
7623 read_met_pbl(ctl, met);
7624
7625 /* Calculate tropopause data... */
7626 read_met_tropo(ctl, clim, met);
7627
7628 /* Calculate cloud properties... */
7629 read_met_cloud(met);
7630
7631 /* Calculate convective available potential energy... */
7632 read_met_cape(ctl, clim, met);
7633
7634 /* Calculate total column ozone... */
7635 read_met_ozone(met);
7636
7637 /* Detrending... */
7638 read_met_detrend(ctl, met);
7639
7640 /* Check meteo data and smooth zeta profiles ... */
7641 read_met_monotonize(ctl, met);
7642
7643 /* Close file... */
7644 NC(nc_close(ncid));
7645
7646 /* Return success... */
7647 return 1;
7648}
7649
7650/*****************************************************************************/
7651
7653 const int ncid,
7654 const char *varname,
7655 const char *varname2,
7656 const char *varname3,
7657 const char *varname4,
7658 const char *varname5,
7659 const char *varname6,
7660 const ctl_t *ctl,
7661 const met_t *met,
7662 float dest[EX][EY],
7663 const float scl,
7664 const int init) {
7665
7666 char varsel[LEN];
7667
7668 float offset, scalfac;
7669
7670 int varid;
7671
7672 /* Check if variable exists... */
7673 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7674 sprintf(varsel, "%s", varname);
7675 else if (varname2 != NULL
7676 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7677 sprintf(varsel, "%s", varname2);
7678 else if (varname3 != NULL
7679 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7680 sprintf(varsel, "%s", varname3);
7681 else if (varname4 != NULL
7682 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7683 sprintf(varsel, "%s", varname4);
7684 else if (varname5 != NULL
7685 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
7686 sprintf(varsel, "%s", varname5);
7687 else if (varname6 != NULL
7688 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
7689 sprintf(varsel, "%s", varname6);
7690 else
7691 return 0;
7692
7693 /* Read packed data... */
7694 if (ctl->met_nc_scale
7695 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
7696 && nc_get_att_float(ncid, varid, "scale_factor",
7697 &scalfac) == NC_NOERR) {
7698
7699 /* Allocate... */
7700 short *help;
7701 ALLOC(help, short,
7702 EX * EY * EP);
7703
7704 /* Read fill value and missing value... */
7705 short fillval, missval;
7706 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7707 fillval = 0;
7708 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
7709 missval = 0;
7710
7711 /* Write info... */
7712 LOG(2, "Read 2-D variable: %s"
7713 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
7714 varsel, fillval, missval, scalfac, offset);
7715
7716 /* Read data... */
7717 NC(nc_get_var_short(ncid, varid, help));
7718
7719 /* Check meteo data layout... */
7720 if (ctl->met_convention != 0)
7721 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
7722
7723 /* Copy and check data... */
7724#pragma omp parallel for default(shared) num_threads(12)
7725 for (int ix = 0; ix < met->nx; ix++)
7726 for (int iy = 0; iy < met->ny; iy++) {
7727 if (init)
7728 dest[ix][iy] = 0;
7729 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
7730 if ((fillval == 0 || aux != fillval)
7731 && (missval == 0 || aux != missval)
7732 && fabsf(aux * scalfac + offset) < 1e14f)
7733 dest[ix][iy] += scl * (aux * scalfac + offset);
7734 else
7735 dest[ix][iy] = NAN;
7736 }
7737
7738 /* Free... */
7739 free(help);
7740 }
7741
7742 /* Unpacked data... */
7743 else {
7744
7745 /* Allocate... */
7746 float *help;
7747 ALLOC(help, float,
7748 EX * EY);
7749
7750 /* Read fill value and missing value... */
7751 float fillval, missval;
7752 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7753 fillval = 0;
7754 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7755 missval = 0;
7756
7757 /* Write info... */
7758 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
7759 varsel, fillval, missval);
7760
7761 /* Read data... */
7762 NC(nc_get_var_float(ncid, varid, help));
7763
7764 /* Check meteo data layout... */
7765 if (ctl->met_convention == 0) {
7766
7767 /* Copy and check data (ordering: lat, lon)... */
7768#pragma omp parallel for default(shared) num_threads(12)
7769 for (int ix = 0; ix < met->nx; ix++)
7770 for (int iy = 0; iy < met->ny; iy++) {
7771 if (init)
7772 dest[ix][iy] = 0;
7773 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
7774 if ((fillval == 0 || aux != fillval)
7775 && (missval == 0 || aux != missval)
7776 && fabsf(aux) < 1e14f)
7777 dest[ix][iy] += scl * aux;
7778 else
7779 dest[ix][iy] = NAN;
7780 }
7781
7782 } else {
7783
7784 /* Copy and check data (ordering: lon, lat)... */
7785#pragma omp parallel for default(shared) num_threads(12)
7786 for (int iy = 0; iy < met->ny; iy++)
7787 for (int ix = 0; ix < met->nx; ix++) {
7788 if (init)
7789 dest[ix][iy] = 0;
7790 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
7791 if ((fillval == 0 || aux != fillval)
7792 && (missval == 0 || aux != missval)
7793 && fabsf(aux) < 1e14f)
7794 dest[ix][iy] += scl * aux;
7795 else
7796 dest[ix][iy] = NAN;
7797 }
7798 }
7799
7800 /* Free... */
7801 free(help);
7802 }
7803
7804 /* Return... */
7805 return 1;
7806}
7807
7808/*****************************************************************************/
7809
7811 const int ncid,
7812 const char *varname,
7813 const char *varname2,
7814 const char *varname3,
7815 const char *varname4,
7816 const ctl_t *ctl,
7817 const met_t *met,
7818 float dest[EX][EY][EP],
7819 const float scl) {
7820
7821 char varsel[LEN];
7822
7823 float offset, scalfac;
7824
7825 int varid;
7826
7827 /* Check if variable exists... */
7828 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7829 sprintf(varsel, "%s", varname);
7830 else if (varname2 != NULL
7831 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7832 sprintf(varsel, "%s", varname2);
7833 else if (varname3 != NULL
7834 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7835 sprintf(varsel, "%s", varname3);
7836 else if (varname4 != NULL
7837 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7838 sprintf(varsel, "%s", varname4);
7839 else
7840 return 0;
7841
7842 /* Read packed data... */
7843 if (ctl->met_nc_scale
7844 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
7845 && nc_get_att_float(ncid, varid, "scale_factor",
7846 &scalfac) == NC_NOERR) {
7847
7848 /* Allocate... */
7849 short *help;
7850 ALLOC(help, short,
7851 EX * EY * EP);
7852
7853 /* Read fill value and missing value... */
7854 short fillval, missval;
7855 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7856 fillval = 0;
7857 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
7858 missval = 0;
7859
7860 /* Write info... */
7861 LOG(2, "Read 3-D variable: %s "
7862 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
7863 varsel, fillval, missval, scalfac, offset);
7864
7865 /* Read data... */
7866 NC(nc_get_var_short(ncid, varid, help));
7867
7868 /* Check meteo data layout... */
7869 if (ctl->met_convention != 0)
7870 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
7871
7872 /* Copy and check data... */
7873#pragma omp parallel for default(shared) num_threads(12)
7874 for (int ix = 0; ix < met->nx; ix++)
7875 for (int iy = 0; iy < met->ny; iy++)
7876 for (int ip = 0; ip < met->np; ip++) {
7877 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7878 if ((fillval == 0 || aux != fillval)
7879 && (missval == 0 || aux != missval)
7880 && fabsf(aux * scalfac + offset) < 1e14f)
7881 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
7882 else
7883 dest[ix][iy][ip] = NAN;
7884 }
7885
7886 /* Free... */
7887 free(help);
7888 }
7889
7890 /* Unpacked data... */
7891 else {
7892
7893 /* Allocate... */
7894 float *help;
7895 ALLOC(help, float,
7896 EX * EY * EP);
7897
7898 /* Read fill value and missing value... */
7899 float fillval, missval;
7900 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7901 fillval = 0;
7902 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7903 missval = 0;
7904
7905 /* Write info... */
7906 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
7907 varsel, fillval, missval);
7908
7909 /* Read data... */
7910 NC(nc_get_var_float(ncid, varid, help));
7911
7912 /* Check meteo data layout... */
7913 if (ctl->met_convention == 0) {
7914
7915 /* Copy and check data (ordering: lev, lat, lon)... */
7916#pragma omp parallel for default(shared) num_threads(12)
7917 for (int ix = 0; ix < met->nx; ix++)
7918 for (int iy = 0; iy < met->ny; iy++)
7919 for (int ip = 0; ip < met->np; ip++) {
7920 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7921 if ((fillval == 0 || aux != fillval)
7922 && (missval == 0 || aux != missval)
7923 && fabsf(aux) < 1e14f)
7924 dest[ix][iy][ip] = scl * aux;
7925 else
7926 dest[ix][iy][ip] = NAN;
7927 }
7928
7929 } else {
7930
7931 /* Copy and check data (ordering: lon, lat, lev)... */
7932#pragma omp parallel for default(shared) num_threads(12)
7933 for (int ip = 0; ip < met->np; ip++)
7934 for (int iy = 0; iy < met->ny; iy++)
7935 for (int ix = 0; ix < met->nx; ix++) {
7936 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7937 if ((fillval == 0 || aux != fillval)
7938 && (missval == 0 || aux != missval)
7939 && fabsf(aux) < 1e14f)
7940 dest[ix][iy][ip] = scl * aux;
7941 else
7942 dest[ix][iy][ip] = NAN;
7943 }
7944 }
7945
7946 /* Free... */
7947 free(help);
7948 }
7949
7950 /* Return... */
7951 return 1;
7952}
7953
7954/*****************************************************************************/
7955
7957 const ctl_t *ctl,
7958 met_t *met) {
7959
7960 /* Set timer... */
7961 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
7962 LOG(2, "Calculate planetary boundary layer...");
7963
7964 /* Convert PBL height from meteo file to pressure... */
7965 if (ctl->met_pbl == 1) {
7966
7967 /* Loop over grid points... */
7968#pragma omp parallel for default(shared) collapse(2)
7969 for (int ix = 0; ix < met->nx; ix++)
7970 for (int iy = 0; iy < met->ny; iy++) {
7971
7972 /* Get pressure at top of PBL... */
7973 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
7974 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
7975 met->pbl[ix][iy] =
7976 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
7977 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
7978 }
7979 }
7980
7981 /* Determine PBL based on Richardson number... */
7982 else if (ctl->met_pbl == 2) {
7983
7984 /* Parameters used to estimate the height of the PBL
7985 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
7986 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
7987
7988 /* Loop over grid points... */
7989#pragma omp parallel for default(shared) collapse(2)
7990 for (int ix = 0; ix < met->nx; ix++)
7991 for (int iy = 0; iy < met->ny; iy++) {
7992
7993 /* Set bottom level of PBL... */
7994 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
7995
7996 /* Find lowest level near the bottom... */
7997 int ip;
7998 for (ip = 1; ip < met->np; ip++)
7999 if (met->p[ip] < pbl_bot)
8000 break;
8001
8002 /* Get near surface data... */
8003 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
8004 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
8005 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
8006
8007 /* Init... */
8008 double rib_old = 0;
8009
8010 /* Loop over levels... */
8011 for (; ip < met->np; ip++) {
8012
8013 /* Get squared horizontal wind speed... */
8014 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
8015 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
8016 vh2 = MAX(vh2, SQR(umin));
8017
8018 /* Calculate bulk Richardson number... */
8019 const double rib =
8020 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
8021 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
8022 met->h2o[ix][iy][ip]) - tvs) / vh2;
8023
8024 /* Check for critical value... */
8025 if (rib >= rib_crit) {
8026 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
8027 rib, met->p[ip], rib_crit));
8028 if (met->pbl[ix][iy] > pbl_bot)
8029 met->pbl[ix][iy] = (float) pbl_bot;
8030 break;
8031 }
8032
8033 /* Save Richardson number... */
8034 rib_old = rib;
8035 }
8036 }
8037 }
8038
8039 /* Determine PBL based on potential temperature... */
8040 if (ctl->met_pbl == 3) {
8041
8042 /* Parameters used to estimate the height of the PBL
8043 (following HYSPLIT model)... */
8044 const double dtheta = 2.0, zmin = 0.1;
8045
8046 /* Loop over grid points... */
8047#pragma omp parallel for default(shared) collapse(2)
8048 for (int ix = 0; ix < met->nx; ix++)
8049 for (int iy = 0; iy < met->ny; iy++) {
8050
8051 /* Potential temperature at the surface... */
8052 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
8053
8054 /* Find topmost level where theta exceeds surface value by 2 K... */
8055 int ip;
8056 for (ip = met->np - 2; ip > 0; ip--)
8057 if (met->p[ip] >= 300.)
8058 if (met->p[ip] > met->ps[ix][iy]
8059 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
8060 break;
8061
8062 /* Interpolate... */
8063 met->pbl[ix][iy]
8064 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
8065 met->p[ip + 1],
8066 THETA(met->p[ip], met->t[ix][iy][ip]),
8067 met->p[ip], theta0 + dtheta));
8068
8069 /* Check minimum value... */
8070 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
8071 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
8072 met->pbl[ix][iy] = (float) pbl_min;
8073 }
8074 }
8075
8076 /* Loop over grid points... */
8077#pragma omp parallel for default(shared) collapse(2)
8078 for (int ix = 0; ix < met->nx; ix++)
8079 for (int iy = 0; iy < met->ny; iy++) {
8080
8081 /* Check minimum value... */
8082 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
8083 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
8084
8085 /* Check maximum value... */
8086 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
8087 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
8088 }
8089}
8090
8091/*****************************************************************************/
8092
8094 met_t *met) {
8095
8096 /* Set timer... */
8097 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
8098 LOG(2, "Apply periodic boundary conditions...");
8099
8100 /* Check longitudes... */
8101 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
8102 + met->lon[1] - met->lon[0] - 360) < 0.01))
8103 return;
8104
8105 /* Increase longitude counter... */
8106 if ((++met->nx) >= EX)
8107 ERRMSG("Cannot create periodic boundary conditions!");
8108
8109 /* Set longitude... */
8110 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
8111
8112 /* Loop over latitudes and pressure levels... */
8113#pragma omp parallel for default(shared)
8114 for (int iy = 0; iy < met->ny; iy++) {
8115 met->ps[met->nx - 1][iy] = met->ps[0][iy];
8116 met->zs[met->nx - 1][iy] = met->zs[0][iy];
8117 met->ts[met->nx - 1][iy] = met->ts[0][iy];
8118 met->us[met->nx - 1][iy] = met->us[0][iy];
8119 met->vs[met->nx - 1][iy] = met->vs[0][iy];
8120 met->ess[met->nx - 1][iy] = met->ess[0][iy];
8121 met->nss[met->nx - 1][iy] = met->nss[0][iy];
8122 met->shf[met->nx - 1][iy] = met->shf[0][iy];
8123 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
8124 met->sst[met->nx - 1][iy] = met->sst[0][iy];
8125 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
8126 met->cape[met->nx - 1][iy] = met->cape[0][iy];
8127 met->cin[met->nx - 1][iy] = met->cin[0][iy];
8128 for (int ip = 0; ip < met->np; ip++) {
8129 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
8130 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
8131 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
8132 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
8133 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
8134 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
8135 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
8136 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
8137 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
8138 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
8139 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
8140 }
8141 for (int ip = 0; ip < met->npl; ip++) {
8142 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
8143 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
8144 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
8145 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
8146 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
8147 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
8148 }
8149 }
8150}
8151
8152/*****************************************************************************/
8153
8155 met_t *met) {
8156
8157 /* Set timer... */
8158 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
8159 LOG(2, "Apply fix for polar winds...");
8160
8161 /* Check latitudes... */
8162 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
8163 return;
8164
8165 /* Loop over hemispheres... */
8166 for (int ihem = 0; ihem < 2; ihem++) {
8167
8168 /* Set latitude indices... */
8169 int i89 = 1, i90 = 0, sign = 1;
8170 if (ihem == 1) {
8171 i89 = met->ny - 2;
8172 i90 = met->ny - 1;
8173 }
8174 if (met->lat[i90] < 0)
8175 sign = -1;
8176
8177 /* Look-up table of cosinus and sinus... */
8178 double clon[EX], slon[EX];
8179#pragma omp parallel for default(shared)
8180 for (int ix = 0; ix < met->nx; ix++) {
8181 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
8182 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
8183 }
8184
8185 /* Loop over levels... */
8186#pragma omp parallel for default(shared)
8187 for (int ip = 0; ip < met->np; ip++) {
8188
8189 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
8190 double vel89x = 0, vel89y = 0;
8191 for (int ix = 0; ix < met->nx; ix++) {
8192 vel89x +=
8193 (met->u[ix][i89][ip] * clon[ix] -
8194 met->v[ix][i89][ip] * slon[ix]) / met->nx;
8195 vel89y +=
8196 (met->u[ix][i89][ip] * slon[ix] +
8197 met->v[ix][i89][ip] * clon[ix]) / met->nx;
8198 }
8199
8200 /* Replace 90 degree winds by 89 degree mean... */
8201 for (int ix = 0; ix < met->nx; ix++) {
8202 met->u[ix][i90][ip]
8203 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
8204 met->v[ix][i90][ip]
8205 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
8206 }
8207 }
8208 }
8209}
8210
8211/*****************************************************************************/
8212
8214 met_t *met) {
8215
8216 double pows[EP];
8217
8218 /* Set timer... */
8219 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
8220 LOG(2, "Calculate potential vorticity...");
8221
8222 /* Set powers... */
8223#pragma omp parallel for default(shared)
8224 for (int ip = 0; ip < met->np; ip++)
8225 pows[ip] = pow(1000. / met->p[ip], 0.286);
8226
8227 /* Loop over grid points... */
8228#pragma omp parallel for default(shared)
8229 for (int ix = 0; ix < met->nx; ix++) {
8230
8231 /* Set indices... */
8232 const int ix0 = MAX(ix - 1, 0);
8233 const int ix1 = MIN(ix + 1, met->nx - 1);
8234
8235 /* Loop over grid points... */
8236 for (int iy = 0; iy < met->ny; iy++) {
8237
8238 /* Set indices... */
8239 const int iy0 = MAX(iy - 1, 0);
8240 const int iy1 = MIN(iy + 1, met->ny - 1);
8241
8242 /* Set auxiliary variables... */
8243 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
8244 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
8245 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
8246 const double c0 = cos(DEG2RAD(met->lat[iy0]));
8247 const double c1 = cos(DEG2RAD(met->lat[iy1]));
8248 const double cr = cos(DEG2RAD(latr));
8249 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
8250
8251 /* Loop over grid points... */
8252 for (int ip = 0; ip < met->np; ip++) {
8253
8254 /* Get gradients in longitude... */
8255 const double dtdx
8256 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
8257 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
8258
8259 /* Get gradients in latitude... */
8260 const double dtdy
8261 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
8262 const double dudy
8263 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
8264
8265 /* Set indices... */
8266 const int ip0 = MAX(ip - 1, 0);
8267 const int ip1 = MIN(ip + 1, met->np - 1);
8268
8269 /* Get gradients in pressure... */
8270 double dtdp, dudp, dvdp;
8271 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
8272 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
8273 if (ip != ip0 && ip != ip1) {
8274 double denom = dp0 * dp1 * (dp0 + dp1);
8275 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
8276 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
8277 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
8278 / denom;
8279 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
8280 - dp1 * dp1 * met->u[ix][iy][ip0]
8281 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
8282 / denom;
8283 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
8284 - dp1 * dp1 * met->v[ix][iy][ip0]
8285 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
8286 / denom;
8287 } else {
8288 const double denom = dp0 + dp1;
8289 dtdp =
8290 (met->t[ix][iy][ip1] * pows[ip1] -
8291 met->t[ix][iy][ip0] * pows[ip0]) / denom;
8292 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
8293 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
8294 }
8295
8296 /* Calculate PV... */
8297 met->pv[ix][iy][ip] = (float)
8298 (1e6 * G0 *
8299 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
8300 }
8301 }
8302 }
8303
8304 /* Fix for polar regions... */
8305#pragma omp parallel for default(shared)
8306 for (int ix = 0; ix < met->nx; ix++)
8307 for (int ip = 0; ip < met->np; ip++) {
8308 met->pv[ix][0][ip]
8309 = met->pv[ix][1][ip]
8310 = met->pv[ix][2][ip];
8311 met->pv[ix][met->ny - 1][ip]
8312 = met->pv[ix][met->ny - 2][ip]
8313 = met->pv[ix][met->ny - 3][ip];
8314 }
8315}
8316
8317/*****************************************************************************/
8318
8320 met_t *met) {
8321
8322 /* Set timer... */
8323 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
8324 LOG(2, "Calculate total column ozone...");
8325
8326 /* Loop over columns... */
8327#pragma omp parallel for default(shared) collapse(2)
8328 for (int ix = 0; ix < met->nx; ix++)
8329 for (int iy = 0; iy < met->ny; iy++) {
8330
8331 /* Integrate... */
8332 double cd = 0;
8333 for (int ip = 1; ip < met->np; ip++)
8334 if (met->p[ip - 1] <= met->ps[ix][iy]) {
8335 const double vmr =
8336 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
8337 const double dp = met->p[ip - 1] - met->p[ip];
8338 cd += vmr * MO3 / MA * dp * 1e2 / G0;
8339 }
8340
8341 /* Convert to Dobson units... */
8342 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
8343 }
8344}
8345
8346/*****************************************************************************/
8347
8349 const ctl_t *ctl,
8350 met_t *met) {
8351
8352 met_t *help;
8353
8354 /* Check parameters... */
8355 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
8356 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
8357 return;
8358
8359 /* Set timer... */
8360 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
8361 LOG(2, "Downsampling of meteo data...");
8362
8363 /* Allocate... */
8364 ALLOC(help, met_t, 1);
8365
8366 /* Copy data... */
8367 help->nx = met->nx;
8368 help->ny = met->ny;
8369 help->np = met->np;
8370 memcpy(help->lon, met->lon, sizeof(met->lon));
8371 memcpy(help->lat, met->lat, sizeof(met->lat));
8372 memcpy(help->p, met->p, sizeof(met->p));
8373
8374 /* Smoothing... */
8375 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
8376 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
8377 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
8378 help->ps[ix][iy] = 0;
8379 help->zs[ix][iy] = 0;
8380 help->ts[ix][iy] = 0;
8381 help->us[ix][iy] = 0;
8382 help->vs[ix][iy] = 0;
8383 help->ess[ix][iy] = 0;
8384 help->nss[ix][iy] = 0;
8385 help->shf[ix][iy] = 0;
8386 help->lsm[ix][iy] = 0;
8387 help->sst[ix][iy] = 0;
8388 help->pbl[ix][iy] = 0;
8389 help->cape[ix][iy] = 0;
8390 help->cin[ix][iy] = 0;
8391 help->t[ix][iy][ip] = 0;
8392 help->u[ix][iy][ip] = 0;
8393 help->v[ix][iy][ip] = 0;
8394 help->w[ix][iy][ip] = 0;
8395 help->h2o[ix][iy][ip] = 0;
8396 help->o3[ix][iy][ip] = 0;
8397 help->lwc[ix][iy][ip] = 0;
8398 help->rwc[ix][iy][ip] = 0;
8399 help->iwc[ix][iy][ip] = 0;
8400 help->swc[ix][iy][ip] = 0;
8401 help->cc[ix][iy][ip] = 0;
8402 float wsum = 0;
8403 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
8404 ix2++) {
8405 int ix3 = ix2;
8406 if (ix3 < 0)
8407 ix3 += met->nx;
8408 else if (ix3 >= met->nx)
8409 ix3 -= met->nx;
8410
8411 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
8412 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
8413 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
8414 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
8415 float w = (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
8416 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
8417 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
8418 help->ps[ix][iy] += w * met->ps[ix3][iy2];
8419 help->zs[ix][iy] += w * met->zs[ix3][iy2];
8420 help->ts[ix][iy] += w * met->ts[ix3][iy2];
8421 help->us[ix][iy] += w * met->us[ix3][iy2];
8422 help->vs[ix][iy] += w * met->vs[ix3][iy2];
8423 help->ess[ix][iy] += w * met->ess[ix3][iy2];
8424 help->nss[ix][iy] += w * met->nss[ix3][iy2];
8425 help->shf[ix][iy] += w * met->shf[ix3][iy2];
8426 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
8427 help->sst[ix][iy] += w * met->sst[ix3][iy2];
8428 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
8429 help->cape[ix][iy] += w * met->cape[ix3][iy2];
8430 help->cin[ix][iy] += w * met->cin[ix3][iy2];
8431 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
8432 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
8433 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
8434 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
8435 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
8436 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
8437 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
8438 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
8439 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
8440 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
8441 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
8442 wsum += w;
8443 }
8444 }
8445 help->ps[ix][iy] /= wsum;
8446 help->zs[ix][iy] /= wsum;
8447 help->ts[ix][iy] /= wsum;
8448 help->us[ix][iy] /= wsum;
8449 help->vs[ix][iy] /= wsum;
8450 help->ess[ix][iy] /= wsum;
8451 help->nss[ix][iy] /= wsum;
8452 help->shf[ix][iy] /= wsum;
8453 help->lsm[ix][iy] /= wsum;
8454 help->sst[ix][iy] /= wsum;
8455 help->pbl[ix][iy] /= wsum;
8456 help->cape[ix][iy] /= wsum;
8457 help->cin[ix][iy] /= wsum;
8458 help->t[ix][iy][ip] /= wsum;
8459 help->u[ix][iy][ip] /= wsum;
8460 help->v[ix][iy][ip] /= wsum;
8461 help->w[ix][iy][ip] /= wsum;
8462 help->h2o[ix][iy][ip] /= wsum;
8463 help->o3[ix][iy][ip] /= wsum;
8464 help->lwc[ix][iy][ip] /= wsum;
8465 help->rwc[ix][iy][ip] /= wsum;
8466 help->iwc[ix][iy][ip] /= wsum;
8467 help->swc[ix][iy][ip] /= wsum;
8468 help->cc[ix][iy][ip] /= wsum;
8469 }
8470 }
8471 }
8472
8473 /* Downsampling... */
8474 met->nx = 0;
8475 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
8476 met->lon[met->nx] = help->lon[ix];
8477 met->ny = 0;
8478 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
8479 met->lat[met->ny] = help->lat[iy];
8480 met->ps[met->nx][met->ny] = help->ps[ix][iy];
8481 met->zs[met->nx][met->ny] = help->zs[ix][iy];
8482 met->ts[met->nx][met->ny] = help->ts[ix][iy];
8483 met->us[met->nx][met->ny] = help->us[ix][iy];
8484 met->vs[met->nx][met->ny] = help->vs[ix][iy];
8485 met->ess[met->nx][met->ny] = help->ess[ix][iy];
8486 met->nss[met->nx][met->ny] = help->nss[ix][iy];
8487 met->shf[met->nx][met->ny] = help->shf[ix][iy];
8488 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
8489 met->sst[met->nx][met->ny] = help->sst[ix][iy];
8490 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
8491 met->cape[met->nx][met->ny] = help->cape[ix][iy];
8492 met->cin[met->nx][met->ny] = help->cin[ix][iy];
8493 met->np = 0;
8494 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
8495 met->p[met->np] = help->p[ip];
8496 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
8497 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
8498 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
8499 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
8500 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
8501 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
8502 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
8503 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
8504 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
8505 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
8506 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
8507 met->np++;
8508 }
8509 met->ny++;
8510 }
8511 met->nx++;
8512 }
8513
8514 /* Free... */
8515 free(help);
8516}
8517
8518/*****************************************************************************/
8519
8521 const int ncid,
8522 const ctl_t *ctl,
8523 met_t *met) {
8524
8525 /* Set timer... */
8526 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
8527 LOG(2, "Read surface data...");
8528
8529 /* Read surface pressure... */
8530 if (read_met_nc_2d
8531 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, met->ps, 1.0f,
8532 1)) {
8533 for (int ix = 0; ix < met->nx; ix++)
8534 for (int iy = 0; iy < met->ny; iy++)
8535 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8536 } else
8537 if (!read_met_nc_2d
8538 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, met->ps, 0.01f,
8539 1)) {
8540 WARN("Cannot not read surface pressure data (use lowest level)!");
8541 for (int ix = 0; ix < met->nx; ix++)
8542 for (int iy = 0; iy < met->ny; iy++)
8543 met->ps[ix][iy]
8544 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
8545 }
8546
8547 /* MPTRAC meteo data... */
8548 if (ctl->met_clams == 0) {
8549
8550 /* Read geopotential height at the surface... */
8551 if (!read_met_nc_2d
8552 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, met->zs,
8553 (float) (1. / (1000. * G0)), 1))
8554 if (!read_met_nc_2d
8555 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, met->zs,
8556 (float) (1. / 1000.), 1))
8557 WARN("Cannot read surface geopotential height!");
8558 }
8559
8560 /* CLaMS meteo data... */
8561 else {
8562
8563 /* Read geopotential height at the surface
8564 (use lowermost level of 3-D data field)... */
8565 float *help;
8566 ALLOC(help, float,
8567 EX * EY * EP);
8568 memcpy(help, met->pl, sizeof(met->pl));
8569 if (!read_met_nc_3d
8570 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
8571 (float) (1e-3 / G0)))
8572 ERRMSG("Cannot read geopotential height!");
8573 for (int ix = 0; ix < met->nx; ix++)
8574 for (int iy = 0; iy < met->ny; iy++)
8575 met->zs[ix][iy] = met->pl[ix][iy][0];
8576 memcpy(met->pl, help, sizeof(met->pl));
8577 free(help);
8578 }
8579
8580 /* Read temperature at the surface... */
8581 if (!read_met_nc_2d
8582 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, met->ts, 1.0, 1))
8583 WARN("Cannot read surface temperature!");
8584
8585 /* Read zonal wind at the surface... */
8586 if (!read_met_nc_2d
8587 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, met->us,
8588 1.0, 1))
8589 WARN("Cannot read surface zonal wind!");
8590
8591 /* Read meridional wind at the surface... */
8592 if (!read_met_nc_2d
8593 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, met->vs,
8594 1.0, 1))
8595 WARN("Cannot read surface meridional wind!");
8596
8597 /* Read eastward turbulent surface stress... */
8598 if (!read_met_nc_2d
8599 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, met->ess, 1.0,
8600 1))
8601 WARN("Cannot read eastward turbulent surface stress!");
8602
8603 /* Read northward turbulent surface stress... */
8604 if (!read_met_nc_2d
8605 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, met->nss, 1.0,
8606 1))
8607 WARN("Cannot read nothward turbulent surface stress!");
8608
8609 /* Read surface sensible heat flux... */
8610 if (!read_met_nc_2d
8611 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, met->shf, 1.0,
8612 1))
8613 WARN("Cannot read surface sensible heat flux!");
8614
8615 /* Read land-sea mask... */
8616 if (!read_met_nc_2d
8617 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, met->lsm, 1.0,
8618 1))
8619 WARN("Cannot read land-sea mask!");
8620
8621 /* Read sea surface temperature... */
8622 if (!read_met_nc_2d
8623 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, met->sst,
8624 1.0, 1))
8625 WARN("Cannot read sea surface temperature!");
8626
8627 /* Read PBL... */
8628 if (ctl->met_pbl == 0)
8629 if (!read_met_nc_2d
8630 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
8631 0.01f, 1))
8632 WARN("Cannot read planetary boundary layer pressure!");
8633 if (ctl->met_pbl == 1)
8634 if (!read_met_nc_2d
8635 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
8636 0.001f, 1))
8637 WARN("Cannot read planetary boundary layer height!");
8638
8639 /* Read CAPE... */
8640 if (ctl->met_cape == 0)
8641 if (!read_met_nc_2d
8642 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, met->cape,
8643 1.0, 1))
8644 WARN("Cannot read CAPE!");
8645
8646 /* Read CIN... */
8647 if (ctl->met_cape == 0)
8648 if (!read_met_nc_2d
8649 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, met->cin,
8650 1.0, 1))
8651 WARN("Cannot read convective inhibition!");
8652}
8653
8654/*****************************************************************************/
8655
8657 const ctl_t *ctl,
8658 const clim_t *clim,
8659 met_t *met) {
8660
8661 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
8662 th2[200], z[EP], z2[200];
8663
8664 /* Set timer... */
8665 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
8666 LOG(2, "Calculate tropopause...");
8667
8668 /* Get altitude and pressure profiles... */
8669#pragma omp parallel for default(shared)
8670 for (int iz = 0; iz < met->np; iz++)
8671 z[iz] = Z(met->p[iz]);
8672#pragma omp parallel for default(shared)
8673 for (int iz = 0; iz <= 190; iz++) {
8674 z2[iz] = 4.5 + 0.1 * iz;
8675 p2[iz] = P(z2[iz]);
8676 }
8677
8678 /* Do not calculate tropopause... */
8679 if (ctl->met_tropo == 0)
8680#pragma omp parallel for default(shared) collapse(2)
8681 for (int ix = 0; ix < met->nx; ix++)
8682 for (int iy = 0; iy < met->ny; iy++)
8683 met->pt[ix][iy] = NAN;
8684
8685 /* Use tropopause climatology... */
8686 else if (ctl->met_tropo == 1) {
8687#pragma omp parallel for default(shared) collapse(2)
8688 for (int ix = 0; ix < met->nx; ix++)
8689 for (int iy = 0; iy < met->ny; iy++)
8690 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
8691 }
8692
8693 /* Use cold point... */
8694 else if (ctl->met_tropo == 2) {
8695
8696 /* Loop over grid points... */
8697#pragma omp parallel for default(shared) private(t,t2) collapse(2)
8698 for (int ix = 0; ix < met->nx; ix++)
8699 for (int iy = 0; iy < met->ny; iy++) {
8700
8701 /* Interpolate temperature profile... */
8702 for (int iz = 0; iz < met->np; iz++)
8703 t[iz] = met->t[ix][iy][iz];
8704 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
8705
8706 /* Find minimum... */
8707 int iz = (int) gsl_stats_min_index(t2, 1, 171);
8708 if (iz > 0 && iz < 170)
8709 met->pt[ix][iy] = (float) p2[iz];
8710 else
8711 met->pt[ix][iy] = NAN;
8712 }
8713 }
8714
8715 /* Use WMO definition... */
8716 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
8717
8718 /* Loop over grid points... */
8719#pragma omp parallel for default(shared) private(t,t2) collapse(2)
8720 for (int ix = 0; ix < met->nx; ix++)
8721 for (int iy = 0; iy < met->ny; iy++) {
8722
8723 /* Interpolate temperature profile... */
8724 int iz;
8725 for (iz = 0; iz < met->np; iz++)
8726 t[iz] = met->t[ix][iy][iz];
8727 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
8728
8729 /* Find 1st tropopause... */
8730 met->pt[ix][iy] = NAN;
8731 for (iz = 0; iz <= 170; iz++) {
8732 int found = 1;
8733 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
8734 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
8735 found = 0;
8736 break;
8737 }
8738 if (found) {
8739 if (iz > 0 && iz < 170)
8740 met->pt[ix][iy] = (float) p2[iz];
8741 break;
8742 }
8743 }
8744
8745 /* Find 2nd tropopause... */
8746 if (ctl->met_tropo == 4) {
8747 met->pt[ix][iy] = NAN;
8748 for (; iz <= 170; iz++) {
8749 int found = 1;
8750 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
8751 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
8752 found = 0;
8753 break;
8754 }
8755 if (found)
8756 break;
8757 }
8758 for (; iz <= 170; iz++) {
8759 int found = 1;
8760 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
8761 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
8762 found = 0;
8763 break;
8764 }
8765 if (found) {
8766 if (iz > 0 && iz < 170)
8767 met->pt[ix][iy] = (float) p2[iz];
8768 break;
8769 }
8770 }
8771 }
8772 }
8773 }
8774
8775 /* Use dynamical tropopause... */
8776 else if (ctl->met_tropo == 5) {
8777
8778 /* Loop over grid points... */
8779#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
8780 for (int ix = 0; ix < met->nx; ix++)
8781 for (int iy = 0; iy < met->ny; iy++) {
8782
8783 /* Interpolate potential vorticity profile... */
8784 for (int iz = 0; iz < met->np; iz++)
8785 pv[iz] = met->pv[ix][iy][iz];
8786 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
8787
8788 /* Interpolate potential temperature profile... */
8789 for (int iz = 0; iz < met->np; iz++)
8790 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
8791 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
8792
8793 /* Find dynamical tropopause... */
8794 met->pt[ix][iy] = NAN;
8795 for (int iz = 0; iz <= 170; iz++)
8796 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
8797 || th2[iz] >= ctl->met_tropo_theta) {
8798 if (iz > 0 && iz < 170)
8799 met->pt[ix][iy] = (float) p2[iz];
8800 break;
8801 }
8802 }
8803 }
8804
8805 else
8806 ERRMSG("Cannot calculate tropopause!");
8807
8808 /* Interpolate temperature, geopotential height, and water vapor... */
8809#pragma omp parallel for default(shared) collapse(2)
8810 for (int ix = 0; ix < met->nx; ix++)
8811 for (int iy = 0; iy < met->ny; iy++) {
8812 double h2ot, tt, zt;
8814 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
8815 met->lat[iy], &tt, ci, cw, 1);
8816 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
8817 met->lat[iy], &zt, ci, cw, 0);
8818 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
8819 met->lat[iy], &h2ot, ci, cw, 0);
8820 met->tt[ix][iy] = (float) tt;
8821 met->zt[ix][iy] = (float) zt;
8822 met->h2ot[ix][iy] = (float) h2ot;
8823 }
8824}
8825
8826/*****************************************************************************/
8827
8829 const char *filename,
8830 const ctl_t *ctl,
8831 double *rt,
8832 double *rz,
8833 double *rlon,
8834 double *rlat,
8835 double *robs,
8836 int *nobs) {
8837
8838 /* Write info... */
8839 LOG(1, "Read observation data: %s", filename);
8840
8841 /* Read data... */
8842 if (ctl->obs_type == 0)
8843 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
8844 else if (ctl->obs_type == 1)
8845 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
8846 else
8847 ERRMSG("Set OBS_TYPE to 0 or 1!");
8848
8849 /* Check time... */
8850 for (int i = 1; i < *nobs; i++)
8851 if (rt[i] < rt[i - 1])
8852 ERRMSG("Time must be ascending!");
8853
8854 /* Write info... */
8855 int n = *nobs;
8856 double mini, maxi;
8857 LOG(2, "Number of observations: %d", *nobs);
8858 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
8859 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8860 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
8861 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
8862 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
8863 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
8864 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
8865 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
8866 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
8867 LOG(2, "Observation range: %g ... %g", mini, maxi);
8868}
8869
8870/*****************************************************************************/
8871
8873 const char *filename,
8874 double *rt,
8875 double *rz,
8876 double *rlon,
8877 double *rlat,
8878 double *robs,
8879 int *nobs) {
8880
8881 /* Open observation data file... */
8882 FILE *in;
8883 if (!(in = fopen(filename, "r")))
8884 ERRMSG("Cannot open file!");
8885
8886 /* Read observations... */
8887 char line[LEN];
8888 while (fgets(line, LEN, in))
8889 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
8890 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
8891 if ((++(*nobs)) >= NOBS)
8892 ERRMSG("Too many observations!");
8893
8894 /* Close observation data file... */
8895 fclose(in);
8896}
8897
8898/*****************************************************************************/
8899
8901 const char *filename,
8902 double *rt,
8903 double *rz,
8904 double *rlon,
8905 double *rlat,
8906 double *robs,
8907 int *nobs) {
8908
8909 int ncid, varid;
8910
8911 /* Open netCDF file... */
8912 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8913 ERRMSG("Cannot open file!");
8914
8915 /* Read the observations from the NetCDF file... */
8916 NC_INQ_DIM("nobs", nobs, 1, NOBS);
8917 NC_GET_DOUBLE("time", rt, 1);
8918 NC_GET_DOUBLE("alt", rz, 1);
8919 NC_GET_DOUBLE("lon", rlon, 1);
8920 NC_GET_DOUBLE("lat", rlat, 1);
8921 NC_GET_DOUBLE("obs", robs, 1);
8922
8923 /* Close file... */
8924 NC(nc_close(ncid));
8925}
8926
8927/*****************************************************************************/
8928
8930 const char *filename,
8931 int argc,
8932 char *argv[],
8933 const char *varname,
8934 const int arridx,
8935 const char *defvalue,
8936 char *value) {
8937
8938 FILE *in = NULL;
8939
8940 char fullname1[LEN], fullname2[LEN], rval[LEN];
8941
8942 int contain = 0, i;
8943
8944 /* Open file... */
8945 if (filename[strlen(filename) - 1] != '-')
8946 if (!(in = fopen(filename, "r")))
8947 ERRMSG("Cannot open file!");
8948
8949 /* Set full variable name... */
8950 if (arridx >= 0) {
8951 sprintf(fullname1, "%s[%d]", varname, arridx);
8952 sprintf(fullname2, "%s[*]", varname);
8953 } else {
8954 sprintf(fullname1, "%s", varname);
8955 sprintf(fullname2, "%s", varname);
8956 }
8957
8958 /* Read data... */
8959 if (in != NULL) {
8960 char dummy[LEN], line[LEN], rvarname[LEN];
8961 while (fgets(line, LEN, in)) {
8962 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
8963 if (strcasecmp(rvarname, fullname1) == 0 ||
8964 strcasecmp(rvarname, fullname2) == 0) {
8965 contain = 1;
8966 break;
8967 }
8968 }
8969 }
8970 for (i = 1; i < argc - 1; i++)
8971 if (strcasecmp(argv[i], fullname1) == 0 ||
8972 strcasecmp(argv[i], fullname2) == 0) {
8973 sprintf(rval, "%s", argv[i + 1]);
8974 contain = 1;
8975 break;
8976 }
8977
8978 /* Close file... */
8979 if (in != NULL)
8980 fclose(in);
8981
8982 /* Check for missing variables... */
8983 if (!contain) {
8984 if (strlen(defvalue) > 0)
8985 sprintf(rval, "%s", defvalue);
8986 else
8987 ERRMSG("Missing variable %s!\n", fullname1);
8988 }
8989
8990 /* Write info... */
8991 LOG(1, "%s = %s", fullname1, rval);
8992
8993 /* Return values... */
8994 if (value != NULL)
8995 sprintf(value, "%s", rval);
8996 return atof(rval);
8997}
8998
8999/*****************************************************************************/
9000
9001double sedi(
9002 const double p,
9003 const double T,
9004 const double rp,
9005 const double rhop) {
9006
9007 /* Convert particle radius from microns to m... */
9008 const double rp_help = rp * 1e-6;
9009
9010 /* Density of dry air [kg / m^3]... */
9011 const double rho = RHO(p, T);
9012
9013 /* Dynamic viscosity of air [kg / (m s)]... */
9014 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
9015
9016 /* Thermal velocity of an air molecule [m / s]... */
9017 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
9018
9019 /* Mean free path of an air molecule [m]... */
9020 const double lambda = 2. * eta / (rho * v);
9021
9022 /* Knudsen number for air (dimensionless)... */
9023 const double K = lambda / rp_help;
9024
9025 /* Cunningham slip-flow correction (dimensionless)... */
9026 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
9027
9028 /* Sedimentation velocity [m / s]... */
9029 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
9030}
9031
9032/*****************************************************************************/
9033
9035 const double *x,
9036 const double *y,
9037 const int n,
9038 const double *x2,
9039 double *y2,
9040 const int n2,
9041 const int method) {
9042
9043 /* Cubic spline interpolation... */
9044 if (method == 1) {
9045
9046 /* Allocate... */
9047 gsl_interp_accel *acc = gsl_interp_accel_alloc();
9048 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
9049
9050 /* Interpolate profile... */
9051 gsl_spline_init(s, x, y, (size_t) n);
9052 for (int i = 0; i < n2; i++)
9053 if (x2[i] <= x[0])
9054 y2[i] = y[0];
9055 else if (x2[i] >= x[n - 1])
9056 y2[i] = y[n - 1];
9057 else
9058 y2[i] = gsl_spline_eval(s, x2[i], acc);
9059
9060 /* Free... */
9061 gsl_spline_free(s);
9062 gsl_interp_accel_free(acc);
9063 }
9064
9065 /* Linear interpolation... */
9066 else {
9067 for (int i = 0; i < n2; i++)
9068 if (x2[i] <= x[0])
9069 y2[i] = y[0];
9070 else if (x2[i] >= x[n - 1])
9071 y2[i] = y[n - 1];
9072 else {
9073 int idx = locate_irr(x, n, x2[i]);
9074 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
9075 }
9076 }
9077}
9078
9079/*****************************************************************************/
9080
9082 const float *data,
9083 const int n) {
9084
9085 if (n <= 0)
9086 return 0;
9087
9088 float mean = 0, var = 0;
9089
9090 for (int i = 0; i < n; ++i) {
9091 mean += data[i];
9092 var += SQR(data[i]);
9093 }
9094
9095 var = var / (float) n - SQR(mean / (float) n);
9096
9097 return (var > 0 ? sqrtf(var) : 0);
9098}
9099
9100/*****************************************************************************/
9101
9103 const double sec,
9104 const double lon,
9105 const double lat) {
9106
9107 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
9108 const double D = sec / 86400 - 0.5;
9109
9110 /* Geocentric apparent ecliptic longitude [rad]... */
9111 const double g = DEG2RAD(357.529 + 0.98560028 * D);
9112 const double q = 280.459 + 0.98564736 * D;
9113 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
9114
9115 /* Mean obliquity of the ecliptic [rad]... */
9116 const double e = DEG2RAD(23.439 - 0.00000036 * D);
9117
9118 /* Declination [rad]... */
9119 const double sindec = sin(e) * sin(L);
9120
9121 /* Right ascension [rad]... */
9122 const double ra = atan2(cos(e) * sin(L), cos(L));
9123
9124 /* Greenwich Mean Sidereal Time [h]... */
9125 const double GMST = 18.697374558 + 24.06570982441908 * D;
9126
9127 /* Local Sidereal Time [h]... */
9128 const double LST = GMST + lon / 15;
9129
9130 /* Hour angle [rad]... */
9131 const double h = LST / 12 * M_PI - ra;
9132
9133 /* Convert latitude... */
9134 const double lat_help = DEG2RAD(lat);
9135
9136 /* Return solar zenith angle [rad]... */
9137 return acos(sin(lat_help) * sindec +
9138 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
9139}
9140
9141/*****************************************************************************/
9142
9144 const int year,
9145 const int mon,
9146 const int day,
9147 const int hour,
9148 const int min,
9149 const int sec,
9150 const double remain,
9151 double *jsec) {
9152
9153 struct tm t0, t1;
9154
9155 t0.tm_year = 100;
9156 t0.tm_mon = 0;
9157 t0.tm_mday = 1;
9158 t0.tm_hour = 0;
9159 t0.tm_min = 0;
9160 t0.tm_sec = 0;
9161
9162 t1.tm_year = year - 1900;
9163 t1.tm_mon = mon - 1;
9164 t1.tm_mday = day;
9165 t1.tm_hour = hour;
9166 t1.tm_min = min;
9167 t1.tm_sec = sec;
9168
9169 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
9170}
9171
9172/*****************************************************************************/
9173
9175 const char *name,
9176 const char *group,
9177 const int output) {
9178
9179 static char names[NTIMER][100], groups[NTIMER][100];
9180
9181 static double rt_name[NTIMER], rt_group[NTIMER],
9182 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
9183
9184 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
9185
9186 /* Get time... */
9187 t1 = omp_get_wtime();
9188 dt = t1 - t0;
9189
9190 /* Add elapsed time to current timers... */
9191 if (iname >= 0) {
9192 rt_name[iname] += dt;
9193 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
9194 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
9195 ct_name[iname]++;
9196 }
9197 if (igroup >= 0)
9198 rt_group[igroup] += t1 - t0;
9199
9200 /* Report timers... */
9201 if (output) {
9202 for (int i = 0; i < nname; i++)
9203 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
9204 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
9205 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
9206 for (int i = 0; i < ngroup; i++)
9207 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
9208 double total = 0.0;
9209 for (int i = 0; i < nname; i++)
9210 total += rt_name[i];
9211 LOG(1, "TIMER_TOTAL = %.3f s", total);
9212 }
9213
9214 /* Identify IDs of next timer... */
9215 for (iname = 0; iname < nname; iname++)
9216 if (strcasecmp(name, names[iname]) == 0)
9217 break;
9218 for (igroup = 0; igroup < ngroup; igroup++)
9219 if (strcasecmp(group, groups[igroup]) == 0)
9220 break;
9221
9222 /* Check whether this is a new timer... */
9223 if (iname >= nname) {
9224 sprintf(names[iname], "%s", name);
9225 if ((++nname) >= NTIMER)
9226 ERRMSG("Too many timers!");
9227 }
9228
9229 /* Check whether this is a new group... */
9230 if (igroup >= ngroup) {
9231 sprintf(groups[igroup], "%s", group);
9232 if ((++ngroup) >= NTIMER)
9233 ERRMSG("Too many groups!");
9234 }
9235
9236 /* Save starting time... */
9237 t0 = t1;
9238}
9239
9240/*****************************************************************************/
9241
9243 const char *filename,
9244 const int offset) {
9245
9246 char tstr[10];
9247
9248 double t;
9249
9250 /* Get time from filename... */
9251 int len = (int) strlen(filename);
9252 sprintf(tstr, "%.4s", &filename[len - offset]);
9253 int year = atoi(tstr);
9254 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
9255 int mon = atoi(tstr);
9256 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
9257 int day = atoi(tstr);
9258 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
9259 int hour = atoi(tstr);
9260 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
9261 int min = atoi(tstr);
9262
9263 /* Check time... */
9264 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
9265 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
9266 ERRMSG("Cannot read time from filename!");
9267
9268 /* Convert time to Julian seconds... */
9269 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
9270
9271 /* Return time... */
9272 return t;
9273}
9274
9275/*****************************************************************************/
9276
9278 const clim_t *clim,
9279 const atm_t *atm,
9280 const int ip) {
9281
9282 /* Get tropopause pressure... */
9283 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
9284
9285 /* Get pressure range... */
9286 const double p1 = pt * 0.866877899;
9287 const double p0 = pt / 0.866877899;
9288
9289 /* Get weighting factor... */
9290 if (atm->p[ip] > p0)
9291 return 1;
9292 else if (atm->p[ip] < p1)
9293 return 0;
9294 else
9295 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
9296}
9297
9298/*****************************************************************************/
9299
9301 const char *filename,
9302 const ctl_t *ctl,
9303 const atm_t *atm,
9304 const double t) {
9305
9306 FILE *out;
9307
9308 /* Set time interval for output... */
9309 const double t0 = t - 0.5 * ctl->dt_mod;
9310 const double t1 = t + 0.5 * ctl->dt_mod;
9311
9312 /* Check if gnuplot output is requested... */
9313 if (ctl->atm_gpfile[0] != '-') {
9314
9315 /* Create gnuplot pipe... */
9316 if (!(out = popen("gnuplot", "w")))
9317 ERRMSG("Cannot create pipe to gnuplot!");
9318
9319 /* Set plot filename... */
9320 fprintf(out, "set out \"%s.png\"\n", filename);
9321
9322 /* Set time string... */
9323 double r;
9324 int year, mon, day, hour, min, sec;
9325 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9326 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
9327 year, mon, day, hour, min);
9328
9329 /* Dump gnuplot file to pipe... */
9330 FILE *in;
9331 if (!(in = fopen(ctl->atm_gpfile, "r")))
9332 ERRMSG("Cannot open file!");
9333 char line[LEN];
9334 while (fgets(line, LEN, in))
9335 fprintf(out, "%s", line);
9336 fclose(in);
9337 }
9338
9339 else {
9340
9341 /* Create file... */
9342 if (!(out = fopen(filename, "w")))
9343 ERRMSG("Cannot create file!");
9344 }
9345
9346 /* Write header... */
9347 fprintf(out,
9348 "# $1 = time [s]\n"
9349 "# $2 = altitude [km]\n"
9350 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
9351 for (int iq = 0; iq < ctl->nq; iq++)
9352 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
9353 ctl->qnt_unit[iq]);
9354 fprintf(out, "\n");
9355
9356 /* Write data... */
9357 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
9358
9359 /* Check time... */
9360 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
9361 continue;
9362
9363 /* Write output... */
9364 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
9365 atm->lon[ip], atm->lat[ip]);
9366 for (int iq = 0; iq < ctl->nq; iq++) {
9367 fprintf(out, " ");
9368 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
9369 fprintf(out, ctl->qnt_format[iq], NAN);
9370 else
9371 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
9372 }
9373 fprintf(out, "\n");
9374 }
9375
9376 /* Close file... */
9377 fclose(out);
9378}
9379
9380/*****************************************************************************/
9381
9383 const char *filename,
9384 const ctl_t *ctl,
9385 const atm_t *atm) {
9386
9387 FILE *out;
9388
9389 /* Create file... */
9390 if (!(out = fopen(filename, "w")))
9391 ERRMSG("Cannot create file!");
9392
9393 /* Write version of binary data... */
9394 int version = 100;
9395 FWRITE(&version, int,
9396 1,
9397 out);
9398
9399 /* Write data... */
9400 FWRITE(&atm->np, int,
9401 1,
9402 out);
9403 FWRITE(atm->time, double,
9404 (size_t) atm->np,
9405 out);
9406 FWRITE(atm->p, double,
9407 (size_t) atm->np,
9408 out);
9409 FWRITE(atm->lon, double,
9410 (size_t) atm->np,
9411 out);
9412 FWRITE(atm->lat, double,
9413 (size_t) atm->np,
9414 out);
9415 for (int iq = 0; iq < ctl->nq; iq++)
9416 FWRITE(atm->q[iq], double,
9417 (size_t) atm->np,
9418 out);
9419
9420 /* Write final flag... */
9421 int final = 999;
9422 FWRITE(&final, int,
9423 1,
9424 out);
9425
9426 /* Close file... */
9427 fclose(out);
9428}
9429
9430/*****************************************************************************/
9431
9433 const char *filename,
9434 const ctl_t *ctl,
9435 const atm_t *atm) {
9436
9437 int tid, pid, ncid, varid;
9438 size_t start[2], count[2];
9439
9440 /* Create file... */
9441 nc_create(filename, NC_NETCDF4, &ncid);
9442
9443 /* Define dimensions... */
9444 NC(nc_def_dim(ncid, "time", 1, &tid));
9445 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9446
9447 /* Define variables and their attributes... */
9448 int dim_ids[2] = { tid, pid };
9449 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9450 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9451 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
9452 ctl->atm_nc_level, 0);
9453 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
9454 ctl->atm_nc_level, 0);
9455 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
9456 ctl->atm_nc_level, 0);
9457 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
9458 for (int iq = 0; iq < ctl->nq; iq++)
9459 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9460 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9461 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9462
9463 /* Define global attributes... */
9464 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9465 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9466
9467 /* End definitions... */
9468 NC(nc_enddef(ncid));
9469
9470 /* Write data... */
9471 NC_PUT_DOUBLE("time", atm->time, 0);
9472 NC_PUT_DOUBLE("LAT", atm->lat, 0);
9473 NC_PUT_DOUBLE("LON", atm->lon, 0);
9474 NC_PUT_DOUBLE("PRESS", atm->p, 0);
9475 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
9476 for (int iq = 0; iq < ctl->nq; iq++)
9477 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9478
9479 /* Close file... */
9480 NC(nc_close(ncid));
9481}
9482
9483/*****************************************************************************/
9484
9486 const char *dirname,
9487 const ctl_t *ctl,
9488 const atm_t *atm,
9489 const double t) {
9490
9491 /* Global Counter... */
9492 static size_t out_cnt = 0;
9493
9494 double r, r_start, r_stop;
9495 int year, mon, day, hour, min, sec;
9496 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
9497 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
9498 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
9499
9500 int ncid, varid, tid, pid, cid;
9501 int dim_ids[2];
9502
9503 /* time, nparc */
9504 size_t start[2];
9505 size_t count[2];
9506
9507 /* Determine start and stop times of calculation... */
9508 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9509 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
9510 &min_start, &sec_start, &r_start);
9511 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
9512 &min_stop, &sec_stop, &r_stop);
9513
9514 sprintf(filename_out, "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc",
9515 dirname,
9516 year_start % 100, mon_start, day_start, hour_start,
9517 year_stop % 100, mon_stop, day_stop, hour_stop);
9518 LOG(1, "Write traj file: %s", filename_out);
9519
9520 /* Define hyperslap for the traj_file... */
9521 start[0] = out_cnt;
9522 start[1] = 0;
9523 count[0] = 1;
9524 count[1] = (size_t) atm->np;
9525
9526 /* Create the file at the first timestep... */
9527 if (out_cnt == 0) {
9528
9529 /* Create file... */
9530 nc_create(filename_out, NC_NETCDF4, &ncid);
9531
9532 /* Define dimensions... */
9533 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
9534 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9535 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
9536 dim_ids[0] = tid;
9537 dim_ids[1] = pid;
9538
9539 /* Define variables and their attributes... */
9540 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9541 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9542 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
9543 ctl->atm_nc_level, 0);
9544 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
9545 ctl->atm_nc_level, 0);
9546 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
9547 ctl->atm_nc_level, 0);
9548 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
9549 ctl->atm_nc_level, 0);
9550 for (int iq = 0; iq < ctl->nq; iq++)
9551 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9552 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9553 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9554
9555 /* Define global attributes... */
9556 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9557 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9558
9559 /* End definitions... */
9560 NC(nc_enddef(ncid));
9561 NC(nc_close(ncid));
9562 }
9563
9564 /* Increment global counter to change hyperslap... */
9565 out_cnt++;
9566
9567 /* Open file... */
9568 NC(nc_open(filename_out, NC_WRITE, &ncid));
9569
9570 /* Write data... */
9571 NC_PUT_DOUBLE("time", atm->time, 1);
9572 NC_PUT_DOUBLE("LAT", atm->lat, 1);
9573 NC_PUT_DOUBLE("LON", atm->lon, 1);
9574 NC_PUT_DOUBLE("PRESS", atm->p, 1);
9575 if (ctl->advect_vert_coord == 1) {
9576 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
9577 } else if (ctl->qnt_zeta >= 0) {
9578 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
9579 }
9580 for (int iq = 0; iq < ctl->nq; iq++)
9581 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
9582
9583 /* Close file... */
9584 NC(nc_close(ncid));
9585
9586 /* At the last time step create the init_fix_YYYYMMDDHH file... */
9587 if ((year == year_stop) && (mon == mon_stop)
9588 && (day == day_stop) && (hour == hour_stop)) {
9589
9590 /* Set filename... */
9591 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
9592 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
9593 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
9594 LOG(1, "Write init file: %s", filename_init);
9595
9596 /* Create file... */
9597 nc_create(filename_init, NC_NETCDF4, &ncid);
9598
9599 /* Define dimensions... */
9600 NC(nc_def_dim(ncid, "time", 1, &tid));
9601 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9602 dim_ids[0] = tid;
9603 dim_ids[1] = pid;
9604
9605 /* Define variables and their attributes... */
9606 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9607 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9608 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
9609 ctl->atm_nc_level, 0);
9610 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
9611 ctl->atm_nc_level, 0);
9612 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
9613 ctl->atm_nc_level, 0);
9614 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
9615 for (int iq = 0; iq < ctl->nq; iq++)
9616 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9617 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9618 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9619
9620 /* Define global attributes... */
9621 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9622 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9623
9624 /* End definitions... */
9625 NC(nc_enddef(ncid));
9626
9627 /* Write data... */
9628 NC_PUT_DOUBLE("time", atm->time, 0);
9629 NC_PUT_DOUBLE("LAT", atm->lat, 0);
9630 NC_PUT_DOUBLE("LON", atm->lon, 0);
9631 NC_PUT_DOUBLE("PRESS", atm->p, 0);
9632 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
9633 for (int iq = 0; iq < ctl->nq; iq++)
9634 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9635
9636 /* Close file... */
9637 NC(nc_close(ncid));
9638 }
9639}
9640
9641/*****************************************************************************/
9642
9644 const char *filename,
9645 const ctl_t *ctl,
9646 const atm_t *atm) {
9647
9648 int ncid, obsid, varid;
9649
9650 size_t start[2], count[2];
9651
9652 /* Create file... */
9653 NC(nc_create(filename, NC_NETCDF4, &ncid));
9654
9655 /* Define dimensions... */
9656 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
9657
9658 /* Define variables and their attributes... */
9659 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
9660 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9661 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
9662 ctl->atm_nc_level, 0);
9663 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
9664 ctl->atm_nc_level, 0);
9665 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
9666 ctl->atm_nc_level, 0);
9667 for (int iq = 0; iq < ctl->nq; iq++)
9668 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
9669 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
9670 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9671
9672 /* Define global attributes... */
9673 NC_PUT_ATT_GLOBAL("featureType", "point");
9674
9675 /* End definitions... */
9676 NC(nc_enddef(ncid));
9677
9678 /* Write data... */
9679 NC_PUT_DOUBLE("time", atm->time, 0);
9680 NC_PUT_DOUBLE("press", atm->p, 0);
9681 NC_PUT_DOUBLE("lon", atm->lon, 0);
9682 NC_PUT_DOUBLE("lat", atm->lat, 0);
9683 for (int iq = 0; iq < ctl->nq; iq++)
9684 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9685
9686 /* Close file... */
9687 NC(nc_close(ncid));
9688}
9689
9690/*****************************************************************************/
9691
9693 const char *filename,
9694 const ctl_t *ctl,
9695 const atm_t *atm,
9696 const double t) {
9697
9698 static FILE *out;
9699
9700 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
9701 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
9702
9703 static int *obscount, ct, cx, cy, cz, ip, ix, iy, iz, n, nobs, nk;
9704
9705 /* Set timer... */
9706 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
9707
9708 /* Init... */
9709 if (t == ctl->t_start) {
9710
9711 /* Check quantity index for mass... */
9712 if (ctl->qnt_m < 0)
9713 ERRMSG("Need quantity mass!");
9714
9715 /* Allocate... */
9716 ALLOC(area, double,
9717 ctl->csi_ny);
9718 ALLOC(rt, double,
9719 NOBS);
9720 ALLOC(rz, double,
9721 NOBS);
9722 ALLOC(rlon, double,
9723 NOBS);
9724 ALLOC(rlat, double,
9725 NOBS);
9726 ALLOC(robs, double,
9727 NOBS);
9728
9729 /* Read observation data... */
9730 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
9731
9732 /* Read kernel data... */
9733 if (ctl->csi_kernel[0] != '-')
9734 read_kernel(ctl->csi_kernel, kz, kw, &nk);
9735
9736 /* Create new file... */
9737 LOG(1, "Write CSI data: %s", filename);
9738 if (!(out = fopen(filename, "w")))
9739 ERRMSG("Cannot create file!");
9740
9741 /* Write header... */
9742 fprintf(out,
9743 "# $1 = time [s]\n"
9744 "# $2 = number of hits (cx)\n"
9745 "# $3 = number of misses (cy)\n"
9746 "# $4 = number of false alarms (cz)\n"
9747 "# $5 = number of observations (cx + cy)\n"
9748 "# $6 = number of forecasts (cx + cz)\n"
9749 "# $7 = bias (ratio of forecasts and observations) [%%]\n"
9750 "# $8 = probability of detection (POD) [%%]\n"
9751 "# $9 = false alarm rate (FAR) [%%]\n"
9752 "# $10 = critical success index (CSI) [%%]\n");
9753 fprintf(out,
9754 "# $11 = hits associated with random chance\n"
9755 "# $12 = equitable threat score (ETS) [%%]\n"
9756 "# $13 = Pearson linear correlation coefficient\n"
9757 "# $14 = Spearman rank-order correlation coefficient\n"
9758 "# $15 = column density mean error (F - O) [kg/m^2]\n"
9759 "# $16 = column density root mean square error (RMSE) [kg/m^2]\n"
9760 "# $17 = column density mean absolute error [kg/m^2]\n"
9761 "# $18 = log-likelihood function\n"
9762 "# $19 = number of data points\n\n");
9763
9764 /* Set grid box size... */
9765 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
9766 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
9767 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
9768
9769 /* Set horizontal coordinates... */
9770 for (iy = 0; iy < ctl->csi_ny; iy++) {
9771 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
9772 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat));
9773 }
9774 }
9775
9776 /* Set time interval... */
9777 const double t0 = t - 0.5 * ctl->dt_mod;
9778 const double t1 = t + 0.5 * ctl->dt_mod;
9779
9780 /* Allocate... */
9781 ALLOC(modmean, double,
9782 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9783 ALLOC(obsmean, double,
9784 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9785 ALLOC(obscount, int,
9786 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9787 ALLOC(obsstd, double,
9788 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9789
9790 /* Loop over observations... */
9791 for (int i = 0; i < nobs; i++) {
9792
9793 /* Check time... */
9794 if (rt[i] < t0)
9795 continue;
9796 else if (rt[i] >= t1)
9797 break;
9798
9799 /* Check observation data... */
9800 if (!isfinite(robs[i]))
9801 continue;
9802
9803 /* Calculate indices... */
9804 ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
9805 iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
9806 iz = (int) ((rz[i] - ctl->csi_z0) / dz);
9807
9808 /* Check indices... */
9809 if (ix < 0 || ix >= ctl->csi_nx ||
9810 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9811 continue;
9812
9813 /* Get mean observation index... */
9814 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9815 obsmean[idx] += robs[i];
9816 obsstd[idx] += SQR(robs[i]);
9817 obscount[idx]++;
9818 }
9819
9820 /* Analyze model data... */
9821 for (ip = 0; ip < atm->np; ip++) {
9822
9823 /* Check time... */
9824 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9825 continue;
9826
9827 /* Get indices... */
9828 ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
9829 iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
9830 iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
9831
9832 /* Check indices... */
9833 if (ix < 0 || ix >= ctl->csi_nx ||
9834 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9835 continue;
9836
9837 /* Get total mass in grid cell... */
9838 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9839 modmean[idx] += kernel_weight(kz, kw, nk, atm->p[ip])
9840 * atm->q[ctl->qnt_m][ip];
9841 }
9842
9843 /* Analyze all grid cells... */
9844 for (ix = 0; ix < ctl->csi_nx; ix++)
9845 for (iy = 0; iy < ctl->csi_ny; iy++)
9846 for (iz = 0; iz < ctl->csi_nz; iz++) {
9847
9848 /* Calculate mean observation index... */
9849 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9850 if (obscount[idx] > 0) {
9851 obsmean[idx] /= obscount[idx];
9852 obsstd[idx] -= SQR(obsmean[idx]);
9853 obsstd[idx] = sqrt(obsstd[idx]);
9854 }
9855
9856 /* Calculate column density... */
9857 if (modmean[idx] > 0)
9858 modmean[idx] /= (1e6 * area[iy]);
9859
9860 /* Calculate CSI... */
9861 if (obscount[idx] > 0) {
9862 ct++;
9863 if (obsmean[idx] >= ctl->csi_obsmin &&
9864 modmean[idx] >= ctl->csi_modmin)
9865 cx++;
9866 else if (obsmean[idx] >= ctl->csi_obsmin &&
9867 modmean[idx] < ctl->csi_modmin)
9868 cy++;
9869 else if (obsmean[idx] < ctl->csi_obsmin &&
9870 modmean[idx] >= ctl->csi_modmin)
9871 cz++;
9872 }
9873
9874 /* Save data for other verification statistics... */
9875 if (obscount[idx] > 0
9876 && (obsmean[idx] >= ctl->csi_obsmin
9877 || modmean[idx] >= ctl->csi_modmin)) {
9878 x[n] = modmean[idx];
9879 y[n] = obsmean[idx];
9880 if (modmean[idx] >= ctl->csi_modmin)
9881 obsstdn[n] = obsstd[idx];
9882 if ((++n) >= NCSI)
9883 ERRMSG("Too many data points to calculate statistics!");
9884 }
9885 }
9886
9887 /* Write output... */
9888 if (fmod(t, ctl->csi_dt_out) == 0) {
9889
9890 /* Calculate verification statistics
9891 (https://www.cawcr.gov.au/projects/verification/) ... */
9892 static double work[2 * NCSI], work2[2 * NCSI];;
9893 const int n_obs = cx + cy;
9894 const int n_for = cx + cz;
9895 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
9896 const double pod = (n_obs > 0) ? (100. * cx) / n_obs : NAN;
9897 const double far = (n_for > 0) ? (100. * cz) / n_for : NAN;
9898 const double csi =
9899 (cx + cy + cz > 0) ? (100. * cx) / (cx + cy + cz) : NAN;
9900 const double cx_rd = (ct > 0) ? (1. * n_obs * n_for) / ct : NAN;
9901 const double ets = (cx + cy + cz - cx_rd > 0) ?
9902 (100. * (cx - cx_rd)) / (cx + cy + cz - cx_rd) : NAN;
9903 const double rho_p =
9904 (n > 0) ? gsl_stats_correlation(x, 1, y, 1, (size_t) n) : NAN;
9905 const double rho_s =
9906 (n > 0) ? gsl_stats_spearman(x, 1, y, 1, (size_t) n, work) : NAN;
9907 for (int i = 0; i < n; i++) {
9908 work[i] = x[i] - y[i];
9909 work2[i] = (obsstdn[i] != 0) ? (x[i] - y[i]) / obsstdn[i] : 0;
9910 }
9911 const double mean = (n > 0) ? gsl_stats_mean(work, 1, (size_t) n) : NAN;
9912 const double rmse =
9913 (n > 0) ? gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n,
9914 0.0) : NAN;
9915 const double absdev =
9916 (n > 0) ? gsl_stats_absdev_m(work, 1, (size_t) n, 0.0) : NAN;
9917 const double loglikelihood =
9918 (n > 0) ? gsl_stats_tss(work2, 1, (size_t) n) * (-0.5) : GSL_NAN;
9919
9920 /* Write... */
9921 fprintf(out,
9922 "%.2f %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n", t,
9923 cx, cy, cz, n_obs, n_for, bias, pod, far, csi, cx_rd, ets, rho_p,
9924 rho_s, mean, rmse, absdev, loglikelihood, n);
9925
9926 /* Set counters to zero... */
9927 n = ct = cx = cy = cz = 0;
9928 }
9929
9930 /* Free... */
9931 free(modmean);
9932 free(obsmean);
9933 free(obscount);
9934 free(obsstd);
9935
9936 /* Finalize... */
9937 if (t == ctl->t_stop) {
9938
9939 /* Close output file... */
9940 fclose(out);
9941
9942 /* Free... */
9943 free(area);
9944 free(rt);
9945 free(rz);
9946 free(rlon);
9947 free(rlat);
9948 free(robs);
9949 }
9950}
9951
9952/*****************************************************************************/
9953
9955 const char *filename,
9956 const ctl_t *ctl,
9957 const atm_t *atm,
9958 const double t) {
9959
9960 static FILE *out;
9961
9962 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
9963 x[3], zm[NENS];
9964
9965 static int n[NENS];
9966
9967 /* Set timer... */
9968 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
9969
9970 /* Check quantities... */
9971 if (ctl->qnt_ens < 0)
9972 ERRMSG("Missing ensemble IDs!");
9973
9974 /* Set time interval... */
9975 const double t0 = t - 0.5 * ctl->dt_mod;
9976 const double t1 = t + 0.5 * ctl->dt_mod;
9977
9978 /* Init... */
9979 for (int i = 0; i < NENS; i++) {
9980 for (int iq = 0; iq < ctl->nq; iq++)
9981 qm[iq][i] = qs[iq][i] = 0;
9982 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
9983 n[i] = 0;
9984 }
9985
9986 /* Loop over air parcels... */
9987 for (int ip = 0; ip < atm->np; ip++) {
9988
9989 /* Check time... */
9990 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9991 continue;
9992
9993 /* Check ensemble ID... */
9994 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
9995 ERRMSG("Ensemble ID is out of range!");
9996
9997 /* Get means... */
9998 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
9999 for (int iq = 0; iq < ctl->nq; iq++) {
10000 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
10001 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
10002 }
10003 xm[ctl->qnt_ens][0] += x[0];
10004 xm[ctl->qnt_ens][1] += x[1];
10005 xm[ctl->qnt_ens][2] += x[2];
10006 zm[ctl->qnt_ens] += Z(atm->p[ip]);
10007 n[ctl->qnt_ens]++;
10008 }
10009
10010 /* Create file... */
10011 LOG(1, "Write ensemble data: %s", filename);
10012 if (!(out = fopen(filename, "w")))
10013 ERRMSG("Cannot create file!");
10014
10015 /* Write header... */
10016 fprintf(out,
10017 "# $1 = time [s]\n"
10018 "# $2 = altitude [km]\n"
10019 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
10020 for (int iq = 0; iq < ctl->nq; iq++)
10021 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
10022 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10023 for (int iq = 0; iq < ctl->nq; iq++)
10024 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
10025 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10026 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
10027
10028 /* Write data... */
10029 for (int i = 0; i < NENS; i++)
10030 if (n[i] > 0) {
10031 cart2geo(xm[i], &dummy, &lon, &lat);
10032 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
10033 for (int iq = 0; iq < ctl->nq; iq++) {
10034 fprintf(out, " ");
10035 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
10036 }
10037 for (int iq = 0; iq < ctl->nq; iq++) {
10038 fprintf(out, " ");
10039 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
10040 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
10041 }
10042 fprintf(out, " %d\n", n[i]);
10043 }
10044
10045 /* Close file... */
10046 fclose(out);
10047}
10048
10049/*****************************************************************************/
10050
10052 const char *filename,
10053 const ctl_t *ctl,
10054 met_t *met0,
10055 met_t *met1,
10056 const atm_t *atm,
10057 const double t) {
10058
10059 static double kz[EP], kw[EP];
10060
10061 static int nk;
10062
10063 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
10064
10065 int *ixs, *iys, *izs, *np;
10066
10067 /* Set timer... */
10068 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
10069
10070 /* Write info... */
10071 LOG(1, "Write grid data: %s", filename);
10072
10073 /* Init... */
10074 if (t == ctl->t_start) {
10075
10076 /* Read kernel data... */
10077 if (ctl->grid_kernel[0] != '-')
10078 read_kernel(ctl->grid_kernel, kz, kw, &nk);
10079 }
10080
10081 /* Allocate... */
10082 ALLOC(cd, double,
10083 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10084 for (int iq = 0; iq < ctl->nq; iq++) {
10085 ALLOC(mean[iq], double,
10086 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10087 ALLOC(sigma[iq], double,
10088 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10089 }
10090 ALLOC(vmr_impl, double,
10091 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10092 ALLOC(z, double,
10093 ctl->grid_nz);
10094 ALLOC(lon, double,
10095 ctl->grid_nx);
10096 ALLOC(lat, double,
10097 ctl->grid_ny);
10098 ALLOC(area, double,
10099 ctl->grid_ny);
10100 ALLOC(press, double,
10101 ctl->grid_nz);
10102 ALLOC(np, int,
10103 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10104 ALLOC(ixs, int,
10105 atm->np);
10106 ALLOC(iys, int,
10107 atm->np);
10108 ALLOC(izs, int,
10109 atm->np);
10110
10111 /* Set grid box size... */
10112 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
10113 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
10114 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
10115
10116 /* Set vertical coordinates... */
10117#pragma omp parallel for default(shared)
10118 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10119 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
10120 press[iz] = P(z[iz]);
10121 }
10122
10123 /* Set horizontal coordinates... */
10124 for (int ix = 0; ix < ctl->grid_nx; ix++)
10125 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
10126#pragma omp parallel for default(shared)
10127 for (int iy = 0; iy < ctl->grid_ny; iy++) {
10128 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
10129 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
10130 }
10131
10132 /* Set time interval for output... */
10133 const double t0 = t - 0.5 * ctl->dt_mod;
10134 const double t1 = t + 0.5 * ctl->dt_mod;
10135
10136 /* Get grid box indices... */
10137#pragma omp parallel for default(shared)
10138 for (int ip = 0; ip < atm->np; ip++) {
10139 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
10140 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
10141 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
10142 if (atm->time[ip] < t0 || atm->time[ip] > t1
10143 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
10144 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
10145 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
10146 izs[ip] = -1;
10147 }
10148
10149 /* Average data... */
10150 for (int ip = 0; ip < atm->np; ip++)
10151 if (izs[ip] >= 0) {
10152 int idx =
10153 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
10154 double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
10155 np[idx]++;
10156 for (int iq = 0; iq < ctl->nq; iq++) {
10157 mean[iq][idx] += kernel * atm->q[iq][ip];
10158 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
10159 }
10160 }
10161
10162 /* Calculate column density and volume mixing ratio... */
10163#pragma omp parallel for default(shared)
10164 for (int ix = 0; ix < ctl->grid_nx; ix++)
10165 for (int iy = 0; iy < ctl->grid_ny; iy++)
10166 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10167
10168 /* Get grid index... */
10169 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
10170
10171 /* Calculate column density... */
10172 cd[idx] = NAN;
10173 if (ctl->qnt_m >= 0)
10174 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
10175
10176 /* Calculate volume mixing ratio (implicit)... */
10177 vmr_impl[idx] = NAN;
10178 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
10179 && met1 != NULL) {
10180 vmr_impl[idx] = 0;
10181 if (mean[ctl->qnt_m][idx] > 0) {
10182
10183 /* Get temperature... */
10184 double temp;
10186 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
10187 lon[ix], lat[iy], &temp, ci, cw, 1);
10188
10189 /* Calculate volume mixing ratio... */
10190 vmr_impl[idx] =
10191 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
10192 }
10193 }
10194
10195 /* Calculate mean... */
10196 if (np[idx] > 0)
10197 for (int iq = 0; iq < ctl->nq; iq++) {
10198 mean[iq][idx] /= np[idx];
10199 double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
10200 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
10201 } else
10202 for (int iq = 0; iq < ctl->nq; iq++) {
10203 mean[iq][idx] = NAN;
10204 sigma[iq][idx] = NAN;
10205 }
10206 }
10207
10208 /* Write ASCII data... */
10209 if (ctl->grid_type == 0)
10210 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
10211 t, z, lon, lat, area, dz, np);
10212
10213 /* Write netCDF data... */
10214 else if (ctl->grid_type == 1)
10215 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
10216 t, z, lon, lat, area, dz, np);
10217
10218 /* Error message... */
10219 else
10220 ERRMSG("Grid data format GRID_TYPE unknown!");
10221
10222 /* Free... */
10223 free(cd);
10224 for (int iq = 0; iq < ctl->nq; iq++) {
10225 free(mean[iq]);
10226 free(sigma[iq]);
10227 }
10228 free(vmr_impl);
10229 free(z);
10230 free(lon);
10231 free(lat);
10232 free(area);
10233 free(press);
10234 free(np);
10235 free(ixs);
10236 free(iys);
10237 free(izs);
10238}
10239
10240/*****************************************************************************/
10241
10243 const char *filename,
10244 const ctl_t *ctl,
10245 const double *cd,
10246 double *mean[NQ],
10247 double *sigma[NQ],
10248 const double *vmr_impl,
10249 const double t,
10250 const double *z,
10251 const double *lon,
10252 const double *lat,
10253 const double *area,
10254 const double dz,
10255 const int *np) {
10256
10257 FILE *out;
10258
10259 /* Check if gnuplot output is requested... */
10260 if (ctl->grid_gpfile[0] != '-') {
10261
10262 /* Create gnuplot pipe... */
10263 if (!(out = popen("gnuplot", "w")))
10264 ERRMSG("Cannot create pipe to gnuplot!");
10265
10266 /* Set plot filename... */
10267 fprintf(out, "set out \"%s.png\"\n", filename);
10268
10269 /* Set time string... */
10270 double r;
10271 int year, mon, day, hour, min, sec;
10272 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
10273 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
10274 year, mon, day, hour, min);
10275
10276 /* Dump gnuplot file to pipe... */
10277 FILE *in;
10278 char line[LEN];
10279 if (!(in = fopen(ctl->grid_gpfile, "r")))
10280 ERRMSG("Cannot open file!");
10281 while (fgets(line, LEN, in))
10282 fprintf(out, "%s", line);
10283 fclose(in);
10284 }
10285
10286 else {
10287
10288 /* Create file... */
10289 if (!(out = fopen(filename, "w")))
10290 ERRMSG("Cannot create file!");
10291 }
10292
10293 /* Write header... */
10294 fprintf(out,
10295 "# $1 = time [s]\n"
10296 "# $2 = altitude [km]\n"
10297 "# $3 = longitude [deg]\n"
10298 "# $4 = latitude [deg]\n"
10299 "# $5 = surface area [km^2]\n"
10300 "# $6 = layer depth [km]\n"
10301 "# $7 = column density (implicit) [kg/m^2]\n"
10302 "# $8 = volume mixing ratio (implicit) [ppv]\n"
10303 "# $9 = number of particles [1]\n");
10304 for (int iq = 0; iq < ctl->nq; iq++)
10305 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
10306 ctl->qnt_unit[iq]);
10307 if (ctl->grid_stddev)
10308 for (int iq = 0; iq < ctl->nq; iq++)
10309 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
10310 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10311 fprintf(out, "\n");
10312
10313 /* Write data... */
10314 for (int ix = 0; ix < ctl->grid_nx; ix++) {
10315 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
10316 fprintf(out, "\n");
10317 for (int iy = 0; iy < ctl->grid_ny; iy++) {
10318 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
10319 fprintf(out, "\n");
10320 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10321 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
10322 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
10323 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
10324 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
10325 for (int iq = 0; iq < ctl->nq; iq++) {
10326 fprintf(out, " ");
10327 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
10328 }
10329 if (ctl->grid_stddev)
10330 for (int iq = 0; iq < ctl->nq; iq++) {
10331 fprintf(out, " ");
10332 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
10333 }
10334 fprintf(out, "\n");
10335 }
10336 }
10337 }
10338 }
10339
10340 /* Close file... */
10341 fclose(out);
10342}
10343
10344/*****************************************************************************/
10345
10347 const char *filename,
10348 const ctl_t *ctl,
10349 const double *cd,
10350 double *mean[NQ],
10351 double *sigma[NQ],
10352 const double *vmr_impl,
10353 const double t,
10354 const double *z,
10355 const double *lon,
10356 const double *lat,
10357 const double *area,
10358 const double dz,
10359 const int *np) {
10360
10361 char longname[2 * LEN], varname[2 * LEN];
10362
10363 double *help;
10364
10365 int *help2, ncid, dimid[10], varid;
10366
10367 size_t start[2], count[2];
10368
10369 /* Allocate... */
10370 ALLOC(help, double,
10371 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10372 ALLOC(help2, int,
10373 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10374
10375 /* Create file... */
10376 NC(nc_create(filename, NC_NETCDF4, &ncid));
10377
10378 /* Define dimensions... */
10379 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
10380 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
10381 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
10382 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
10383 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
10384
10385 /* Define variables and their attributes... */
10386 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
10387 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
10388 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
10389 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
10390 0);
10391 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
10392 0);
10393 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
10394 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
10395
10396 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
10397 ctl->grid_nc_level, 0);
10398 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid, "volume mixing ratio (implicit)",
10399 "ppv", ctl->grid_nc_level, 0);
10400 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
10401 for (int iq = 0; iq < ctl->nq; iq++) {
10402 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
10403 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
10404 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
10405 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
10406 if (ctl->grid_stddev) {
10407 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
10408 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
10409 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
10410 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
10411 }
10412 }
10413 /* End definitions... */
10414 NC(nc_enddef(ncid));
10415
10416 /* Write data... */
10417 NC_PUT_DOUBLE("time", &t, 0);
10418 NC_PUT_DOUBLE("lon", lon, 0);
10419 NC_PUT_DOUBLE("lat", lat, 0);
10420 NC_PUT_DOUBLE("z", z, 0);
10421 NC_PUT_DOUBLE("area", area, 0);
10422 NC_PUT_DOUBLE("dz", &dz, 0);
10423
10424 for (int ix = 0; ix < ctl->grid_nx; ix++)
10425 for (int iy = 0; iy < ctl->grid_ny; iy++)
10426 for (int iz = 0; iz < ctl->grid_nz; iz++)
10427 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10428 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10429 NC_PUT_DOUBLE("cd", help, 0);
10430
10431 for (int ix = 0; ix < ctl->grid_nx; ix++)
10432 for (int iy = 0; iy < ctl->grid_ny; iy++)
10433 for (int iz = 0; iz < ctl->grid_nz; iz++)
10434 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10435 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10436 NC_PUT_DOUBLE("vmr_impl", help, 0);
10437
10438 for (int ix = 0; ix < ctl->grid_nx; ix++)
10439 for (int iy = 0; iy < ctl->grid_ny; iy++)
10440 for (int iz = 0; iz < ctl->grid_nz; iz++)
10441 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10442 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10443 NC_PUT_INT("np", help2, 0);
10444
10445 for (int iq = 0; iq < ctl->nq; iq++) {
10446 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
10447 for (int ix = 0; ix < ctl->grid_nx; ix++)
10448 for (int iy = 0; iy < ctl->grid_ny; iy++)
10449 for (int iz = 0; iz < ctl->grid_nz; iz++)
10450 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10451 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10452 NC_PUT_DOUBLE(varname, help, 0);
10453 }
10454
10455 if (ctl->grid_stddev)
10456 for (int iq = 0; iq < ctl->nq; iq++) {
10457 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
10458 for (int ix = 0; ix < ctl->grid_nx; ix++)
10459 for (int iy = 0; iy < ctl->grid_ny; iy++)
10460 for (int iz = 0; iz < ctl->grid_nz; iz++)
10461 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10462 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10463 NC_PUT_DOUBLE(varname, help, 0);
10464 }
10465
10466 /* Close file... */
10467 NC(nc_close(ncid));
10468
10469 /* Free... */
10470 free(help);
10471 free(help2);
10472}
10473
10474/*****************************************************************************/
10475
10477 const char *filename,
10478 const ctl_t *ctl,
10479 met_t *met) {
10480
10481 /* Create file... */
10482 FILE *out;
10483 if (!(out = fopen(filename, "w")))
10484 ERRMSG("Cannot create file!");
10485
10486 /* Write type of binary data... */
10487 FWRITE(&ctl->met_type, int,
10488 1,
10489 out);
10490
10491 /* Write version of binary data... */
10492 int version = 103;
10493 FWRITE(&version, int,
10494 1,
10495 out);
10496
10497 /* Write grid data... */
10498 FWRITE(&met->time, double,
10499 1,
10500 out);
10501 FWRITE(&met->nx, int,
10502 1,
10503 out);
10504 FWRITE(&met->ny, int,
10505 1,
10506 out);
10507 FWRITE(&met->np, int,
10508 1,
10509 out);
10510 FWRITE(met->lon, double,
10511 (size_t) met->nx,
10512 out);
10513 FWRITE(met->lat, double,
10514 (size_t) met->ny,
10515 out);
10516 FWRITE(met->p, double,
10517 (size_t) met->np,
10518 out);
10519
10520 /* Write surface data... */
10521 write_met_bin_2d(out, met, met->ps, "PS");
10522 write_met_bin_2d(out, met, met->ts, "TS");
10523 write_met_bin_2d(out, met, met->zs, "ZS");
10524 write_met_bin_2d(out, met, met->us, "US");
10525 write_met_bin_2d(out, met, met->vs, "VS");
10526 write_met_bin_2d(out, met, met->ess, "ESS");
10527 write_met_bin_2d(out, met, met->nss, "NSS");
10528 write_met_bin_2d(out, met, met->shf, "SHF");
10529 write_met_bin_2d(out, met, met->lsm, "LSM");
10530 write_met_bin_2d(out, met, met->sst, "SST");
10531 write_met_bin_2d(out, met, met->pbl, "PBL");
10532 write_met_bin_2d(out, met, met->pt, "PT");
10533 write_met_bin_2d(out, met, met->tt, "TT");
10534 write_met_bin_2d(out, met, met->zt, "ZT");
10535 write_met_bin_2d(out, met, met->h2ot, "H2OT");
10536 write_met_bin_2d(out, met, met->pct, "PCT");
10537 write_met_bin_2d(out, met, met->pcb, "PCB");
10538 write_met_bin_2d(out, met, met->cl, "CL");
10539 write_met_bin_2d(out, met, met->plcl, "PLCL");
10540 write_met_bin_2d(out, met, met->plfc, "PLFC");
10541 write_met_bin_2d(out, met, met->pel, "PEL");
10542 write_met_bin_2d(out, met, met->cape, "CAPE");
10543 write_met_bin_2d(out, met, met->cin, "CIN");
10544 write_met_bin_2d(out, met, met->o3c, "O3C");
10545
10546 /* Write level data... */
10547 write_met_bin_3d(out, ctl, met, met->z, "Z",
10548 (ctl->met_zfp_tol_z <= 0 ? ctl->met_zfp_prec : 0),
10549 ctl->met_zfp_tol_z);
10550 write_met_bin_3d(out, ctl, met, met->t, "T",
10551 (ctl->met_zfp_tol_t <= 0 ? ctl->met_zfp_prec : 0),
10552 ctl->met_zfp_tol_t);
10553 write_met_bin_3d(out, ctl, met, met->u, "U", ctl->met_zfp_prec, 0);
10554 write_met_bin_3d(out, ctl, met, met->v, "V", ctl->met_zfp_prec, 0);
10555 write_met_bin_3d(out, ctl, met, met->w, "W", ctl->met_zfp_prec, 0);
10556 write_met_bin_3d(out, ctl, met, met->pv, "PV", ctl->met_zfp_prec, 0);
10557 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", ctl->met_zfp_prec, 0);
10558 write_met_bin_3d(out, ctl, met, met->o3, "O3", ctl->met_zfp_prec, 0);
10559 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", ctl->met_zfp_prec, 0);
10560 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", ctl->met_zfp_prec, 0);
10561 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", ctl->met_zfp_prec, 0);
10562 write_met_bin_3d(out, ctl, met, met->swc, "SWC", ctl->met_zfp_prec, 0);
10563 write_met_bin_3d(out, ctl, met, met->cc, "CC", ctl->met_zfp_prec, 0);
10564
10565 /* Write final flag... */
10566 int final = 999;
10567 FWRITE(&final, int,
10568 1,
10569 out);
10570
10571 /* Close file... */
10572 fclose(out);
10573}
10574
10575/*****************************************************************************/
10576
10578 FILE *out,
10579 met_t *met,
10580 float var[EX][EY],
10581 const char *varname) {
10582
10583 float *help;
10584
10585 /* Allocate... */
10586 ALLOC(help, float,
10587 EX * EY);
10588
10589 /* Copy data... */
10590 for (int ix = 0; ix < met->nx; ix++)
10591 for (int iy = 0; iy < met->ny; iy++)
10592 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
10593
10594 /* Write uncompressed data... */
10595 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
10596 FWRITE(help, float,
10597 (size_t) (met->nx * met->ny),
10598 out);
10599
10600 /* Free... */
10601 free(help);
10602}
10603
10604/*****************************************************************************/
10605
10607 FILE *out,
10608 const ctl_t *ctl,
10609 met_t *met,
10610 float var[EX][EY][EP],
10611 const char *varname,
10612 const int precision,
10613 const double tolerance) {
10614
10615 float *help;
10616
10617 /* Allocate... */
10618 ALLOC(help, float,
10619 EX * EY * EP);
10620
10621 /* Copy data... */
10622#pragma omp parallel for default(shared) collapse(2)
10623 for (int ix = 0; ix < met->nx; ix++)
10624 for (int iy = 0; iy < met->ny; iy++)
10625 for (int ip = 0; ip < met->np; ip++)
10626 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
10627
10628 /* Write uncompressed data... */
10629 if (ctl->met_type == 1) {
10630 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
10631 FWRITE(help, float,
10632 (size_t) (met->nx * met->ny * met->np),
10633 out);
10634 }
10635
10636 /* Write packed data... */
10637 else if (ctl->met_type == 2)
10638 compress_pck(varname, help, (size_t) (met->ny * met->nx),
10639 (size_t) met->np, 0, out);
10640
10641 /* Write zfp data... */
10642#ifdef ZFP
10643 else if (ctl->met_type == 3) {
10644 FWRITE(&precision, int,
10645 1,
10646 out);
10647 FWRITE(&tolerance, double,
10648 1,
10649 out);
10650 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
10651 tolerance, 0, out);
10652 }
10653#endif
10654
10655 /* Write zstd data... */
10656#ifdef ZSTD
10657 else if (ctl->met_type == 4)
10658 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
10659 out);
10660#endif
10661
10662 /* Write cmultiscale data... */
10663#ifdef CMS
10664 else if (ctl->met_type == 5) {
10665 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
10666 (size_t) met->np, 0, out);
10667 }
10668#endif
10669
10670 /* Unknown method... */
10671 else {
10672 ERRMSG("MET_TYPE not supported!");
10673 LOG(3, "%d %g", precision, tolerance);
10674 }
10675
10676 /* Free... */
10677 free(help);
10678}
10679
10680/*****************************************************************************/
10681
10683 const char *filename,
10684 const ctl_t *ctl,
10685 met_t *met) {
10686
10687 /* Create file... */
10688 int ncid, varid;
10689 size_t start[4], count[4];
10690 nc_create(filename, NC_NETCDF4, &ncid);
10691
10692 /* Define dimensions... */
10693 int tid, lonid, latid, levid;
10694 NC(nc_def_dim(ncid, "time", 1, &tid));
10695 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
10696 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
10697 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
10698
10699 /* Define grid... */
10700 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
10701 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
10702 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
10703 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
10704 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
10705
10706 /* Define surface variables... */
10707 int dimid2[2] = { latid, lonid };
10708 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
10709 ctl->met_nc_level, 0);
10710 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
10711 ctl->met_nc_level, 0);
10712 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
10713 ctl->met_nc_level, 0);
10714 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
10715 "m s**-1", ctl->met_nc_level, 0);
10716 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
10717 "m s**-1", ctl->met_nc_level, 0);
10718 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
10719 "Instantaneous eastward turbulent surface stress", "N m**-2",
10720 ctl->met_nc_level, 0);
10721 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
10722 "Instantaneous northward turbulent surface stress", "N m**-2",
10723 ctl->met_nc_level, 0);
10724 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
10725 "Instantaneous surface sensible heat flux", "W m**-1",
10726 ctl->met_nc_level, 0);
10727 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
10728 ctl->met_nc_level, 0);
10729 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
10730 ctl->met_nc_level, 0);
10731 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
10732 ctl->met_nc_level, 0);
10733 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
10734 ctl->met_nc_level, 0);
10735 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
10736 ctl->met_nc_level, 0);
10737 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
10738 ctl->met_nc_level, 0);
10739 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
10740 ctl->met_nc_level, 0);
10741 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
10742 ctl->met_nc_level, 0);
10743 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
10744 ctl->met_nc_level, 0);
10745 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water", "kg m**2",
10746 ctl->met_nc_level, 0);
10747 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
10748 "Pressure at lifted condensation level (LCL)", "Pa",
10749 ctl->met_nc_level, 0);
10750 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
10751 "Pressure at level of free convection (LFC)", "Pa",
10752 ctl->met_nc_level, 0);
10753 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2, "Pressure at equilibrium level (EL)",
10754 "Pa", ctl->met_nc_level, 0);
10755 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
10756 "Convective available potential energy", "J kg**-1",
10757 ctl->met_nc_level, 0);
10758 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition", "J kg**-1",
10759 ctl->met_nc_level, 0);
10760 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
10761 ctl->met_nc_level, 0);
10762
10763 /* Define level data... */
10764 int dimid3[3] = { levid, latid, lonid };
10765 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
10766 ctl->met_nc_level, ctl->met_nc_quant);
10767 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
10768 ctl->met_nc_level, ctl->met_nc_quant);
10769 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
10770 ctl->met_nc_level, ctl->met_nc_quant);
10771 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
10772 ctl->met_nc_level, ctl->met_nc_quant);
10773 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
10774 ctl->met_nc_level, ctl->met_nc_quant);
10775 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
10776 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10777 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
10778 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10779 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
10780 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10781 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
10782 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10783 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
10784 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10785 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
10786 ctl->met_nc_level, ctl->met_nc_quant);
10787
10788 /* End definitions... */
10789 NC(nc_enddef(ncid));
10790
10791 /* Write grid data... */
10792 NC_PUT_DOUBLE("time", &met->time, 0);
10793 NC_PUT_DOUBLE("lon", met->lon, 0);
10794 NC_PUT_DOUBLE("lat", met->lat, 0);
10795 double phelp[EP];
10796 for (int ip = 0; ip < met->np; ip++)
10797 phelp[ip] = 100. * met->p[ip];
10798 NC_PUT_DOUBLE("lev", phelp, 0);
10799
10800 /* Write surface data... */
10801 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
10802 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
10803 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
10804 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
10805 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
10806 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
10807 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
10808 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
10809 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
10810 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
10811 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
10812 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
10813 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
10814 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
10815 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
10816 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
10817 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
10818 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
10819 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
10820 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
10821 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
10822 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
10823 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
10824 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
10825
10826 /* Write level data... */
10827 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
10828 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
10829 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
10830 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
10831 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
10832 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
10833 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
10834 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
10835 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
10836 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
10837 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
10838
10839 /* Close file... */
10840 NC(nc_close(ncid));
10841}
10842
10843/*****************************************************************************/
10844
10846 const int ncid,
10847 const char *varname,
10848 met_t *met,
10849 float var[EX][EY],
10850 const float scl) {
10851
10852 int varid;
10853 size_t start[4], count[4];
10854
10855 /* Allocate... */
10856 float *help;
10857 ALLOC(help, float,
10858 EX * EY);
10859
10860 /* Copy data... */
10861 for (int ix = 0; ix < met->nx; ix++)
10862 for (int iy = 0; iy < met->ny; iy++)
10863 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
10864
10865 /* Write data... */
10866 NC_PUT_FLOAT(varname, help, 0);
10867
10868 /* Free... */
10869 free(help);
10870}
10871
10872/*****************************************************************************/
10873
10875 const int ncid,
10876 const char *varname,
10877 met_t *met,
10878 float var[EX][EY][EP],
10879 const float scl) {
10880
10881 int varid;
10882 size_t start[4], count[4];
10883
10884 /* Allocate... */
10885 float *help;
10886 ALLOC(help, float,
10887 EX * EY * EP);
10888
10889 /* Copy data... */
10890 for (int ix = 0; ix < met->nx; ix++)
10891 for (int iy = 0; iy < met->ny; iy++)
10892 for (int ip = 0; ip < met->np; ip++)
10893 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
10894
10895 /* Write data... */
10896 NC_PUT_FLOAT(varname, help, 0);
10897
10898 /* Free... */
10899 free(help);
10900}
10901
10902/*****************************************************************************/
10903
10905 const char *filename,
10906 const ctl_t *ctl,
10907 met_t *met0,
10908 met_t *met1,
10909 const atm_t *atm,
10910 const double t) {
10911
10912 static FILE *out;
10913
10914 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
10915 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
10916
10917 static int nobs, *obscount, ip, okay;
10918
10919 /* Set timer... */
10920 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
10921
10922 /* Init... */
10923 if (t == ctl->t_start) {
10924
10925 /* Check quantity index for mass... */
10926 if (ctl->qnt_m < 0)
10927 ERRMSG("Need quantity mass!");
10928
10929 /* Check molar mass... */
10930 if (ctl->molmass <= 0)
10931 ERRMSG("Specify molar mass!");
10932
10933 /* Allocate... */
10934 ALLOC(lon, double,
10935 ctl->prof_nx);
10936 ALLOC(lat, double,
10937 ctl->prof_ny);
10938 ALLOC(area, double,
10939 ctl->prof_ny);
10940 ALLOC(z, double,
10941 ctl->prof_nz);
10942 ALLOC(press, double,
10943 ctl->prof_nz);
10944 ALLOC(rt, double,
10945 NOBS);
10946 ALLOC(rz, double,
10947 NOBS);
10948 ALLOC(rlon, double,
10949 NOBS);
10950 ALLOC(rlat, double,
10951 NOBS);
10952 ALLOC(robs, double,
10953 NOBS);
10954
10955 /* Read observation data... */
10956 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
10957
10958 /* Create new output file... */
10959 LOG(1, "Write profile data: %s", filename);
10960 if (!(out = fopen(filename, "w")))
10961 ERRMSG("Cannot create file!");
10962
10963 /* Write header... */
10964 fprintf(out,
10965 "# $1 = time [s]\n"
10966 "# $2 = altitude [km]\n"
10967 "# $3 = longitude [deg]\n"
10968 "# $4 = latitude [deg]\n"
10969 "# $5 = pressure [hPa]\n"
10970 "# $6 = temperature [K]\n"
10971 "# $7 = volume mixing ratio [ppv]\n"
10972 "# $8 = H2O volume mixing ratio [ppv]\n"
10973 "# $9 = O3 volume mixing ratio [ppv]\n"
10974 "# $10 = observed BT index [K]\n"
10975 "# $11 = number of observations\n");
10976
10977 /* Set grid box size... */
10978 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
10979 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
10980 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
10981
10982 /* Set vertical coordinates... */
10983 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10984 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
10985 press[iz] = P(z[iz]);
10986 }
10987
10988 /* Set horizontal coordinates... */
10989 for (int ix = 0; ix < ctl->prof_nx; ix++)
10990 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
10991 for (int iy = 0; iy < ctl->prof_ny; iy++) {
10992 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
10993 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
10994 }
10995 }
10996
10997 /* Set time interval... */
10998 const double t0 = t - 0.5 * ctl->dt_mod;
10999 const double t1 = t + 0.5 * ctl->dt_mod;
11000
11001 /* Allocate... */
11002 ALLOC(mass, double,
11003 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
11004 ALLOC(obsmean, double,
11005 ctl->prof_nx * ctl->prof_ny);
11006 ALLOC(obscount, int,
11007 ctl->prof_nx * ctl->prof_ny);
11008
11009 /* Loop over observations... */
11010 for (int i = 0; i < nobs; i++) {
11011
11012 /* Check time... */
11013 if (rt[i] < t0)
11014 continue;
11015 else if (rt[i] >= t1)
11016 break;
11017
11018 /* Check observation data... */
11019 if (!isfinite(robs[i]))
11020 continue;
11021
11022 /* Calculate indices... */
11023 int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
11024 int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
11025
11026 /* Check indices... */
11027 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
11028 continue;
11029
11030 /* Get mean observation index... */
11031 int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
11032 obsmean[idx] += robs[i];
11033 obscount[idx]++;
11034 }
11035
11036 /* Analyze model data... */
11037 for (ip = 0; ip < atm->np; ip++) {
11038
11039 /* Check time... */
11040 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11041 continue;
11042
11043 /* Get indices... */
11044 int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
11045 int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
11046 int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
11047
11048 /* Check indices... */
11049 if (ix < 0 || ix >= ctl->prof_nx ||
11050 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
11051 continue;
11052
11053 /* Get total mass in grid cell... */
11054 int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11055 mass[idx] += atm->q[ctl->qnt_m][ip];
11056 }
11057
11058 /* Extract profiles... */
11059 for (int ix = 0; ix < ctl->prof_nx; ix++)
11060 for (int iy = 0; iy < ctl->prof_ny; iy++) {
11061 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
11062 if (obscount[idx2] > 0) {
11063
11064 /* Check profile... */
11065 okay = 0;
11066 for (int iz = 0; iz < ctl->prof_nz; iz++) {
11067 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11068 if (mass[idx3] > 0) {
11069 okay = 1;
11070 break;
11071 }
11072 }
11073 if (!okay)
11074 continue;
11075
11076 /* Write output... */
11077 fprintf(out, "\n");
11078
11079 /* Loop over altitudes... */
11080 for (int iz = 0; iz < ctl->prof_nz; iz++) {
11081
11082 /* Get temperature, water vapor, and ozone... */
11084 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
11085 lon[ix], lat[iy], &temp, ci, cw, 1);
11086 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
11087 lon[ix], lat[iy], &h2o, ci, cw, 0);
11088 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
11089 lon[ix], lat[iy], &o3, ci, cw, 0);
11090
11091 /* Calculate volume mixing ratio... */
11092 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11093 vmr = MA / ctl->molmass * mass[idx3]
11094 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
11095
11096 /* Write output... */
11097 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
11098 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
11099 obsmean[idx2] / obscount[idx2], obscount[idx2]);
11100 }
11101 }
11102 }
11103
11104 /* Free... */
11105 free(mass);
11106 free(obsmean);
11107 free(obscount);
11108
11109 /* Finalize... */
11110 if (t == ctl->t_stop) {
11111
11112 /* Close output file... */
11113 fclose(out);
11114
11115 /* Free... */
11116 free(lon);
11117 free(lat);
11118 free(area);
11119 free(z);
11120 free(press);
11121 free(rt);
11122 free(rz);
11123 free(rlon);
11124 free(rlat);
11125 free(robs);
11126 }
11127}
11128
11129/*****************************************************************************/
11130
11132 const char *filename,
11133 const ctl_t *ctl,
11134 met_t *met0,
11135 met_t *met1,
11136 const atm_t *atm,
11137 const double t) {
11138
11139 static FILE *out;
11140
11141 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
11142 kw[EP];
11143
11144 static int nobs, nk;
11145
11146 /* Set timer... */
11147 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
11148
11149 /* Init... */
11150 if (t == ctl->t_start) {
11151
11152 /* Allocate... */
11153 ALLOC(rt, double,
11154 NOBS);
11155 ALLOC(rz, double,
11156 NOBS);
11157 ALLOC(rlon, double,
11158 NOBS);
11159 ALLOC(rlat, double,
11160 NOBS);
11161 ALLOC(robs, double,
11162 NOBS);
11163
11164 /* Read observation data... */
11165 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11166
11167 /* Read kernel data... */
11168 if (ctl->sample_kernel[0] != '-')
11169 read_kernel(ctl->sample_kernel, kz, kw, &nk);
11170
11171 /* Create output file... */
11172 LOG(1, "Write sample data: %s", filename);
11173 if (!(out = fopen(filename, "w")))
11174 ERRMSG("Cannot create file!");
11175
11176 /* Write header... */
11177 fprintf(out,
11178 "# $1 = time [s]\n"
11179 "# $2 = altitude [km]\n"
11180 "# $3 = longitude [deg]\n"
11181 "# $4 = latitude [deg]\n"
11182 "# $5 = surface area [km^2]\n"
11183 "# $6 = layer depth [km]\n"
11184 "# $7 = number of particles [1]\n"
11185 "# $8 = column density [kg/m^2]\n"
11186 "# $9 = volume mixing ratio [ppv]\n"
11187 "# $10 = observed BT index [K]\n\n");
11188
11189 /* Set latitude range, squared radius, and area... */
11190 dlat = DY2DEG(ctl->sample_dx);
11191 rmax2 = SQR(ctl->sample_dx);
11192 area = M_PI * rmax2;
11193 }
11194
11195 /* Set time interval for output... */
11196 const double t0 = t - 0.5 * ctl->dt_mod;
11197 const double t1 = t + 0.5 * ctl->dt_mod;
11198
11199 /* Loop over observations... */
11200 for (int i = 0; i < nobs; i++) {
11201
11202 /* Check time... */
11203 if (rt[i] < t0)
11204 continue;
11205 else if (rt[i] >= t1)
11206 break;
11207
11208 /* Calculate Cartesian coordinates... */
11209 double x0[3];
11210 geo2cart(0, rlon[i], rlat[i], x0);
11211
11212 /* Set pressure range... */
11213 const double rp = P(rz[i]);
11214 const double ptop = P(rz[i] + ctl->sample_dz);
11215 const double pbot = P(rz[i] - ctl->sample_dz);
11216
11217 /* Init... */
11218 double mass = 0;
11219 int np = 0;
11220
11221 /* Loop over air parcels... */
11222 //#pragma omp parallel for default(shared) reduction(+:mass,np)
11223 for (int ip = 0; ip < atm->np; ip++) {
11224
11225 /* Check time... */
11226 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11227 continue;
11228
11229 /* Check latitude... */
11230 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
11231 continue;
11232
11233 /* Check horizontal distance... */
11234 double x1[3];
11235 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
11236 if (DIST2(x0, x1) > rmax2)
11237 continue;
11238
11239 /* Check pressure... */
11240 if (ctl->sample_dz > 0)
11241 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
11242 continue;
11243
11244 /* Add mass... */
11245 if (ctl->qnt_m >= 0)
11246 mass +=
11247 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11248 np++;
11249 }
11250
11251 /* Calculate column density... */
11252 const double cd = mass / (1e6 * area);
11253
11254 /* Calculate volume mixing ratio... */
11255 double vmr = 0;
11256 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
11257 if (mass > 0) {
11258
11259 /* Get temperature... */
11260 double temp;
11262 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
11263 rlon[i], rlat[i], &temp, ci, cw, 1);
11264
11265 /* Calculate volume mixing ratio... */
11266 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
11267 }
11268 } else
11269 vmr = NAN;
11270
11271 /* Write output... */
11272 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
11273 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
11274 }
11275
11276 /* Finalize...... */
11277 if (t == ctl->t_stop) {
11278
11279 /* Close output file... */
11280 fclose(out);
11281
11282 /* Free... */
11283 free(rt);
11284 free(rz);
11285 free(rlon);
11286 free(rlat);
11287 free(robs);
11288 }
11289}
11290
11291/*****************************************************************************/
11292
11294 const char *filename,
11295 const ctl_t *ctl,
11296 atm_t *atm,
11297 const double t) {
11298
11299 static FILE *out;
11300
11301 static double rmax2, x0[3], x1[3];
11302
11303 /* Set timer... */
11304 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
11305
11306 /* Init... */
11307 if (t == ctl->t_start) {
11308
11309 /* Write info... */
11310 LOG(1, "Write station data: %s", filename);
11311
11312 /* Create new file... */
11313 if (!(out = fopen(filename, "w")))
11314 ERRMSG("Cannot create file!");
11315
11316 /* Write header... */
11317 fprintf(out,
11318 "# $1 = time [s]\n"
11319 "# $2 = altitude [km]\n"
11320 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11321 for (int iq = 0; iq < ctl->nq; iq++)
11322 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
11323 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11324 fprintf(out, "\n");
11325
11326 /* Set geolocation and search radius... */
11327 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
11328 rmax2 = SQR(ctl->stat_r);
11329 }
11330
11331 /* Set time interval for output... */
11332 const double t0 = t - 0.5 * ctl->dt_mod;
11333 const double t1 = t + 0.5 * ctl->dt_mod;
11334
11335 /* Loop over air parcels... */
11336 for (int ip = 0; ip < atm->np; ip++) {
11337
11338 /* Check time... */
11339 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11340 continue;
11341
11342 /* Check time range for station output... */
11343 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
11344 continue;
11345
11346 /* Check station flag... */
11347 if (ctl->qnt_stat >= 0)
11348 if ((int) atm->q[ctl->qnt_stat][ip])
11349 continue;
11350
11351 /* Get Cartesian coordinates... */
11352 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
11353
11354 /* Check horizontal distance... */
11355 if (DIST2(x0, x1) > rmax2)
11356 continue;
11357
11358 /* Set station flag... */
11359 if (ctl->qnt_stat >= 0)
11360 atm->q[ctl->qnt_stat][ip] = 1;
11361
11362 /* Write data... */
11363 fprintf(out, "%.2f %g %g %g",
11364 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
11365 for (int iq = 0; iq < ctl->nq; iq++) {
11366 fprintf(out, " ");
11367 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11368 }
11369 fprintf(out, "\n");
11370 }
11371
11372 /* Close file... */
11373 if (t == ctl->t_stop)
11374 fclose(out);
11375}
11376
11377/*****************************************************************************/
11378
11380 const char *filename,
11381 const ctl_t *ctl,
11382 const atm_t *atm,
11383 const double t) {
11384
11385 FILE *out;
11386
11387 /* Set timer... */
11388 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
11389
11390 /* Write info... */
11391 LOG(1, "Write VTK data: %s", filename);
11392
11393 /* Set time interval for output... */
11394 const double t0 = t - 0.5 * ctl->dt_mod;
11395 const double t1 = t + 0.5 * ctl->dt_mod;
11396
11397 /* Create file... */
11398 if (!(out = fopen(filename, "w")))
11399 ERRMSG("Cannot create file!");
11400
11401 /* Count data points... */
11402 int np = 0;
11403 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11404 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11405 continue;
11406 np++;
11407 }
11408
11409 /* Write header... */
11410 fprintf(out,
11411 "# vtk DataFile Version 3.0\n"
11412 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
11413
11414 /* Write point coordinates... */
11415 fprintf(out, "POINTS %d float\n", np);
11416 if (ctl->vtk_sphere) {
11417 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11418 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11419 continue;
11420 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
11421 + ctl->vtk_offset) / RE;
11422 const double coslat = cos(DEG2RAD(atm->lat[ip]));
11423 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
11424 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
11425 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
11426 fprintf(out, "%g %g %g\n", x, y, z);
11427 }
11428 } else
11429 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11430 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11431 continue;
11432 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
11433 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
11434 }
11435
11436 /* Write point data... */
11437 fprintf(out, "POINT_DATA %d\n", np);
11438 for (int iq = 0; iq < ctl->nq; iq++) {
11439 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
11440 ctl->qnt_name[iq]);
11441 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11442 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11443 continue;
11444 fprintf(out, "%g\n", atm->q[iq][ip]);
11445 }
11446 }
11447
11448 /* Close file... */
11449 fclose(out);
11450}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:6993
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:5677
void day2doy(const int year, const int mon, const int day, int *doy)
Get day of year from date.
Definition: mptrac.c:900
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:6953
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:7253
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:7581
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:9485
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:10845
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:4195
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:8348
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:10606
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:8828
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:2084
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:3922
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:5373
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:3238
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:6101
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:6792
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:2624
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:9001
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:1462
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:6068
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:7956
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:6849
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:7652
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:8656
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:8872
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:2509
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:2045
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:1095
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:4268
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:7496
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:6220
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:8093
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:3959
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:9954
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:3342
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:6192
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:7454
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:8900
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:7121
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:6562
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:1981
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:3063
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:1775
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:1165
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:10242
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:5565
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:9143
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:4389
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:1520
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:1395
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:949
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:4060
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:665
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:5868
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:9034
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:2362
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:6274
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:3797
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:9174
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:9300
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:1337
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:8520
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:1549
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:2551
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:6373
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:2266
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:8929
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:2239
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:3886
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:9081
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:1607
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:7810
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:6591
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:2011
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:9242
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:10904
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:4479
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:9277
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:10682
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:3661
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:4408
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:5621
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:5777
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:8319
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:4242
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:3692
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:1006
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:11293
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:9102
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:3432
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:919
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:1574
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:3610
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:2064
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:10577
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:8213
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:5956
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:1071
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:2663
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:3826
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:1698
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:6414
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:5428
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:9432
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:2865
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:6012
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:11379
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:3990
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:4539
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:8154
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:2980
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:10346
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:5892
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:2740
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:10874
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:3133
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:3526
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:988
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:1731
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:5914
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:1138
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:11131
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:10051
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:2917
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:10476
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:9382
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:6677
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:5737
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:1757
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:9692
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:9643
MPTRAC library declarations.
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1232
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:241
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:222
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1719
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:391
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1274
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:197
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:157
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:192
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:202
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:276
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:667
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1379
#define H0
Scale height [km].
Definition: mptrac.h:177
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1212
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1002
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:840
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1016
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:217
#define KARMAN
Karman's constant.
Definition: mptrac.h:187
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:682
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:987
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:1904
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1173
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:271
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1544
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:713
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:281
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:286
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:372
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:1741
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1304
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:182
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:172
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:301
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:251
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:647
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:525
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:461
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:266
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:167
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1352
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1644
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:227
#define NORM(a)
Compute the norm (magnitude) of a vector.
Definition: mptrac.h:1247
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1523
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1620
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1694
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1772
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1673
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:562
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:1871
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:1791
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1456
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:786
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:349
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1500
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:316
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:478
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:207
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1557
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1396
#define NC_INQ_DIM(dimname, ptr, min, max)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1103
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:246
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:1948
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:1984
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:696
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1426
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1150
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:291
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:1834
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:1045
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1595
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:416
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:256
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1075
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:261
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1328
void compress_zstd(const char *varname, float *array, const size_t n, const int decompress, FILE *inout)
Compresses or decompresses an array of floats using the Zstandard (ZSTD) library.
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1481
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:296
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1126
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:859
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:594
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:440
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:162
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:306
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:543
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:886
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:629
Air parcel data.
Definition: mptrac.h:3149
double time[NP]
Time [s].
Definition: mptrac.h:3155
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3164
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3161
int np
Number of air parcels.
Definition: mptrac.h:3152
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3167
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3158
Cache data structure.
Definition: mptrac.h:3177
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3198
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3186
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3189
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3183
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3195
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3192
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3180
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3209
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3215
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3224
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3245
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3221
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3239
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3242
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3236
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3230
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3251
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3254
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3233
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3248
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3227
int np
Number of pressure levels.
Definition: mptrac.h:3212
int no3c
Number of total ozone columns.
Definition: mptrac.h:3218
Climatological data.
Definition: mptrac.h:3317
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3359
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3335
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3347
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3338
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3320
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3365
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3353
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3356
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3350
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3329
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3344
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3323
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3341
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3332
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3326
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3362
Climatological data in the form of time series.
Definition: mptrac.h:3265
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3274
double time[CTS]
Time [s].
Definition: mptrac.h:3271
int ntime
Number of timesteps.
Definition: mptrac.h:3268
Climatological data in the form of zonal means.
Definition: mptrac.h:3285
double time[CT]
Time [s].
Definition: mptrac.h:3297
int np
Number of pressure levels.
Definition: mptrac.h:3294
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3303
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3306
int ntime
Number of timesteps.
Definition: mptrac.h:3288
int nlat
Number of latitudes.
Definition: mptrac.h:3291
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3300
Control parameters.
Definition: mptrac.h:2158
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3029
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2270
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:2993
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:2960
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2417
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2881
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2489
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2303
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:2969
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2743
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2249
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2441
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:2921
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2806
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2830
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2177
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2189
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2450
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2198
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2282
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:2963
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2291
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2782
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2731
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:2984
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2258
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3107
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2791
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2642
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2803
double stat_r
Search radius around station [km].
Definition: mptrac.h:3113
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2875
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:2987
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3137
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2827
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2610
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2279
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2845
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2695
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2429
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2532
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2357
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3056
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3032
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2453
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2649
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2435
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2562
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2629
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2321
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2384
char species[LEN]
Species.
Definition: mptrac.h:2740
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:2978
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:2990
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2677
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2607
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2273
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2686
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3017
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3035
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:2934
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2704
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3047
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2204
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2348
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2535
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2300
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3038
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2327
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2626
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3092
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2378
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2472
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2764
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2848
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2598
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3008
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2523
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2671
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2192
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2225
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2369
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2719
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3119
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:2954
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2668
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3053
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:2981
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2231
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2854
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3023
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2354
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2836
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2737
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2339
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2595
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2568
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2201
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2659
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3059
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2646
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2725
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2207
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3062
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:2957
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2604
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:2966
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2565
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2839
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2683
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2547
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2550
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3005
int met_zfp_prec
ZFP compression precision for all variables, except z and T.
Definition: mptrac.h:2498
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2526
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3065
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2264
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2710
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2620
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3071
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2186
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2617
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2195
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2635
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2794
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2387
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2324
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:2975
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3116
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2857
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2767
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2752
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:2893
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2800
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2345
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:2939
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2586
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2866
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:2951
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2902
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2222
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2213
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2414
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3125
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2459
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2701
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3095
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2315
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3002
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2486
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2243
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2363
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2553
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2716
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2613
int met_dx
Stride for longitudes.
Definition: mptrac.h:2556
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2815
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2475
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2375
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2761
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2869
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2462
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2662
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2402
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2396
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2246
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3134
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2261
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2342
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2713
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2632
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2318
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2174
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2420
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2583
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2851
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2267
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3080
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2366
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2255
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3101
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2749
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:2948
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3020
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2541
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2210
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2517
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3041
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2444
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2438
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2168
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:2918
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2818
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2234
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2294
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2652
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3068
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2589
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2252
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:2927
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2863
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2372
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2692
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:2996
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2872
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:2479
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:2972
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2381
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3110
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2423
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2890
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3044
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2447
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2408
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2574
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2689
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2469
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2728
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2520
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2824
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2306
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2707
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2797
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2312
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2722
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2809
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2773
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2411
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2399
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3026
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2758
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2219
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:2999
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3089
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:2930
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2601
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2821
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:2924
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2785
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3086
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2507
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2908
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2571
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3074
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2833
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2288
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2336
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2351
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2592
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3083
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2309
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2911
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3077
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2544
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2495
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2860
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2432
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2945
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2899
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2842
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2776
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2538
int met_cms_zstd
cmultiscale zstd compression (0=off, 1=on).
Definition: mptrac.h:2510
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3014
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3122
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2905
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2237
int met_np
Number of target pressure levels.
Definition: mptrac.h:2577
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2183
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2492
double met_zfp_tol_t
ZFP compression tolerance for temperature.
Definition: mptrac.h:2501
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2788
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2333
double met_zfp_tol_z
ZFP compression tolerance for geopotential height.
Definition: mptrac.h:2504
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3131
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2779
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2529
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2887
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2665
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2698
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2390
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev).
Definition: mptrac.h:2656
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2330
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2426
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2228
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2812
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2942
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2755
int met_cms_heur
cmultiscale coarsening heuristics (0=default, 1=mean diff, 2=median diff, 3=max diff).
Definition: mptrac.h:2514
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2896
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2360
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2216
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2884
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2878
int met_dy
Stride for latitudes.
Definition: mptrac.h:2559
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2405
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2680
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2734
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2180
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2623
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2276
double t_start
Start time of simulation [s].
Definition: mptrac.h:2456
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2171
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2580
int nq
Number of quantities.
Definition: mptrac.h:2165
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2746
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3098
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3128
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3104
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2674
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3050
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2240
int met_type
Type of meteo data files (0=netCDF, 1=binary, 2=pck, 3=zfp, 4=zstd, 5=cms).
Definition: mptrac.h:2483
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2285
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2297
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3011
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2393
Meteo data structure.
Definition: mptrac.h:3376
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3445
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3433
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3505
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3475
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3532
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3496
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3469
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3490
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3451
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3403
int nx
Number of longitudes.
Definition: mptrac.h:3382
int ny
Number of latitudes.
Definition: mptrac.h:3385
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3427
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3406
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3502
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3415
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3526
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3523
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3412
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3499
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3514
int np
Number of pressure levels.
Definition: mptrac.h:3388
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3481
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3409
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3484
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3421
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3520
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3454
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3466
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3472
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3460
double lon[EX]
Longitude [deg].
Definition: mptrac.h:3394
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3439
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3442
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3436
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3418
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3478
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3487
int npl
Number of model levels.
Definition: mptrac.h:3391
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3430
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3508
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3448
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3493
double time
Time [s].
Definition: mptrac.h:3379
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3457
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3424
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3517
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3463
double lat[EY]
Latitude [deg].
Definition: mptrac.h:3397
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3511
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3529
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3400