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 = cms_read_sol(cms_ptr, inout);
491
492 /* Evaluate... */
493#pragma omp parallel for default(shared)
494 for (size_t ix = 0; ix < nx; ix++)
495 for (size_t iy = 0; iy < ny; iy++) {
496 double val, x[] = { lon[ix], lat[iy] };
497 cms_eval(cms_ptr, cms_sol, x, &val);
498 array[ARRAY_3D(ix, iy, ny, ip, np)] = (float) val;
499 }
500
501 /* Calculate mean compression ratio... */
502 cr += cms_compression_rate(cms_ptr, cms_sol) / (double) np;
503
504 /* Free... */
505 cms_delete_sol(cms_sol);
506 cms_delete_module(cms_ptr);
507 }
508
509 /* Write info... */
510 LOG(2, "Read 3-D variable: %s (cms, RATIO= %g)", varname, cr);
511 }
512
513 /* Compress array and output compressed stream... */
514 else {
515
516 /* Init... */
517 cms_module_t *cms_ptr[EP];
518 cms_sol_t *cms_sol[EP];
519
520 /* Loop over batches... */
521 const size_t dip = (ctl->met_cms_batch <= 0
522 ? (size_t) omp_get_max_threads()
523 : (size_t) ctl->met_cms_batch);
524 for (size_t ip0 = 0; ip0 < np; ip0 += dip) {
525
526 /* Measure time... */
527 double t0 = omp_get_wtime();
528
529 /* Loop over levels... */
530#pragma omp parallel for default(shared)
531 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
532
533 /* Allocate... */
534 float *tmp_arr;
535 ALLOC(tmp_arr, float,
536 nxy);
537
538 /* Copy level data... */
539 for (size_t ix = 0; ix < nx; ++ix)
540 for (size_t iy = 0; iy < ny; ++iy)
541 tmp_arr[ARRAY_2D(ix, iy, ny)] =
542 array[ARRAY_3D(ix, iy, ny, ip, np)];
543
544 /* Initialize multiscale module... */
545 cms_ptr[ip] = cms_init(cms_param);
546
547 /* Create solution pointer... */
548 cms_sol[ip] = cms_read_arr(cms_ptr[ip], tmp_arr, lon, lat, nx, ny);
549
550 /* Set eps threshold value... */
551 if (strcasecmp(varname, "Z") == 0)
552 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_z);
553 else if (strcasecmp(varname, "T") == 0)
554 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_t);
555 else if (strcasecmp(varname, "U") == 0)
556 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_u);
557 else if (strcasecmp(varname, "V") == 0)
558 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_v);
559 else if (strcasecmp(varname, "W") == 0)
560 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_w);
561 else if (strcasecmp(varname, "PV") == 0)
562 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_pv);
563 else if (strcasecmp(varname, "H2O") == 0)
564 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_h2o);
565 else if (strcasecmp(varname, "O3") == 0)
566 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_o3);
567 else if (strcasecmp(varname, "LWC") == 0)
568 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_lwc);
569 else if (strcasecmp(varname, "RWC") == 0)
570 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_rwc);
571 else if (strcasecmp(varname, "IWC") == 0)
572 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_iwc);
573 else if (strcasecmp(varname, "SWC") == 0)
574 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_swc);
575 else if (strcasecmp(varname, "CC") == 0)
576 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_cc);
577 else
578 ERRMSG("Variable name unknown!");
579
580 /* Coarsening... */
581 cms_coarsening(cms_ptr[ip], cms_sol[ip],
582 (unsigned int) ctl->met_cms_heur);
583
584 /* Free... */
585 free(tmp_arr);
586 }
587
588 /* Measure time... */
589 t_coars += (omp_get_wtime() - t0);
590
591 /* Loop over levels... */
592 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
593
594 /* Allocate... */
595 double *tmp_cms, *tmp_org, *tmp_diff;
596 ALLOC(tmp_cms, double,
597 nxy);
598 ALLOC(tmp_org, double,
599 nxy);
600 ALLOC(tmp_diff, double,
601 nxy);
602
603 /* Measure time... */
604 t0 = omp_get_wtime();
605
606 /* Evaluate... */
607#pragma omp parallel for default(shared)
608 for (size_t ix = 0; ix < nx; ix++)
609 for (size_t iy = 0; iy < ny; iy++) {
610 size_t idx = ARRAY_2D(ix, iy, ny);
611 double x[] = { lon[ix], lat[iy] };
612 cms_eval(cms_ptr[ip], cms_sol[ip], x, &tmp_cms[idx]);
613 tmp_org[idx] = array[ARRAY_3D(ix, iy, ny, ip, np)];
614 tmp_diff[idx] = tmp_cms[idx] - tmp_org[idx];
615 }
616
617 /* Measure time... */
618 t_eval += (omp_get_wtime() - t0);
619
620 /* Write info... */
621 LOG(2,
622 "cmultiscale: var= %s / lev= %lu / ratio= %g / rho= %g"
623 " / mean= %g / sd= %g / min= %g / max= %g", varname, ip,
624 cms_compression_rate(cms_ptr[ip], cms_sol[ip]),
625 gsl_stats_correlation(tmp_cms, 1, tmp_org, 1, nxy),
626 gsl_stats_mean(tmp_diff, 1, nxy), gsl_stats_sd(tmp_diff, 1, nxy),
627 gsl_stats_min(tmp_diff, 1, nxy), gsl_stats_max(tmp_diff, 1, nxy));
628
629 /* Calculate mean compression ratio... */
630 cr += cms_compression_rate(cms_ptr[ip], cms_sol[ip]) / (double) np;
631
632 /* Save binary data... */
633 cms_save_sol(cms_sol[ip], inout);
634
635 /* Free... */
636 cms_delete_sol(cms_sol[ip]);
637 cms_delete_module(cms_ptr[ip]);
638 free(tmp_cms);
639 free(tmp_org);
640 free(tmp_diff);
641 }
642 }
643
644 /* Write info... */
645 LOG(2, "Write 3-D variable: %s"
646 " (cms, RATIO= %g, T_COARS= %g s, T_EVAL= %g s)",
647 varname, cr, t_coars, t_eval);
648 }
649
650 /* Free... */
651 cms_delete_param(cms_param);
652}
653#endif
654
655/*****************************************************************************/
656
658 const char *varname,
659 float *array,
660 const size_t nxy,
661 const size_t nz,
662 const int decompress,
663 FILE *inout) {
664
665 double min[EP], max[EP], off[EP], scl[EP];
666
667 unsigned short *sarray;
668
669 /* Allocate... */
670 ALLOC(sarray, unsigned short,
671 nxy * nz);
672
673 /* Read compressed stream and decompress array... */
674 if (decompress) {
675
676 /* Write info... */
677 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
678 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
679
680 /* Read data... */
681 FREAD(&scl, double,
682 nz,
683 inout);
684 FREAD(&off, double,
685 nz,
686 inout);
687 FREAD(sarray, unsigned short,
688 nxy * nz,
689 inout);
690
691 /* Convert to float... */
692#pragma omp parallel for default(shared)
693 for (size_t ixy = 0; ixy < nxy; ixy++)
694 for (size_t iz = 0; iz < nz; iz++)
695 array[ixy * nz + iz]
696 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
697 }
698
699 /* Compress array and output compressed stream... */
700 else {
701
702 /* Write info... */
703 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
704 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
705
706 /* Get range... */
707 for (size_t iz = 0; iz < nz; iz++) {
708 min[iz] = array[iz];
709 max[iz] = array[iz];
710 }
711 for (size_t ixy = 1; ixy < nxy; ixy++)
712 for (size_t iz = 0; iz < nz; iz++) {
713 if (array[ixy * nz + iz] < min[iz])
714 min[iz] = array[ixy * nz + iz];
715 if (array[ixy * nz + iz] > max[iz])
716 max[iz] = array[ixy * nz + iz];
717 }
718
719 /* Get offset and scaling factor... */
720 for (size_t iz = 0; iz < nz; iz++) {
721 scl[iz] = (max[iz] - min[iz]) / 65533.;
722 off[iz] = min[iz];
723 }
724
725 /* Convert to short... */
726#pragma omp parallel for default(shared)
727 for (size_t ixy = 0; ixy < nxy; ixy++)
728 for (size_t iz = 0; iz < nz; iz++)
729 if (scl[iz] != 0)
730 sarray[ixy * nz + iz] = (unsigned short)
731 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
732 else
733 sarray[ixy * nz + iz] = 0;
734
735 /* Write data... */
736 FWRITE(&scl, double,
737 nz,
738 inout);
739 FWRITE(&off, double,
740 nz,
741 inout);
742 FWRITE(sarray, unsigned short,
743 nxy * nz,
744 inout);
745 }
746
747 /* Free... */
748 free(sarray);
749}
750
751/*****************************************************************************/
752
753#ifdef ZFP
754void compress_zfp(
755 const char *varname,
756 float *array,
757 const int nx,
758 const int ny,
759 const int nz,
760 const int precision,
761 const double tolerance,
762 const int decompress,
763 FILE *inout) {
764
765 zfp_field *field; /* array meta data */
766 zfp_stream *zfp; /* compressed stream */
767 void *buffer; /* storage for compressed stream */
768 size_t bufsize; /* byte size of compressed buffer */
769 bitstream *stream; /* bit stream to write to or read from */
770 size_t zfpsize; /* byte size of compressed stream */
771
772 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
773 const zfp_type type = zfp_type_float;
774 field = zfp_field_3d(array, type, (uint) nx, (uint) ny, (uint) nz);
775
776 /* Allocate meta data for a compressed stream... */
777 zfp = zfp_stream_open(NULL);
778
779 /* Set compression mode... */
780 int actual_prec = 0;
781 double actual_tol = 0;
782 if (precision > 0)
783 actual_prec = (int) zfp_stream_set_precision(zfp, (uint) precision);
784 else if (tolerance > 0)
785 actual_tol = zfp_stream_set_accuracy(zfp, tolerance);
786 else
787 ERRMSG("Set precision or tolerance!");
788
789 /* Allocate buffer for compressed data... */
790 bufsize = zfp_stream_maximum_size(zfp, field);
791 buffer = malloc(bufsize);
792
793 /* Associate bit stream with allocated buffer... */
794 stream = stream_open(buffer, bufsize);
795 zfp_stream_set_bit_stream(zfp, stream);
796 zfp_stream_rewind(zfp);
797
798 /* Read compressed stream and decompress array... */
799 if (decompress) {
800 FREAD(&zfpsize, size_t,
801 1,
802 inout);
803 if (fread(buffer, 1, zfpsize, inout) != zfpsize)
804 ERRMSG("Error while reading zfp data!");
805 if (!zfp_decompress(zfp, field)) {
806 ERRMSG("Decompression failed!");
807 }
808 LOG(2, "Read 3-D variable: %s "
809 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
810 varname, actual_prec, actual_tol,
811 ((double) (nx * ny * nz)) / (double) zfpsize);
812 }
813
814 /* Compress array and output compressed stream... */
815 else {
816 zfpsize = zfp_compress(zfp, field);
817 if (!zfpsize) {
818 ERRMSG("Compression failed!");
819 } else {
820 FWRITE(&zfpsize, size_t,
821 1,
822 inout);
823 if (fwrite(buffer, 1, zfpsize, inout) != zfpsize)
824 ERRMSG("Error while writing zfp data!");
825 }
826 LOG(2, "Write 3-D variable: %s "
827 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
828 varname, actual_prec, actual_tol,
829 ((double) (nx * ny * nz)) / (double) zfpsize);
830 }
831
832 /* Free... */
833 zfp_field_free(field);
834 zfp_stream_close(zfp);
835 stream_close(stream);
836 free(buffer);
837}
838#endif
839
840/*****************************************************************************/
841
842#ifdef ZSTD
843void compress_zstd(
844 const char *varname,
845 float *array,
846 const size_t n,
847 const int decompress,
848 FILE *inout) {
849
850 /* Get buffer sizes... */
851 size_t uncomprLen = n * sizeof(float);
852 size_t comprLen = ZSTD_compressBound(uncomprLen);
853 size_t compsize;
854
855 /* Allocate... */
856 char *compr = (char *) calloc((uint) comprLen, 1);
857 char *uncompr = (char *) array;
858
859 /* Read compressed stream and decompress array... */
860 if (decompress) {
861 FREAD(&comprLen, size_t,
862 1,
863 inout);
864 if (fread(compr, 1, comprLen, inout) != comprLen)
865 ERRMSG("Error while reading zstd data!");
866 compsize = ZSTD_decompress(uncompr, uncomprLen, compr, comprLen);
867 if (ZSTD_isError(compsize)) {
868 ERRMSG("Decompression failed!");
869 }
870 LOG(2, "Read 3-D variable: %s (zstd, RATIO= %g)",
871 varname, ((double) uncomprLen) / (double) comprLen)
872 }
873
874 /* Compress array and output compressed stream... */
875 else {
876 compsize = ZSTD_compress(compr, comprLen, uncompr, uncomprLen, 0);
877 if (ZSTD_isError(compsize)) {
878 ERRMSG("Compression failed!");
879 } else {
880 FWRITE(&compsize, size_t,
881 1,
882 inout);
883 if (fwrite(compr, 1, compsize, inout) != compsize)
884 ERRMSG("Error while writing zstd data!");
885 }
886 LOG(2, "Write 3-D variable: %s (zstd, RATIO= %g)",
887 varname, ((double) uncomprLen) / (double) compsize);
888 }
889
890 /* Free... */
891 free(compr);
892}
893#endif
894
895/*****************************************************************************/
896
898 const int year,
899 const int mon,
900 const int day,
901 int *doy) {
902
903 const int
904 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
905 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
906
907 /* Get day of year... */
908 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
909 *doy = d0l[mon - 1] + day - 1;
910 else
911 *doy = d0[mon - 1] + day - 1;
912}
913
914/*****************************************************************************/
915
917 const int year,
918 const int doy,
919 int *mon,
920 int *day) {
921
922 const int
923 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
924 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
925
926 int i;
927
928 /* Get month and day... */
929 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
930 for (i = 11; i > 0; i--)
931 if (d0l[i] <= doy)
932 break;
933 *mon = i + 1;
934 *day = doy - d0l[i] + 1;
935 } else {
936 for (i = 11; i > 0; i--)
937 if (d0[i] <= doy)
938 break;
939 *mon = i + 1;
940 *day = doy - d0[i] + 1;
941 }
942}
943
944/*****************************************************************************/
945
947 double *fcReal,
948 double *fcImag,
949 const int n) {
950
951 double data[2 * EX];
952
953 /* Check size... */
954 if (n > EX)
955 ERRMSG("Too many data points!");
956
957 /* Allocate... */
958 gsl_fft_complex_wavetable *wavetable =
959 gsl_fft_complex_wavetable_alloc((size_t) n);
960 gsl_fft_complex_workspace *workspace =
961 gsl_fft_complex_workspace_alloc((size_t) n);
962
963 /* Set data (real, complex)... */
964 for (int i = 0; i < n; i++) {
965 data[2 * i] = fcReal[i];
966 data[2 * i + 1] = fcImag[i];
967 }
968
969 /* Calculate FFT... */
970 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
971
972 /* Copy data... */
973 for (int i = 0; i < n; i++) {
974 fcReal[i] = data[2 * i];
975 fcImag[i] = data[2 * i + 1];
976 }
977
978 /* Free... */
979 gsl_fft_complex_wavetable_free(wavetable);
980 gsl_fft_complex_workspace_free(workspace);
981}
982
983/*****************************************************************************/
984
986 const double z,
987 const double lon,
988 const double lat,
989 double *x) {
990
991 const double radius = z + RE;
992 const double latrad = DEG2RAD(lat);
993 const double lonrad = DEG2RAD(lon);
994 const double coslat = cos(latrad);
995
996 x[0] = radius * coslat * cos(lonrad);
997 x[1] = radius * coslat * sin(lonrad);
998 x[2] = radius * sin(latrad);
999}
1000
1001/*****************************************************************************/
1002
1004 ctl_t *ctl,
1005 clim_t *clim,
1006 const double t,
1007 met_t **met0,
1008 met_t **met1) {
1009
1010 static int init;
1011
1012 met_t *mets;
1013
1014 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
1015
1016 /* Set timer... */
1017 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1018
1019 /* Init... */
1020 if (t == ctl->t_start || !init) {
1021 init = 1;
1022
1023 /* Read meteo data... */
1024 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
1025 ctl->metbase, ctl->dt_met, filename);
1026 if (!read_met(filename, ctl, clim, *met0))
1027 ERRMSG("Cannot open file!");
1028
1029 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
1030 ctl->metbase, ctl->dt_met, filename);
1031 if (!read_met(filename, ctl, clim, *met1))
1032 ERRMSG("Cannot open file!");
1033
1034 /* Update GPU... */
1035#ifdef _OPENACC
1036 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
1037 met_t *met0up = *met0;
1038 met_t *met1up = *met1;
1039#ifdef ASYNCIO
1040#pragma acc update device(met0up[:1],met1up[:1]) async(5)
1041#else
1042#pragma acc update device(met0up[:1],met1up[:1])
1043#endif
1044 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1045#endif
1046
1047 /* Caching... */
1048 if (ctl->met_cache && t != ctl->t_stop) {
1049 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
1050 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
1051 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1052 LOG(1, "Caching: %s", cachefile);
1053 if (system(cmd) != 0)
1054 WARN("Caching command failed!");
1055 }
1056 }
1057
1058 /* Read new data for forward trajectories... */
1059 if (t > (*met1)->time) {
1060
1061 /* Pointer swap... */
1062 mets = *met1;
1063 *met1 = *met0;
1064 *met0 = mets;
1065
1066 /* Read new meteo data... */
1067 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
1068 if (!read_met(filename, ctl, clim, *met1))
1069 ERRMSG("Cannot open file!");
1070
1071 /* Update GPU... */
1072#ifdef _OPENACC
1073 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
1074 met_t *met1up = *met1;
1075#ifdef ASYNCIO
1076#pragma acc update device(met1up[:1]) async(5)
1077#else
1078#pragma acc update device(met1up[:1])
1079#endif
1080 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1081#endif
1082
1083 /* Caching... */
1084 if (ctl->met_cache && t != ctl->t_stop) {
1085 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
1086 cachefile);
1087 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1088 LOG(1, "Caching: %s", cachefile);
1089 if (system(cmd) != 0)
1090 WARN("Caching command failed!");
1091 }
1092 }
1093
1094 /* Read new data for backward trajectories... */
1095 if (t < (*met0)->time) {
1096
1097 /* Pointer swap... */
1098 mets = *met1;
1099 *met1 = *met0;
1100 *met0 = mets;
1101
1102 /* Read new meteo data... */
1103 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
1104 if (!read_met(filename, ctl, clim, *met0))
1105 ERRMSG("Cannot open file!");
1106
1107 /* Update GPU... */
1108#ifdef _OPENACC
1109 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
1110 met_t *met0up = *met0;
1111#ifdef ASYNCIO
1112#pragma acc update device(met0up[:1]) async(5)
1113#else
1114#pragma acc update device(met0up[:1])
1115#endif
1116 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
1117#endif
1118
1119 /* Caching... */
1120 if (ctl->met_cache && t != ctl->t_stop) {
1121 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
1122 cachefile);
1123 sprintf(cmd, "cat %s > /dev/null &", cachefile);
1124 LOG(1, "Caching: %s", cachefile);
1125 if (system(cmd) != 0)
1126 WARN("Caching command failed!");
1127 }
1128 }
1129
1130 /* Check that grids are consistent... */
1131 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
1132 if ((*met0)->nx != (*met1)->nx
1133 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
1134 ERRMSG("Meteo grid dimensions do not match!");
1135 for (int ix = 0; ix < (*met0)->nx; ix++)
1136 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
1137 ERRMSG("Meteo grid longitudes do not match!");
1138 for (int iy = 0; iy < (*met0)->ny; iy++)
1139 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
1140 ERRMSG("Meteo grid latitudes do not match!");
1141 for (int ip = 0; ip < (*met0)->np; ip++)
1142 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
1143 ERRMSG("Meteo grid pressure levels do not match!");
1144 }
1145}
1146
1147/*****************************************************************************/
1148
1150 const ctl_t *ctl,
1151 const double t,
1152 const int direct,
1153 const char *metbase,
1154 const double dt_met,
1155 char *filename) {
1156
1157 char repl[LEN];
1158
1159 double t6, r;
1160
1161 int year, mon, day, hour, min, sec;
1162
1163 /* Round time to fixed intervals... */
1164 if (direct == -1)
1165 t6 = floor(t / dt_met) * dt_met;
1166 else
1167 t6 = ceil(t / dt_met) * dt_met;
1168
1169 /* Decode time... */
1170 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1171
1172 /* Set filename of MPTRAC meteo files... */
1173 if (ctl->met_clams == 0) {
1174 if (ctl->met_type == 0)
1175 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1176 else if (ctl->met_type == 1)
1177 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1178 else if (ctl->met_type == 2)
1179 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1180 else if (ctl->met_type == 3)
1181 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1182 else if (ctl->met_type == 4)
1183 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1184 else if (ctl->met_type == 5)
1185 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1186 sprintf(repl, "%d", year);
1187 get_met_replace(filename, "YYYY", repl);
1188 sprintf(repl, "%02d", mon);
1189 get_met_replace(filename, "MM", repl);
1190 sprintf(repl, "%02d", day);
1191 get_met_replace(filename, "DD", repl);
1192 sprintf(repl, "%02d", hour);
1193 get_met_replace(filename, "HH", repl);
1194 }
1195
1196 /* Set filename of CLaMS meteo files... */
1197 else {
1198 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1199 sprintf(repl, "%d", year);
1200 get_met_replace(filename, "YYYY", repl);
1201 sprintf(repl, "%02d", year % 100);
1202 get_met_replace(filename, "YY", repl);
1203 sprintf(repl, "%02d", mon);
1204 get_met_replace(filename, "MM", repl);
1205 sprintf(repl, "%02d", day);
1206 get_met_replace(filename, "DD", repl);
1207 sprintf(repl, "%02d", hour);
1208 get_met_replace(filename, "HH", repl);
1209 }
1210}
1211
1212/*****************************************************************************/
1213
1215 char *orig,
1216 char *search,
1217 char *repl) {
1218
1219 char buffer[LEN];
1220
1221 /* Iterate... */
1222 for (int i = 0; i < 3; i++) {
1223
1224 /* Replace sub-string... */
1225 char *ch;
1226 if (!(ch = strstr(orig, search)))
1227 return;
1228 strncpy(buffer, orig, (size_t) (ch - orig));
1229 buffer[ch - orig] = 0;
1230 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1231 orig[0] = 0;
1232 strcpy(orig, buffer);
1233 }
1234}
1235
1236/*****************************************************************************/
1237
1239 const int met_tropo,
1240 ctl_t *ctl,
1241 clim_t *clim,
1242 met_t *met,
1243 const double *lons,
1244 const int nx,
1245 const double *lats,
1246 const int ny,
1247 double *pt,
1248 double *zt,
1249 double *tt,
1250 double *qt,
1251 double *o3t,
1252 double *ps,
1253 double *zs) {
1254
1256
1257 ctl->met_tropo = met_tropo;
1258 read_met_tropo(ctl, clim, met);
1259#pragma omp parallel for default(shared) private(ci,cw)
1260 for (int ix = 0; ix < nx; ix++)
1261 for (int iy = 0; iy < ny; iy++) {
1262 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1263 &pt[iy * nx + ix], ci, cw, 1);
1264 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1265 &ps[iy * nx + ix], ci, cw, 0);
1266 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1267 &zs[iy * nx + ix], ci, cw, 0);
1268 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1269 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1270 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1271 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1272 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1273 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1274 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1275 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1276 }
1277}
1278
1279/*****************************************************************************/
1280
1282 const met_t *met0,
1283 float heights0[EX][EY][EP],
1284 float array0[EX][EY][EP],
1285 const met_t *met1,
1286 float heights1[EX][EY][EP],
1287 float array1[EX][EY][EP],
1288 const double ts,
1289 const double height,
1290 const double lon,
1291 const double lat,
1292 double *var,
1293 int *ci,
1294 double *cw,
1295 const int init) {
1296
1297 if (init) {
1298
1299 /* Check longitude... */
1300 double lon2 = FMOD(lon, 360.);
1301 if (lon2 < met0->lon[0])
1302 lon2 += 360;
1303 else if (lon2 > met0->lon[met0->nx - 1])
1304 lon2 -= 360;
1305
1306 /* Get horizontal indizes... */
1307 ci[0] = locate_irr(met0->lon, met0->nx, lon2);
1308 ci[1] = locate_irr(met0->lat, met0->ny, lat);
1309
1310 /* Locate the vertical indizes for each edge of the column... */
1311 int ind[2][4];
1312 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1313 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1314
1315 /* Find minimum and maximum indizes... */
1316 ci[2] = ind[0][0];
1317 int k_max = ind[0][0];
1318 for (int i = 0; i < 2; i++)
1319 for (int j = 0; j < 4; j++) {
1320 if (ci[2] > ind[i][j])
1321 ci[2] = ind[i][j];
1322 if (k_max < ind[i][j])
1323 k_max = ind[i][j];
1324 }
1325
1326 /* Get weighting factors for time, longitude and latitude... */
1327 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1328 cw[0] = (lon2 - met0->lon[ci[0]]) /
1329 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1330 cw[1] = (lat - met0->lat[ci[1]]) /
1331 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1332
1333 /* Start determiniation of the altitude weighting factor... */
1334 double height_top, height_bot;
1335 double height00, height01, height10, height11, height0, height1;
1336
1337 /* Interpolate in time at the lowest level... */
1338 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1339 - heights0[ci[0]][ci[1]][ci[2]])
1340 + heights0[ci[0]][ci[1]][ci[2]];
1341 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1342 - heights0[ci[0]][ci[1] + 1][ci[2]])
1343 + heights0[ci[0]][ci[1] + 1][ci[2]];
1344 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1345 - heights0[ci[0] + 1][ci[1]][ci[2]])
1346 + heights0[ci[0] + 1][ci[1]][ci[2]];
1347 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1348 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1349 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1350
1351 /* Interpolate in latitude direction... */
1352 height0 = cw[1] * (height01 - height00) + height00;
1353 height1 = cw[1] * (height11 - height10) + height10;
1354
1355 /* Interpolate in longitude direction... */
1356 height_bot = cw[0] * (height1 - height0) + height0;
1357
1358 /* Interpolate in time at the upper level... */
1359 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1360 - heights0[ci[0]][ci[1]][ci[2] + 1])
1361 + heights0[ci[0]][ci[1]][ci[2] + 1];
1362 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1363 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1364 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1365 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1366 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1367 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1368 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1369 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1370 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1371
1372 /* Interpolate in latitude direction... */
1373 height0 = cw[1] * (height01 - height00) + height00;
1374 height1 = cw[1] * (height11 - height10) + height10;
1375
1376 /* Interpolate in longitude direction... */
1377 height_top = cw[0] * (height1 - height0) + height0;
1378
1379 /* Search at higher levels if height is not in box... */
1380 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1381 ((height_bot <= height) || (height_top > height))
1382 && (height_bot >= height) && (ci[2] < k_max))
1383 ||
1384 ((heights0[0][0][0] < heights0[0][0][1]) &&
1385 ((height_bot >= height) || (height_top < height))
1386 && (height_bot <= height) && (ci[2] < k_max))
1387 ) {
1388
1389 ci[2]++;
1390 height_bot = height_top;
1391
1392 /* Interpolate in time at the next level... */
1393 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1394 - heights0[ci[0]][ci[1]][ci[2] + 1])
1395 + heights0[ci[0]][ci[1]][ci[2] + 1];
1396 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1397 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1398 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1399 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1400 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1401 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1402 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1403 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1404 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1405
1406 /* Interpolate in latitude direction... */
1407 height0 = cw[1] * (height01 - height00) + height00;
1408 height1 = cw[1] * (height11 - height10) + height10;
1409
1410 /* Interpolate in longitude direction... */
1411 height_top = cw[0] * (height1 - height0) + height0;
1412 }
1413
1414 /* Get vertical weighting factors... */
1415 cw[2] = (height - height_bot)
1416 / (height_top - height_bot);
1417 }
1418
1419 /* Calculate the needed array values... */
1420 double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1421 - array0[ci[0]][ci[1]][ci[2]])
1422 + array0[ci[0]][ci[1]][ci[2]];
1423 double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1424 - array0[ci[0] + 1][ci[1]][ci[2]])
1425 + array0[ci[0] + 1][ci[1]][ci[2]];
1426 double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1427 - array0[ci[0]][ci[1] + 1][ci[2]])
1428 + array0[ci[0]][ci[1] + 1][ci[2]];
1429 double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1430 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1431 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1432 double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1433 - array0[ci[0]][ci[1]][ci[2] + 1])
1434 + array0[ci[0]][ci[1]][ci[2] + 1];
1435 double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
1436 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
1437 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
1438 double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
1439 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
1440 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
1441 double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1442 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1443 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1444
1445 double array00 = cw[0] * (array100 - array000) + array000;
1446 double array10 = cw[0] * (array110 - array010) + array010;
1447 double array01 = cw[0] * (array101 - array001) + array001;
1448 double array11 = cw[0] * (array111 - array011) + array011;
1449
1450 double aux0 = cw[1] * (array10 - array00) + array00;
1451 double aux1 = cw[1] * (array11 - array01) + array01;
1452
1453 /* Interpolate vertically... */
1454 *var = cw[2] * (aux1 - aux0) + aux0;
1455}
1456
1457/*****************************************************************************/
1458
1460 const met_t *met,
1461 float array[EX][EY][EP],
1462 const double p,
1463 const double lon,
1464 const double lat,
1465 double *var,
1466 int *ci,
1467 double *cw,
1468 const int init) {
1469
1470 /* Initialize interpolation... */
1471 if (init) {
1472
1473 /* Check longitude... */
1474 double lon2 = FMOD(lon, 360.);
1475 if (lon2 < met->lon[0])
1476 lon2 += 360;
1477 else if (lon2 > met->lon[met->nx - 1])
1478 lon2 -= 360;
1479
1480 /* Get interpolation indices... */
1481 ci[0] = locate_irr(met->p, met->np, p);
1482 ci[1] = locate_reg(met->lon, met->nx, lon2);
1483 ci[2] = locate_reg(met->lat, met->ny, lat);
1484
1485 /* Get interpolation weights... */
1486 cw[0] = (met->p[ci[0] + 1] - p)
1487 / (met->p[ci[0] + 1] - met->p[ci[0]]);
1488 cw[1] = (met->lon[ci[1] + 1] - lon2)
1489 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1490 cw[2] = (met->lat[ci[2] + 1] - lat)
1491 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1492 }
1493
1494 /* Interpolate vertically... */
1495 double aux00 =
1496 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
1497 + array[ci[1]][ci[2]][ci[0] + 1];
1498 double aux01 =
1499 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
1500 array[ci[1]][ci[2] + 1][ci[0] + 1])
1501 + array[ci[1]][ci[2] + 1][ci[0] + 1];
1502 double aux10 =
1503 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
1504 array[ci[1] + 1][ci[2]][ci[0] + 1])
1505 + array[ci[1] + 1][ci[2]][ci[0] + 1];
1506 double aux11 =
1507 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
1508 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
1509 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
1510
1511 /* Interpolate horizontally... */
1512 aux00 = cw[2] * (aux00 - aux01) + aux01;
1513 aux11 = cw[2] * (aux10 - aux11) + aux11;
1514 *var = cw[1] * (aux00 - aux11) + aux11;
1515}
1516
1517/*****************************************************************************/
1518
1520 const met_t *met,
1521 float array[EX][EY][EP],
1522 const double p,
1523 const double lon,
1524 const double lat,
1525 double *var) {
1526
1527 /* Check longitude... */
1528 double lon2 = FMOD(lon, 360.);
1529 if (lon2 < met->lon[0])
1530 lon2 += 360;
1531 else if (lon2 > met->lon[met->nx - 1])
1532 lon2 -= 360;
1533
1534 /* Get horizontal indices... */
1535 int ix = locate_reg(met->lon, met->nx, lon2);
1536 int iy = locate_reg(met->lat, met->ny, lat);
1537
1538 /* Interpolate vertically... */
1539 int iz = locate_irr_float(met->pl[ix][iy], met->npl, p, 0);
1540 double aux00;
1541 if (p >= met->pl[ix][iy][iz + 1])
1542 aux00 = array[ix][iy][iz + 1];
1543 else if (p <= met->pl[ix][iy][iz])
1544 aux00 = array[ix][iy][iz];
1545 else
1546 aux00 = LIN(met->pl[ix][iy][iz],
1547 array[ix][iy][iz],
1548 met->pl[ix][iy][iz + 1], array[ix][iy][iz + 1], p);
1549
1550 iz = locate_irr_float(met->pl[ix][iy + 1], met->npl, p, iz);
1551 double aux01;
1552 if (p >= met->pl[ix][iy + 1][iz + 1])
1553 aux01 = array[ix][iy + 1][iz + 1];
1554 else if (p <= met->pl[ix][iy + 1][iz])
1555 aux01 = array[ix][iy + 1][iz];
1556 else
1557 aux01 = LIN(met->pl[ix][iy + 1][iz],
1558 array[ix][iy + 1][iz],
1559 met->pl[ix][iy + 1][iz + 1], array[ix][iy + 1][iz + 1], p);
1560
1561 iz = locate_irr_float(met->pl[ix + 1][iy], met->npl, p, iz);
1562 double aux10;
1563 if (p >= met->pl[ix + 1][iy][iz + 1])
1564 aux10 = array[ix + 1][iy][iz + 1];
1565 else if (p <= met->pl[ix + 1][iy][iz])
1566 aux10 = array[ix + 1][iy][iz];
1567 else
1568 aux10 = LIN(met->pl[ix + 1][iy][iz],
1569 array[ix + 1][iy][iz],
1570 met->pl[ix + 1][iy][iz + 1], array[ix + 1][iy][iz + 1], p);
1571
1572 iz = locate_irr_float(met->pl[ix + 1][iy + 1], met->npl, p, iz);
1573 double aux11;
1574 if (p >= met->pl[ix + 1][iy + 1][iz + 1])
1575 aux11 = array[ix + 1][iy + 1][iz + 1];
1576 else if (p <= met->pl[ix + 1][iy + 1][iz])
1577 aux11 = array[ix + 1][iy + 1][iz];
1578 else
1579 aux11 = LIN(met->pl[ix + 1][iy + 1][iz],
1580 array[ix + 1][iy + 1][iz],
1581 met->pl[ix + 1][iy + 1][iz + 1],
1582 array[ix + 1][iy + 1][iz + 1], p);
1583
1584 /* Interpolate horizontally... */
1585 double aux0 = LIN(met->lat[iy], aux00, met->lat[iy + 1], aux01, lat);
1586 double aux1 = LIN(met->lat[iy], aux10, met->lat[iy + 1], aux11, lat);
1587 *var = LIN(met->lon[ix], aux0, met->lon[ix + 1], aux1, lon2);
1588}
1589
1590/*****************************************************************************/
1591
1593 const met_t *met,
1594 float array[EX][EY],
1595 const double lon,
1596 const double lat,
1597 double *var,
1598 int *ci,
1599 double *cw,
1600 const int init) {
1601
1602 /* Initialize interpolation... */
1603 if (init) {
1604
1605 /* Check longitude... */
1606 double lon2 = FMOD(lon, 360.);
1607 if (lon2 < met->lon[0])
1608 lon2 += 360;
1609 else if (lon2 > met->lon[met->nx - 1])
1610 lon2 -= 360;
1611
1612 /* Get interpolation indices... */
1613 ci[1] = locate_reg(met->lon, met->nx, lon2);
1614 ci[2] = locate_reg(met->lat, met->ny, lat);
1615
1616 /* Get interpolation weights... */
1617 cw[1] = (met->lon[ci[1] + 1] - lon2)
1618 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1619 cw[2] = (met->lat[ci[2] + 1] - lat)
1620 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1621 }
1622
1623 /* Set variables... */
1624 double aux00 = array[ci[1]][ci[2]];
1625 double aux01 = array[ci[1]][ci[2] + 1];
1626 double aux10 = array[ci[1] + 1][ci[2]];
1627 double aux11 = array[ci[1] + 1][ci[2] + 1];
1628
1629 /* Interpolate horizontally... */
1630 if (isfinite(aux00) && isfinite(aux01)
1631 && isfinite(aux10) && isfinite(aux11)) {
1632 aux00 = cw[2] * (aux00 - aux01) + aux01;
1633 aux11 = cw[2] * (aux10 - aux11) + aux11;
1634 *var = cw[1] * (aux00 - aux11) + aux11;
1635 } else {
1636 if (cw[2] < 0.5) {
1637 if (cw[1] < 0.5)
1638 *var = aux11;
1639 else
1640 *var = aux01;
1641 } else {
1642 if (cw[1] < 0.5)
1643 *var = aux10;
1644 else
1645 *var = aux00;
1646 }
1647 }
1648}
1649
1650/*****************************************************************************/
1651
1653 const met_t *met0,
1654 float array0[EX][EY][EP],
1655 const met_t *met1,
1656 float array1[EX][EY][EP],
1657 const double ts,
1658 const double p,
1659 const double lon,
1660 const double lat,
1661 double *var,
1662 int *ci,
1663 double *cw,
1664 const int init) {
1665
1666 double var0, var1;
1667
1668 /* Spatial interpolation... */
1669 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
1670 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
1671
1672 /* Get weighting factor... */
1673 const double wt = (met1->time - ts) / (met1->time - met0->time);
1674
1675 /* Interpolate... */
1676 *var = wt * (var0 - var1) + var1;
1677}
1678
1679/*****************************************************************************/
1680
1682 const met_t *met0,
1683 float array0[EX][EY][EP],
1684 const met_t *met1,
1685 float array1[EX][EY][EP],
1686 const double ts,
1687 const double p,
1688 const double lon,
1689 const double lat,
1690 double *var) {
1691
1692 double var0, var1;
1693
1694 /* Spatial interpolation... */
1695 intpol_met_space_3d_ml(met0, array0, p, lon, lat, &var0);
1696 intpol_met_space_3d_ml(met1, array1, p, lon, lat, &var1);
1697
1698 /* Interpolate... */
1699 *var = LIN(met0->time, var0, met1->time, var1, ts);
1700}
1701
1702/*****************************************************************************/
1703
1705 const met_t *met0,
1706 float array0[EX][EY],
1707 const met_t *met1,
1708 float array1[EX][EY],
1709 const double ts,
1710 const double lon,
1711 const double lat,
1712 double *var,
1713 int *ci,
1714 double *cw,
1715 const int init) {
1716
1717 double var0, var1;
1718
1719 /* Spatial interpolation... */
1720 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
1721 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
1722
1723 /* Get weighting factor... */
1724 const double wt = (met1->time - ts) / (met1->time - met0->time);
1725
1726 /* Interpolate... */
1727 if (isfinite(var0) && isfinite(var1))
1728 *var = wt * (var0 - var1) + var1;
1729 else if (wt < 0.5)
1730 *var = var1;
1731 else
1732 *var = var0;
1733}
1734
1735/*****************************************************************************/
1736
1738 const double time0,
1739 float array0[EX][EY],
1740 const double time1,
1741 float array1[EX][EY],
1742 const double lons[EX],
1743 const double lats[EY],
1744 const int nlon,
1745 const int nlat,
1746 const double time,
1747 const double lon,
1748 const double lat,
1749 const int method,
1750 double *var,
1751 double *sigma) {
1752
1753 double aux0, aux1, aux00, aux01, aux10, aux11, mean = 0;
1754
1755 int n = 0;
1756
1757 /* Check longitude... */
1758 double lon2 = FMOD(lon, 360.);
1759 if (lon2 < lons[0])
1760 lon2 += 360;
1761 else if (lon2 > lons[nlon - 1])
1762 lon2 -= 360;
1763
1764 /* Get indices... */
1765 const int ix = locate_reg(lons, (int) nlon, lon2);
1766 const int iy = locate_reg(lats, (int) nlat, lat);
1767
1768 /* Calculate standard deviation... */
1769 *sigma = 0;
1770 for (int dx = 0; dx < 2; dx++)
1771 for (int dy = 0; dy < 2; dy++) {
1772 if (isfinite(array0[ix + dx][iy + dy])) {
1773 mean += array0[ix + dx][iy + dy];
1774 *sigma += SQR(array0[ix + dx][iy + dy]);
1775 n++;
1776 }
1777 if (isfinite(array1[ix + dx][iy + dy])) {
1778 mean += array1[ix + dx][iy + dy];
1779 *sigma += SQR(array1[ix + dx][iy + dy]);
1780 n++;
1781 }
1782 }
1783 if (n > 0)
1784 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
1785
1786 /* Linear interpolation... */
1787 if (method == 1 && isfinite(array0[ix][iy])
1788 && isfinite(array0[ix][iy + 1])
1789 && isfinite(array0[ix + 1][iy])
1790 && isfinite(array0[ix + 1][iy + 1])
1791 && isfinite(array1[ix][iy])
1792 && isfinite(array1[ix][iy + 1])
1793 && isfinite(array1[ix + 1][iy])
1794 && isfinite(array1[ix + 1][iy + 1])) {
1795
1796 aux00 = LIN(lons[ix], array0[ix][iy],
1797 lons[ix + 1], array0[ix + 1][iy], lon2);
1798 aux01 = LIN(lons[ix], array0[ix][iy + 1],
1799 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1800 aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat);
1801
1802 aux10 = LIN(lons[ix], array1[ix][iy],
1803 lons[ix + 1], array1[ix + 1][iy], lon2);
1804 aux11 = LIN(lons[ix], array1[ix][iy + 1],
1805 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1806 aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat);
1807
1808 *var = LIN(time0, aux0, time1, aux1, time);
1809 }
1810
1811 /* Nearest neighbor interpolation... */
1812 else {
1813 aux00 = NN(lons[ix], array0[ix][iy],
1814 lons[ix + 1], array0[ix + 1][iy], lon2);
1815 aux01 = NN(lons[ix], array0[ix][iy + 1],
1816 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1817 aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat);
1818
1819 aux10 = NN(lons[ix], array1[ix][iy],
1820 lons[ix + 1], array1[ix + 1][iy], lon2);
1821 aux11 = NN(lons[ix], array1[ix][iy + 1],
1822 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1823 aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat);
1824
1825 *var = NN(time0, aux0, time1, aux1, time);
1826 }
1827}
1828
1829/*****************************************************************************/
1830
1832 const double jsec,
1833 int *year,
1834 int *mon,
1835 int *day,
1836 int *hour,
1837 int *min,
1838 int *sec,
1839 double *remain) {
1840
1841 struct tm t0, *t1;
1842
1843 t0.tm_year = 100;
1844 t0.tm_mon = 0;
1845 t0.tm_mday = 1;
1846 t0.tm_hour = 0;
1847 t0.tm_min = 0;
1848 t0.tm_sec = 0;
1849
1850 const time_t jsec0 = (time_t) jsec + timegm(&t0);
1851 t1 = gmtime(&jsec0);
1852
1853 *year = t1->tm_year + 1900;
1854 *mon = t1->tm_mon + 1;
1855 *day = t1->tm_mday;
1856 *hour = t1->tm_hour;
1857 *min = t1->tm_min;
1858 *sec = t1->tm_sec;
1859 *remain = jsec - floor(jsec);
1860}
1861
1862/*****************************************************************************/
1863
1865 const double kz[EP],
1866 const double kw[EP],
1867 const int nk,
1868 const double p) {
1869
1870 /* Check number of data points... */
1871 if (nk < 2)
1872 return 1.0;
1873
1874 /* Get altitude... */
1875 const double z = Z(p);
1876
1877 /* Get weighting factor... */
1878 if (z < kz[0])
1879 return kw[0];
1880 else if (z > kz[nk - 1])
1881 return kw[nk - 1];
1882 else {
1883 int idx = locate_irr(kz, nk, z);
1884 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
1885 }
1886}
1887
1888/*****************************************************************************/
1889
1891 const double t,
1892 const double h2o) {
1893
1894 /*
1895 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
1896 and water vapor volume mixing ratio [1].
1897
1898 Reference: https://en.wikipedia.org/wiki/Lapse_rate
1899 */
1900
1901 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
1902
1903 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
1904}
1905
1906/*****************************************************************************/
1907
1909 ctl_t *ctl) {
1910
1911 if (0 == ctl->met_press_level_def) {
1912
1913 ctl->met_np = 138;
1914
1915 const double press[138] = {
1916 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1917 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1918 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1919 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1920 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1921 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1922 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1923 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1924 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1925 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1926 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1927 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1928 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1929 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1930 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1931 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1932 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1933 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1934 1010.8487, 1013.2500, 1044.45
1935 };
1936
1937 for (int ip = 0; ip < ctl->met_np; ip++)
1938 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1939
1940 } else if (1 == ctl->met_press_level_def) {
1941
1942 ctl->met_np = 92;
1943
1944 const double press[92] = {
1945 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1946 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1947 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1948 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1949 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1950 113.6382,
1951 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1952 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1953 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1954 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1955 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1956 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1957 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1958 1007.4431, 1010.8487, 1013.2500, 1044.45
1959 };
1960
1961 for (int ip = 0; ip < ctl->met_np; ip++)
1962 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1963
1964 } else if (2 == ctl->met_press_level_def) {
1965
1966 ctl->met_np = 60;
1967
1968 const double press[60] = {
1969 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1970 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1971 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1972 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1973 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1974 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1975 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1976 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1044.45
1977 };
1978
1979 for (int ip = 0; ip < ctl->met_np; ip++)
1980 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1981
1982 } else if (3 == ctl->met_press_level_def) {
1983
1984 ctl->met_np = 147;
1985
1986 const double press[147] = {
1987 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1988 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1989 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1990 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1991 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1992 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1993 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1994 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1995 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1996 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1997 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1998 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1999 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
2000 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
2001 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
2002 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
2003 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
2004 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
2005 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
2006 1031.97,
2007 1035.09, 1038.21, 1041.33, 1044.45
2008 };
2009
2010 for (int ip = 0; ip < ctl->met_np; ip++)
2011 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2012
2013 } else if (4 == ctl->met_press_level_def) {
2014
2015 ctl->met_np = 101;
2016
2017 const double press[101] = {
2018 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
2019 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
2020 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
2021 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
2022 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
2023 113.6382,
2024 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
2025 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
2026 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
2027 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
2028 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
2029 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
2030 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
2031 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
2032 1028.85, 1031.97,
2033 1035.09, 1038.21, 1041.33, 1044.45
2034 };
2035
2036 for (int ip = 0; ip < ctl->met_np; ip++)
2037 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2038
2039 } else if (5 == ctl->met_press_level_def) {
2040
2041 ctl->met_np = 62;
2042
2043 const double press[62] = {
2044 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
2045 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
2046 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
2047 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
2048 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
2049 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
2050 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
2051 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
2052 1044.45
2053 };
2054
2055 for (int ip = 0; ip < ctl->met_np; ip++)
2056 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2057
2058 } else if (6 == ctl->met_press_level_def) {
2059
2060 ctl->met_np = 137;
2061
2062 const double press[137] = {
2063 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
2064 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
2065 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
2066 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
2067 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
2068 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
2069 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
2070 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
2071 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
2072 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
2073 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
2074 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
2075 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
2076 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
2077 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
2078 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
2079 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
2080 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
2081 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
2082 1030.06, 1037.25, 1044.45
2083 };
2084
2085 for (int ip = 0; ip < ctl->met_np; ip++)
2086 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2087
2088 } else if (7 == ctl->met_press_level_def) {
2089
2090 ctl->met_np = 59;
2091
2092 const double press[59] = {
2093 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
2094 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
2095 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
2096 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
2097 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
2098 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
2099 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
2100 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
2101 1028.53, 1046.13
2102 };
2103
2104 for (int ip = 0; ip < ctl->met_np; ip++)
2105 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
2106
2107 } else {
2108 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.")
2109 }
2110}
2111
2112/*****************************************************************************/
2113
2115 const double *xx,
2116 const int n,
2117 const double x) {
2118
2119 int ilo = 0;
2120 int ihi = n - 1;
2121 int i = (ihi + ilo) >> 1;
2122
2123 if (xx[i] < xx[i + 1])
2124 while (ihi > ilo + 1) {
2125 i = (ihi + ilo) >> 1;
2126 if (xx[i] > x)
2127 ihi = i;
2128 else
2129 ilo = i;
2130 } else
2131 while (ihi > ilo + 1) {
2132 i = (ihi + ilo) >> 1;
2133 if (xx[i] <= x)
2134 ihi = i;
2135 else
2136 ilo = i;
2137 }
2138
2139 return ilo;
2140}
2141
2142/*****************************************************************************/
2143
2145 const float *xx,
2146 const int n,
2147 const double x,
2148 const int ig) {
2149
2150 int ilo = 0;
2151 int ihi = n - 1;
2152 int i = (ihi + ilo) >> 1;
2153
2154 if (x >= xx[ig] && x < xx[ig + 1])
2155 return ig;
2156
2157 if (xx[i] < xx[i + 1])
2158 while (ihi > ilo + 1) {
2159 i = (ihi + ilo) >> 1;
2160 if (xx[i] > x)
2161 ihi = i;
2162 else
2163 ilo = i;
2164 } else
2165 while (ihi > ilo + 1) {
2166 i = (ihi + ilo) >> 1;
2167 if (xx[i] <= x)
2168 ihi = i;
2169 else
2170 ilo = i;
2171 }
2172
2173 return ilo;
2174}
2175
2176/*****************************************************************************/
2177
2179 const double *xx,
2180 const int n,
2181 const double x) {
2182
2183 /* Calculate index... */
2184 int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2185
2186 /* Check range... */
2187 if (i < 0)
2188 return 0;
2189 else if (i > n - 2)
2190 return n - 2;
2191 else
2192 return i;
2193}
2194
2195/*****************************************************************************/
2196
2198 float profiles[EX][EY][EP],
2199 const int np,
2200 const int lon_ap_ind,
2201 const int lat_ap_ind,
2202 const double height_ap,
2203 int *ind) {
2204
2205 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2206 np, height_ap, 0);
2207 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2208 np, height_ap, ind[0]);
2209 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2210 np, height_ap, ind[1]);
2211 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2212 np, height_ap, ind[2]);
2213}
2214
2215/*****************************************************************************/
2216
2218 const ctl_t *ctl,
2219 const cache_t *cache,
2220 met_t *met0,
2221 met_t *met1,
2222 atm_t *atm) {
2223
2224 /* Set timer... */
2225 SELECT_TIMER("MODULE_ADVECTION", "PHYSICS", NVTX_GPU);
2226
2227 /* Pressure coordinate... */
2228 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2229
2230 /* Loop over particles... */
2231 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2232
2233 /* Init... */
2235 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2236 x[3] = { 0, 0, 0 };
2237
2238 /* Loop over integration nodes... */
2239 for (int i = 0; i < ctl->advect; i++) {
2240
2241 /* Set position... */
2242 if (i == 0) {
2243 dts = 0.0;
2244 x[0] = atm->lon[ip];
2245 x[1] = atm->lat[ip];
2246 x[2] = atm->p[ip];
2247 } else {
2248 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2249 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2250 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2251 x[2] = atm->p[ip] + dts * w[i - 1];
2252 }
2253 const double tm = atm->time[ip] + dts;
2254
2255 /* Interpolate meteo data on pressure levels... */
2256 if (ctl->advect_vert_coord == 0) {
2257 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2258 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2259 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2260 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2261 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2262 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2263 }
2264
2265 /* Interpolate meteo data on model levels... */
2266 else {
2267 intpol_met_time_3d_ml(met0, met0->ul, met1, met1->ul, tm, x[2],
2268 x[0], x[1], &u[i]);
2269 intpol_met_time_3d_ml(met0, met0->vl, met1, met1->vl, tm, x[2],
2270 x[0], x[1], &v[i]);
2271 intpol_met_time_3d_ml(met0, met0->wl, met1, met1->wl, tm, x[2],
2272 x[0], x[1], &w[i]);
2273 }
2274
2275 /* Get mean wind... */
2276 double k = 1.0;
2277 if (ctl->advect == 2)
2278 k = (i == 0 ? 0.0 : 1.0);
2279 else if (ctl->advect == 4)
2280 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2281 um += k * u[i];
2282 vm += k * v[i];
2283 wm += k * w[i];
2284 }
2285
2286 /* Set new position... */
2287 atm->time[ip] += cache->dt[ip];
2288 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2289 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2290 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2291 atm->p[ip] += cache->dt[ip] * wm;
2292 }
2293 }
2294
2295 /* Zeta coordinate... */
2296 else if (ctl->advect_vert_coord == 1) {
2297
2298 /* Loop over particles... */
2299 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2300
2301 /* Convert pressure to zeta... */
2303 intpol_met_4d_coord(met0, met0->pl, met0->zetal, met1,
2304 met1->pl, met1->zetal, atm->time[ip], atm->p[ip],
2305 atm->lon[ip], atm->lat[ip],
2306 &atm->q[ctl->qnt_zeta][ip], ci, cw, 1);
2307
2308 /* Init... */
2309 double dts, u[4], um = 0, v[4], vm = 0, zeta_dot[4],
2310 zeta_dotm = 0, x[3] = { 0, 0, 0 };
2311
2312 /* Loop over integration nodes... */
2313 for (int i = 0; i < ctl->advect; i++) {
2314
2315 /* Set position... */
2316 if (i == 0) {
2317 dts = 0.0;
2318 x[0] = atm->lon[ip];
2319 x[1] = atm->lat[ip];
2320 x[2] = atm->q[ctl->qnt_zeta][ip];
2321 } else {
2322 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2323 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2324 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2325 x[2] = atm->q[ctl->qnt_zeta][ip] + dts * zeta_dot[i - 1];
2326 }
2327 const double tm = atm->time[ip] + dts;
2328
2329 /* Interpolate meteo data... */
2330 intpol_met_4d_coord(met0, met0->zetal, met0->ul, met1, met1->zetal,
2331 met1->ul, tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2332 intpol_met_4d_coord(met0, met0->zetal, met0->vl, met1, met0->zetal,
2333 met1->vl, tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2334 intpol_met_4d_coord(met0, met0->zetal, met0->zeta_dotl, met1,
2335 met1->zetal, met1->zeta_dotl, tm, x[2], x[0],
2336 x[1], &zeta_dot[i], ci, cw, 0);
2337
2338 /* Get mean wind... */
2339 double k = 1.0;
2340 if (ctl->advect == 2)
2341 k = (i == 0 ? 0.0 : 1.0);
2342 else if (ctl->advect == 4)
2343 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2344 um += k * u[i];
2345 vm += k * v[i];
2346 zeta_dotm += k * zeta_dot[i];
2347 }
2348
2349 /* Set new position... */
2350 atm->time[ip] += cache->dt[ip];
2351 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2352 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2353 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2354 atm->q[ctl->qnt_zeta][ip] += cache->dt[ip] * zeta_dotm;
2355
2356 /* Check if zeta is below zero... */
2357 if (atm->q[ctl->qnt_zeta][ip] < 0)
2358 atm->q[ctl->qnt_zeta][ip] = 0; /* TODO: reflect particle, or skip this test (use module_position) */
2359
2360 /* Convert zeta to pressure... */
2361 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2362 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2363 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2364 }
2365 }
2366}
2367
2368/*****************************************************************************/
2369
2371 const ctl_t *ctl,
2372 met_t *met0,
2373 met_t *met1,
2374 atm_t *atm) {
2375
2376 /* Initialize pressure consistent with zeta... */
2377 if (ctl->advect_vert_coord == 1) {
2378#pragma omp parallel for default(shared)
2379 for (int ip = 0; ip < atm->np; ip++) {
2380
2381 /* Check time... */
2382 if (atm->time[ip] < met0->time || atm->time[ip] > met1->time)
2383 ERRMSG("Time of air parcel is out of range!");
2384
2385 /* Interpolate pressure... */
2387 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2388 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2389 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2390 }
2391 }
2392}
2393
2394/*****************************************************************************/
2395
2397 const ctl_t *ctl,
2398 const cache_t *cache,
2399 const clim_t *clim,
2400 met_t *met0,
2401 met_t *met1,
2402 atm_t *atm) {
2403
2404 /* Set timer... */
2405 SELECT_TIMER("MODULE_BOUNDCOND", "PHYSICS", NVTX_GPU);
2406
2407 /* Check quantity flags... */
2408 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2409 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2410 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2411 return;
2412
2413 /* Loop over particles... */
2414 PARTICLE_LOOP(0, atm->np, 1,
2415 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2416
2417 /* Check latitude and pressure range... */
2418 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2419 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2420 continue;
2421
2422 /* Check surface layer... */
2423 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2424 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2425
2426 /* Get surface pressure... */
2427 double ps;
2429 INTPOL_2D(ps, 1);
2430
2431 /* Check pressure... */
2432 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2433 continue;
2434
2435 /* Check height... */
2436 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2437 continue;
2438
2439 /* Check zeta range... */
2440 if (ctl->bound_zetas > 0) {
2441 double t;
2442 INTPOL_3D(t, 1);
2443 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2444 continue;
2445 }
2446
2447 /* Check planetary boundary layer... */
2448 if (ctl->bound_pbl) {
2449 double pbl;
2450 INTPOL_2D(pbl, 0);
2451 if (atm->p[ip] < pbl)
2452 continue;
2453 }
2454 }
2455
2456 /* Set mass and volume mixing ratio... */
2457 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2458 atm->q[ctl->qnt_m][ip] =
2459 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2460 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2461 atm->q[ctl->qnt_vmr][ip] =
2462 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2463
2464 /* Set CFC-10 volume mixing ratio... */
2465 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2466 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2467
2468 /* Set CFC-11 volume mixing ratio... */
2469 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2470 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2471
2472 /* Set CFC-12 volume mixing ratio... */
2473 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2474 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2475
2476 /* Set N2O volume mixing ratio... */
2477 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2478 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2479
2480 /* Set SF6 volume mixing ratio... */
2481 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2482 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2483
2484 /* Set age of air... */
2485 if (ctl->qnt_aoa >= 0)
2486 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2487 }
2488}
2489
2490/*****************************************************************************/
2491
2493 const ctl_t *ctl,
2494 met_t *met0,
2495 met_t *met1,
2496 atm_t *atm,
2497 const double tt) {
2498
2499 /* Check quantities... */
2500 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
2501 return;
2502 if (ctl->molmass <= 0)
2503 ERRMSG("Molar mass is not defined!");
2504
2505 /* Set timer... */
2506 SELECT_TIMER("MODULE_CHEMGRID", "PHYSICS", NVTX_GPU);
2507
2508 /* Allocate... */
2509 const int np = atm->np;
2510 const int nz = ctl->chemgrid_nz;
2511 const int nx = ctl->chemgrid_nx;
2512 const int ny = ctl->chemgrid_ny;
2513 const int ngrid = nx * ny * nz;
2514
2515 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2516 double *restrict const press =
2517 (double *) malloc((size_t) nz * sizeof(double));
2518 double *restrict const mass =
2519 (double *) calloc((size_t) ngrid, sizeof(double));
2520 double *restrict const area =
2521 (double *) malloc((size_t) ny * sizeof(double));
2522 double *restrict const lon =
2523 (double *) malloc((size_t) nx * sizeof(double));
2524 double *restrict const lat =
2525 (double *) malloc((size_t) ny * sizeof(double));
2526
2527 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2528 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2529 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2530
2531 /* Set grid box size... */
2532 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2533 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2534 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2535
2536 /* Set vertical coordinates... */
2537#ifdef _OPENACC
2538#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])
2539#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2540#pragma acc parallel loop independent gang vector
2541#else
2542#pragma omp parallel for default(shared)
2543#endif
2544 for (int iz = 0; iz < nz; iz++) {
2545 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2546 press[iz] = P(z[iz]);
2547 }
2548
2549 /* Set time interval for output... */
2550 const double t0 = tt - 0.5 * ctl->dt_mod;
2551 const double t1 = tt + 0.5 * ctl->dt_mod;
2552
2553 /* Get indices... */
2554#ifdef _OPENACC
2555#pragma acc parallel loop independent gang vector
2556#else
2557#pragma omp parallel for default(shared)
2558#endif
2559 for (int ip = 0; ip < np; ip++) {
2560 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2561 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2562 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2563 if (atm->time[ip] < t0 || atm->time[ip] > t1
2564 || ixs[ip] < 0 || ixs[ip] >= nx
2565 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2566 izs[ip] = -1;
2567 }
2568
2569 /* Set horizontal coordinates... */
2570#ifdef _OPENACC
2571#pragma acc parallel loop independent gang vector
2572#else
2573#pragma omp parallel for default(shared)
2574#endif
2575 for (int ix = 0; ix < nx; ix++)
2576 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
2577#ifdef _OPENACC
2578#pragma acc parallel loop independent gang vector
2579#else
2580#pragma omp parallel for default(shared)
2581#endif
2582 for (int iy = 0; iy < ny; iy++) {
2583 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
2584 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
2585 }
2586
2587 /* Get mass per grid box... */
2588#ifdef _OPENACC
2589#pragma acc parallel loop independent gang vector
2590#endif
2591 for (int ip = 0; ip < np; ip++)
2592 if (izs[ip] >= 0)
2593#ifdef _OPENACC
2594#pragma acc atomic update
2595#endif
2596 mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)]
2597 += atm->q[ctl->qnt_m][ip];
2598
2599 /* Assign grid data to air parcels ... */
2600#ifdef _OPENACC
2601#pragma acc parallel loop independent gang vector
2602#else
2603#pragma omp parallel for default(shared)
2604#endif
2605 for (int ip = 0; ip < np; ip++)
2606 if (izs[ip] >= 0) {
2607
2608 /* Interpolate temperature... */
2609 double temp;
2611 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt, press[izs[ip]],
2612 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
2613
2614 /* Set mass... */
2615 const double m = mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)];
2616
2617 /* Calculate volume mixing ratio... */
2618 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
2619 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
2620 }
2621#ifdef _OPENACC
2622#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
2623#endif
2624
2625 /* Free... */
2626 free(mass);
2627 free(lon);
2628 free(lat);
2629 free(area);
2630 free(z);
2631 free(press);
2632 free(ixs);
2633 free(iys);
2634 free(izs);
2635}
2636
2637/*****************************************************************************/
2638
2640 const ctl_t *ctl,
2641 const clim_t *clim,
2642 met_t *met0,
2643 met_t *met1,
2644 atm_t *atm) {
2645
2646#pragma omp parallel for default(shared)
2647 for (int ip = 0; ip < atm->np; ip++) {
2648
2649 /* Check time... */
2650 if (atm->time[ip] < met0->time || atm->time[ip] > met1->time)
2651 ERRMSG("Time of air parcel is out of range!");
2652
2653 /* Set H2O and O3 using meteo data... */
2655 if (ctl->qnt_Ch2o >= 0) {
2656 double h2o;
2657 INTPOL_3D(h2o, 1);
2658 SET_ATM(qnt_Ch2o, h2o);
2659 }
2660 if (ctl->qnt_Co3 >= 0) {
2661 double o3;
2662 INTPOL_3D(o3, 1);
2663 SET_ATM(qnt_Co3, o3);
2664 }
2665
2666 /* Set radical species... */
2667 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
2668 atm->lon[ip], atm->lat[ip], atm->p[ip]));
2669 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
2670 atm->lat[ip], atm->p[ip]));
2671 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
2672 atm->lat[ip], atm->p[ip]));
2673 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
2674 atm->lat[ip], atm->p[ip]));
2675 }
2676}
2677
2678/*****************************************************************************/
2679
2681 const ctl_t *ctl,
2682 cache_t *cache,
2683 met_t *met0,
2684 met_t *met1,
2685 atm_t *atm) {
2686
2687 /* Set timer... */
2688 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
2689
2690 /* Create random numbers... */
2691 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
2692
2693 /* Loop over particles... */
2694 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2695
2696 /* Interpolate CAPE... */
2697 double ps;
2699 INTPOL_2D(ps, 1);
2700
2701 /* Initialize pressure range for vertical mixing... */
2702 double pbot = ps, ptop = ps;
2703
2704 /* Mixing in the PBL... */
2705 if (ctl->conv_mix_pbl) {
2706
2707 /* Interpolate PBL... */
2708 double pbl;
2709 INTPOL_2D(pbl, 0);
2710
2711 /* Set pressure range... */
2712 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
2713 }
2714
2715 /* Convective mixing... */
2716 if (ctl->conv_cape >= 0) {
2717
2718 /* Interpolate CAPE, CIN, and equilibrium level... */
2719 double cape, cin, pel;
2720 INTPOL_2D(cape, 0);
2721 INTPOL_2D(cin, 0);
2722 INTPOL_2D(pel, 0);
2723
2724 /* Set pressure range... */
2725 if (isfinite(cape) && cape >= ctl->conv_cape
2726 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
2727 ptop = GSL_MIN(ptop, pel);
2728 }
2729
2730 /* Apply vertical mixing... */
2731 if (ptop != pbot && atm->p[ip] >= ptop) {
2732
2733 /* Get density range... */
2734 double tbot, ttop;
2735 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2736 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
2737 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2738 ptop, atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
2739 const double rhobot = pbot / tbot;
2740 const double rhotop = ptop / ttop;
2741
2742 /* Get new density... */
2743 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
2744
2745 /* Get pressure... */
2746 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
2747 }
2748 }
2749}
2750
2751/*****************************************************************************/
2752
2754 const ctl_t *ctl,
2755 const cache_t *cache,
2756 const clim_t *clim,
2757 atm_t *atm) {
2758
2759 /* Set timer... */
2760 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
2761
2762 /* Check quantity flags... */
2763 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2764 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2765
2766 /* Loop over particles... */
2767 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
2768
2769 /* Get weighting factor... */
2770 const double w = tropo_weight(clim, atm, ip);
2771
2772 /* Set lifetime... */
2773 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
2774
2775 /* Calculate exponential decay... */
2776 const double aux = exp(-cache->dt[ip] / tdec);
2777 if (ctl->qnt_m >= 0) {
2778 if (ctl->qnt_mloss_decay >= 0)
2779 atm->q[ctl->qnt_mloss_decay][ip]
2780 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2781 atm->q[ctl->qnt_m][ip] *= aux;
2782 if (ctl->qnt_loss_rate >= 0)
2783 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
2784 }
2785 if (ctl->qnt_vmr >= 0)
2786 atm->q[ctl->qnt_vmr][ip] *= aux;
2787 }
2788}
2789
2790/*****************************************************************************/
2791
2793 const ctl_t *ctl,
2794 cache_t *cache,
2795 met_t *met0,
2796 met_t *met1,
2797 atm_t *atm) {
2798
2799 /* Set timer... */
2800 SELECT_TIMER("MODULE_DIFFMESO", "PHYSICS", NVTX_GPU);
2801
2802 /* Create random numbers... */
2803 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2804
2805 /* Loop over particles... */
2806 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2807
2808 /* Get indices... */
2809 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
2810 const int iy = locate_reg(met0->lat, met0->ny, atm->lat[ip]);
2811 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
2812
2813 /* Get standard deviations of local wind data... */
2814 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
2815 for (int i = 0; i < 2; i++)
2816 for (int j = 0; j < 2; j++)
2817 for (int k = 0; k < 2; k++) {
2818 umean += met0->u[ix + i][iy + j][iz + k];
2819 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
2820 vmean += met0->v[ix + i][iy + j][iz + k];
2821 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
2822 wmean += met0->w[ix + i][iy + j][iz + k];
2823 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
2824
2825 umean += met1->u[ix + i][iy + j][iz + k];
2826 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
2827 vmean += met1->v[ix + i][iy + j][iz + k];
2828 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
2829 wmean += met1->w[ix + i][iy + j][iz + k];
2830 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
2831 }
2832 usig = usig / 16.f - SQR(umean / 16.f);
2833 usig = (usig > 0 ? sqrtf(usig) : 0);
2834 vsig = vsig / 16.f - SQR(vmean / 16.f);
2835 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
2836 wsig = wsig / 16.f - SQR(wmean / 16.f);
2837 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
2838
2839 /* Set temporal correlations for mesoscale fluctuations... */
2840 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
2841 const double r2 = sqrt(1 - r * r);
2842
2843 /* Calculate horizontal mesoscale wind fluctuations... */
2844 if (ctl->turb_mesox > 0) {
2845 cache->uvwp[ip][0] =
2846 (float) (r * cache->uvwp[ip][0] +
2847 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
2848 atm->lon[ip] +=
2849 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2850
2851 cache->uvwp[ip][1] =
2852 (float) (r * cache->uvwp[ip][1] +
2853 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
2854 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2855 }
2856
2857 /* Calculate vertical mesoscale wind fluctuations... */
2858 if (ctl->turb_mesoz > 0) {
2859 cache->uvwp[ip][2] =
2860 (float) (r * cache->uvwp[ip][2] +
2861 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
2862 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
2863 }
2864 }
2865}
2866
2867/*****************************************************************************/
2868
2870 const ctl_t *ctl,
2871 cache_t *cache,
2872 met_t *met0,
2873 met_t *met1,
2874 atm_t *atm) {
2875
2876 /* Set timer... */
2877 SELECT_TIMER("MODULE_DIFFPBL", "PHYSICS", NVTX_GPU);
2878
2879 /* Create random numbers... */
2880 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2881
2882 /* Loop over particles... */
2883 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2884
2885 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
2886 tau_u = 300., tau_w = 100.;
2887
2888 /* Get surface and PBL pressure... */
2889 double pbl, ps;
2891 INTPOL_2D(ps, 1);
2892 INTPOL_2D(pbl, 0);
2893
2894 /* Boundary layer... */
2895 if (atm->p[ip] >= pbl) {
2896
2897 /* Calculate heights... */
2898 const double p = MIN(atm->p[ip], ps);
2899 const double zs = Z(ps);
2900 const double z = 1e3 * (Z(p) - zs);
2901 const double zi = 1e3 * (Z(pbl) - zs);
2902 const double zratio = z / zi;
2903
2904 /* Calculate friction velocity... */
2905 double ess, nss, h2o, t;
2906 INTPOL_2D(ess, 0);
2907 INTPOL_2D(nss, 0);
2908 INTPOL_3D(t, 1);
2909 INTPOL_3D(h2o, 0);
2910 const double rho = RHO(p, TVIRT(t, h2o));
2911 const double tau = sqrt(SQR(ess) + SQR(nss));
2912 const double ustar = sqrt(tau / rho);
2913
2914 /* Get surface sensible heat flux... */
2915 double shf;
2916 INTPOL_2D(shf, 1);
2917
2918 /* Stable or neutral conditions... */
2919 if (shf <= 0) {
2920
2921 /* Calcalute turbulent velocity variances... */
2922 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
2923 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
2924
2925 /* Calculate derivative dsig_w/dz... */
2926 dsigw_dz = -1.3 * ustar / zi;
2927
2928 /* Calcalute Lagrangian timescales... */
2929 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
2930 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
2931 }
2932
2933 /* Unstable conditions... */
2934 else {
2935
2936 /* Convective velocity... */
2937 const double wstar =
2938 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
2939
2940 /* Calcalute turbulent velocity variances... */
2941 sig_u = 1e-2
2942 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
2943 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
2944 * pow(zratio, 2.0 / 3.0)
2945 + (1.8 - 1.4 * zratio) * SQR(ustar));
2946
2947 /* Calculate derivative dsig_w/dz... */
2948 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
2949 * (0.8 *
2950 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
2951 - 1.8 * pow(zratio, 2.0 / 3.0)));
2952
2953 /* Calcalute Lagrangian timescales... */
2954 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
2955 const double eps =
2956 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
2957 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
2958 tau_u = 2 * SQR(sig_u) / (C0 * eps);
2959 tau_w = 2 * SQR(sig_w) / (C0 * eps);
2960 }
2961 }
2962
2963 /* Set minimum values... */
2964 sig_u = MAX(sig_u, 0.25);
2965 sig_w = MAX(sig_w, 0.1);
2966 tau_u = MAX(tau_u, 300.);
2967 tau_w = MAX(tau_w, 100.);
2968
2969 /* Update perturbations... */
2970 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
2971 const double ru2 = sqrt(1.0 - SQR(ru));
2972 cache->uvwp[ip][0]
2973 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
2974 cache->uvwp[ip][1]
2975 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
2976
2977 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
2978 const double rw2 = sqrt(1.0 - SQR(rw));
2979 cache->uvwp[ip][2]
2980 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
2981 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
2982
2983 /* Calculate new air parcel position... */
2984 atm->lon[ip] +=
2985 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2986 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2987 atm->p[ip] +=
2988 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
2989 }
2990}
2991
2992/*****************************************************************************/
2993
2995 const ctl_t *ctl,
2996 cache_t *cache,
2997 const clim_t *clim,
2998 met_t *met0,
2999 met_t *met1,
3000 atm_t *atm) {
3001
3002 /* Set timer... */
3003 SELECT_TIMER("MODULE_DIFFTURB", "PHYSICS", NVTX_GPU);
3004
3005 /* Create random numbers... */
3006 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
3007
3008 /* Loop over particles... */
3009 PARTICLE_LOOP(0, atm->np, 1,
3010 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3011
3012 /* Get PBL and surface pressure... */
3013 double pbl, ps;
3015 INTPOL_2D(pbl, 1);
3016 INTPOL_2D(ps, 0);
3017
3018 /* Get weighting factors... */
3019 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
3020 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
3021 const double wstrat = 1.0 - wpbl - wtrop;
3022
3023 /* Set diffusivity... */
3024 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
3025 + wstrat * ctl->turb_dx_strat;
3026 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
3027 + wstrat * ctl->turb_dz_strat;
3028
3029 /* Horizontal turbulent diffusion... */
3030 if (dx > 0) {
3031 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
3032 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
3033 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
3034 }
3035
3036 /* Vertical turbulent diffusion... */
3037 if (dz > 0) {
3038 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
3039 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
3040 }
3041 }
3042}
3043
3044/*****************************************************************************/
3045
3047 const ctl_t *ctl,
3048 const cache_t *cache,
3049 met_t *met0,
3050 met_t *met1,
3051 atm_t *atm) {
3052
3053 /* Set timer... */
3054 SELECT_TIMER("MODULE_DRYDEPO", "PHYSICS", NVTX_GPU);
3055
3056 /* Check quantity flags... */
3057 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3058 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3059
3060 /* Loop over particles... */
3061 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3062
3063 /* Get surface pressure... */
3064 double ps;
3066 INTPOL_2D(ps, 1);
3067
3068 /* Check whether particle is above the surface layer... */
3069 if (atm->p[ip] < ps - ctl->dry_depo_dp)
3070 continue;
3071
3072 /* Set depth of surface layer... */
3073 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
3074
3075 /* Calculate sedimentation velocity for particles... */
3076 double v_dep;
3077 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
3078
3079 /* Get temperature... */
3080 double t;
3081 INTPOL_3D(t, 1);
3082
3083 /* Set deposition velocity... */
3084 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3085 atm->q[ctl->qnt_rhop][ip]);
3086 }
3087
3088 /* Use explicit sedimentation velocity for gases... */
3089 else
3090 v_dep = ctl->dry_depo_vdep;
3091
3092 /* Calculate loss of mass based on deposition velocity... */
3093 const double aux = exp(-cache->dt[ip] * v_dep / dz);
3094 if (ctl->qnt_m >= 0) {
3095 if (ctl->qnt_mloss_dry >= 0)
3096 atm->q[ctl->qnt_mloss_dry][ip]
3097 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3098 atm->q[ctl->qnt_m][ip] *= aux;
3099 if (ctl->qnt_loss_rate >= 0)
3100 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
3101 }
3102 if (ctl->qnt_vmr >= 0)
3103 atm->q[ctl->qnt_vmr][ip] *= aux;
3104 }
3105}
3106
3107/*****************************************************************************/
3108
3110 const ctl_t *ctl,
3111 const cache_t *cache,
3112 const clim_t *clim,
3113 met_t *met0,
3114 met_t *met1,
3115 atm_t *atm) {
3116
3117 /* Set timer... */
3118 SELECT_TIMER("MODULE_H2O2CHEM", "PHYSICS", NVTX_GPU);
3119
3120 /* Check quantity flags... */
3121 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3122 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3123
3124 /* Parameter of SO2 correction... */
3125 const double a = 3.12541941e-06;
3126 const double b = -5.72532259e-01;
3127 const double low = pow(1. / a, 1. / b);
3128
3129 /* Loop over particles... */
3130 PARTICLE_LOOP(0, atm->np, 1,
3131 "acc data present(ctl,cache,ctl,met0,met1,atm)") {
3132
3133 /* Check whether particle is inside cloud... */
3134 double lwc, rwc;
3136 INTPOL_3D(lwc, 1);
3137 INTPOL_3D(rwc, 0);
3138 if (!(lwc > 0 || rwc > 0))
3139 continue;
3140
3141 /* Get temperature... */
3142 double t;
3143 INTPOL_3D(t, 0);
3144
3145 /* Get molecular density... */
3146 const double M = MOLEC_DENS(atm->p[ip], t);
3147
3148 /* Reaction rate (Berglen et al., 2004)... */
3149 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3150
3151 /* Henry constant of SO2... */
3152 const double H_SO2 =
3153 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3154 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3155
3156 /* Henry constant of H2O2... */
3157 const double H_h2o2 =
3158 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3159
3160 /* Correction factor for high SO2 concentration
3161 (if qnt_Cx is defined, the correction is switched on)... */
3162 double cor = 1.0;
3163 if (ctl->qnt_Cx >= 0)
3164 cor = atm->q[ctl->qnt_Cx][ip] >
3165 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3166
3167 const double h2o2 = H_h2o2
3168 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3169 * M * cor * 1000. / AVO; /* unit: mol/L */
3170
3171 /* Volume water content in cloud [m^3 m^(-3)]... */
3172 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3173 const double CWC = (lwc + rwc) * rho_air / 1e3;
3174
3175 /* Calculate exponential decay (Rolph et al., 1992)... */
3176 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3177 const double aux = exp(-cache->dt[ip] * rate_coef);
3178 if (ctl->qnt_m >= 0) {
3179 if (ctl->qnt_mloss_h2o2 >= 0)
3180 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3181 atm->q[ctl->qnt_m][ip] *= aux;
3182 if (ctl->qnt_loss_rate >= 0)
3183 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3184 }
3185 if (ctl->qnt_vmr >= 0)
3186 atm->q[ctl->qnt_vmr][ip] *= aux;
3187 }
3188}
3189
3190/*****************************************************************************/
3191
3193 const ctl_t *ctl,
3194 cache_t *cache,
3195 met_t *met0,
3196 met_t *met1,
3197 atm_t *atm) {
3198
3199 double t;
3200
3201 /* Set timer... */
3202 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3203
3204 /* Init... */
3206
3207 /* Save pressure... */
3208 if (ctl->isosurf == 1)
3209 for (int ip = 0; ip < atm->np; ip++)
3210 cache->iso_var[ip] = atm->p[ip];
3211
3212 /* Save density... */
3213 else if (ctl->isosurf == 2)
3214 for (int ip = 0; ip < atm->np; ip++) {
3215 INTPOL_3D(t, 1);
3216 cache->iso_var[ip] = atm->p[ip] / t;
3217 }
3218
3219 /* Save potential temperature... */
3220 else if (ctl->isosurf == 3)
3221 for (int ip = 0; ip < atm->np; ip++) {
3222 INTPOL_3D(t, 1);
3223 cache->iso_var[ip] = THETA(atm->p[ip], t);
3224 }
3225
3226 /* Read balloon pressure data... */
3227 else if (ctl->isosurf == 4) {
3228
3229 /* Write info... */
3230 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3231
3232 /* Open file... */
3233 FILE *in;
3234 if (!(in = fopen(ctl->balloon, "r")))
3235 ERRMSG("Cannot open file!");
3236
3237 /* Read pressure time series... */
3238 char line[LEN];
3239 while (fgets(line, LEN, in))
3240 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3241 &(cache->iso_ps[cache->iso_n])) == 2)
3242 if ((++cache->iso_n) > NP)
3243 ERRMSG("Too many data points!");
3244
3245 /* Check number of points... */
3246 if (cache->iso_n < 1)
3247 ERRMSG("Could not read any data!");
3248
3249 /* Close file... */
3250 fclose(in);
3251 }
3252}
3253
3254/*****************************************************************************/
3255
3257 const ctl_t *ctl,
3258 const cache_t *cache,
3259 met_t *met0,
3260 met_t *met1,
3261 atm_t *atm) {
3262
3263 /* Set timer... */
3264 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3265
3266 /* Loop over particles... */
3267 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
3268
3269 /* Init... */
3270 double t;
3272
3273 /* Restore pressure... */
3274 if (ctl->isosurf == 1)
3275 atm->p[ip] = cache->iso_var[ip];
3276
3277 /* Restore density... */
3278 else if (ctl->isosurf == 2) {
3279 INTPOL_3D(t, 1);
3280 atm->p[ip] = cache->iso_var[ip] * t;
3281 }
3282
3283 /* Restore potential temperature... */
3284 else if (ctl->isosurf == 3) {
3285 INTPOL_3D(t, 1);
3286 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3287 }
3288
3289 /* Interpolate pressure... */
3290 else if (ctl->isosurf == 4) {
3291 if (atm->time[ip] <= cache->iso_ts[0])
3292 atm->p[ip] = cache->iso_ps[0];
3293 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3294 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3295 else {
3296 int idx = locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3297 atm->p[ip] = LIN(cache->iso_ts[idx], cache->iso_ps[idx],
3298 cache->iso_ts[idx + 1], cache->iso_ps[idx + 1],
3299 atm->time[ip]);
3300 }
3301 }
3302 }
3303}
3304
3305/*****************************************************************************/
3306
3307#ifdef KPP
3308void module_kpp_chem(
3309 ctl_t *ctl,
3310 cache_t *cache,
3311 clim_t *clim,
3312 met_t *met0,
3313 met_t *met1,
3314 atm_t *atm) {
3315
3316 /* Set timer... */
3317 SELECT_TIMER("MODULE_KPPCHEM", "PHYSICS", NVTX_GPU);
3318
3319 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
3320 double rtol[1] = { 1.0e-3 };
3321 double atol[1] = { 1.0 };
3322
3323 /* Loop over particles... */
3324#ifdef _OPENACC
3325#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
3326#endif
3327 PARTICLE_LOOP(0, atm->np, 1,
3328 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
3329
3330 /* Initialize... */
3331 double var[nvar], fix[nfix], rconst[nreact];
3332 for (int i = 0; i < nvar; i++)
3333 var[i] = 0.0;
3334 for (int i = 0; i < nfix; i++)
3335 fix[i] = 0.0;
3336 for (int i = 0; i < nreact; i++)
3337 rconst[i] = 0.0;
3338 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
3339
3340 /* Integrate... */
3341 double rpar[20];
3342 int ipar[20];
3343 for (int i = 0; i < 20; i++) {
3344 ipar[i] = 0;
3345 rpar[i] = 0.0;
3346 }
3347 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) */
3348 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
3349 ipar[3] = 4; /* choice of the method:Rodas3 */
3350 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
3351 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
3352
3353 /* Save results.. */
3354 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
3355 }
3356}
3357#endif
3358
3359/*****************************************************************************/
3360
3362 const ctl_t *ctl,
3363 const cache_t *cache,
3364 const clim_t *clim,
3365 met_t *met0,
3366 met_t *met1,
3367 atm_t *atm) {
3368
3369 /* Set timer... */
3370 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
3371
3372 /* Check quantity flags... */
3373 if (ctl->qnt_tsts >= 0)
3374 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3375 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3376
3377 /* Loop over particles... */
3378 PARTICLE_LOOP(0, atm->np, 0,
3379 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3380
3381 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb, cl,
3382 plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot, o3, lwc,
3383 rwc, iwc, swc, cc, z, zt;
3384
3385 /* Interpolate meteo data... */
3387 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3388
3389 /* Set quantities... */
3390 SET_ATM(qnt_ps, ps);
3391 SET_ATM(qnt_ts, ts);
3392 SET_ATM(qnt_zs, zs);
3393 SET_ATM(qnt_us, us);
3394 SET_ATM(qnt_vs, vs);
3395 SET_ATM(qnt_ess, ess);
3396 SET_ATM(qnt_nss, nss);
3397 SET_ATM(qnt_shf, shf);
3398 SET_ATM(qnt_lsm, lsm);
3399 SET_ATM(qnt_sst, sst);
3400 SET_ATM(qnt_pbl, pbl);
3401 SET_ATM(qnt_pt, pt);
3402 SET_ATM(qnt_tt, tt);
3403 SET_ATM(qnt_zt, zt);
3404 SET_ATM(qnt_h2ot, h2ot);
3405 SET_ATM(qnt_zg, z);
3406 SET_ATM(qnt_p, atm->p[ip]);
3407 SET_ATM(qnt_t, t);
3408 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3409 SET_ATM(qnt_u, u);
3410 SET_ATM(qnt_v, v);
3411 SET_ATM(qnt_w, w);
3412 SET_ATM(qnt_h2o, h2o);
3413 SET_ATM(qnt_o3, o3);
3414 SET_ATM(qnt_lwc, lwc);
3415 SET_ATM(qnt_rwc, rwc);
3416 SET_ATM(qnt_iwc, iwc);
3417 SET_ATM(qnt_swc, swc);
3418 SET_ATM(qnt_cc, cc);
3419 SET_ATM(qnt_pct, pct);
3420 SET_ATM(qnt_pcb, pcb);
3421 SET_ATM(qnt_cl, cl);
3422 SET_ATM(qnt_plcl, plcl);
3423 SET_ATM(qnt_plfc, plfc);
3424 SET_ATM(qnt_pel, pel);
3425 SET_ATM(qnt_cape, cape);
3426 SET_ATM(qnt_cin, cin);
3427 SET_ATM(qnt_o3c, o3c);
3428 SET_ATM(qnt_hno3,
3429 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3430 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3431 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3432 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3433 atm->lat[ip], atm->p[ip]));
3434 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3435 atm->lat[ip], atm->p[ip]));
3436 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3437 atm->lat[ip], atm->p[ip]));
3438 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3439 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3440 SET_ATM(qnt_psat, PSAT(t));
3441 SET_ATM(qnt_psice, PSICE(t));
3442 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3443 SET_ATM(qnt_sh, SH(h2o));
3444 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3445 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3446 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3447 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3448 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3449 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3450 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3451 SET_ATM(qnt_pv, pv);
3452 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3453 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3454 SET_ATM(qnt_tnat,
3455 nat_temperature(atm->p[ip], h2o,
3456 clim_zm(&clim->hno3, atm->time[ip],
3457 atm->lat[ip], atm->p[ip])));
3458 SET_ATM(qnt_tsts,
3459 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3460 }
3461}
3462
3463/*****************************************************************************/
3464
3466 const ctl_t *ctl,
3467 const clim_t *clim,
3468 atm_t *atm,
3469 const double t) {
3470
3471 /* Set timer... */
3472 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
3473
3474 /* Allocate... */
3475 const int np = atm->np;
3476 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3477 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3478 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3479
3480 /* Set grid box size... */
3481 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3482 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3483 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3484
3485 /* Set time interval... */
3486 const double t0 = t - 0.5 * ctl->dt_mod;
3487 const double t1 = t + 0.5 * ctl->dt_mod;
3488
3489 /* Get indices... */
3490#ifdef _OPENACC
3491#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3492#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3493#pragma acc parallel loop independent gang vector
3494#else
3495#pragma omp parallel for default(shared)
3496#endif
3497 for (int ip = 0; ip < np; ip++) {
3498 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3499 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3500 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3501 if (atm->time[ip] < t0 || atm->time[ip] > t1
3502 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3503 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3504 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3505 izs[ip] = -1;
3506 }
3507
3508 /* Calculate interparcel mixing... */
3509 if (ctl->qnt_m >= 0)
3510 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_m);
3511 if (ctl->qnt_vmr >= 0)
3512 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_vmr);
3513 if (ctl->qnt_Ch2o >= 0)
3514 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o);
3515 if (ctl->qnt_Co3 >= 0)
3516 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3);
3517 if (ctl->qnt_Cco >= 0)
3518 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cco);
3519 if (ctl->qnt_Coh >= 0)
3520 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Coh);
3521 if (ctl->qnt_Ch >= 0)
3522 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch);
3523 if (ctl->qnt_Cho2 >= 0)
3524 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cho2);
3525 if (ctl->qnt_Ch2o2 >= 0)
3526 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o2);
3527 if (ctl->qnt_Co1d >= 0)
3528 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co1d);
3529 if (ctl->qnt_Co3p >= 0)
3530 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3p);
3531 if (ctl->qnt_Cccl4 >= 0)
3532 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl4);
3533 if (ctl->qnt_Cccl3f >= 0)
3534 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl3f);
3535 if (ctl->qnt_Cccl2f2 >= 0)
3536 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl2f2);
3537 if (ctl->qnt_Cn2o >= 0)
3538 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cn2o);
3539 if (ctl->qnt_Csf6 >= 0)
3540 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Csf6);
3541 if (ctl->qnt_aoa >= 0)
3542 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_aoa);
3543
3544 /* Free... */
3545#ifdef _OPENACC
3546#pragma acc exit data delete(ixs,iys,izs)
3547#endif
3548 free(ixs);
3549 free(iys);
3550 free(izs);
3551}
3552
3553/*****************************************************************************/
3554
3556 const ctl_t *ctl,
3557 const clim_t *clim,
3558 atm_t *atm,
3559 const int *ixs,
3560 const int *iys,
3561 const int *izs,
3562 const int qnt_idx) {
3563
3564 /* Allocate... */
3565 const int np = atm->np;
3566 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
3567 double *restrict const cmean =
3568 (double *) malloc((size_t) ngrid * sizeof(double));
3569 int *restrict const count = (int *) malloc((size_t) ngrid * sizeof(int));
3570
3571 /* Init... */
3572#ifdef _OPENACC
3573#pragma acc enter data create(cmean[0:ngrid],count[0:ngrid])
3574#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
3575#pragma acc parallel loop independent gang vector
3576#else
3577#ifdef __NVCOMPILER
3578#pragma novector
3579#endif
3580#pragma omp parallel for
3581#endif
3582 for (int i = 0; i < ngrid; i++) {
3583 count[i] = 0;
3584 cmean[i] = 0;
3585 }
3586
3587 /* Loop over particles... */
3588#ifdef _OPENACC
3589#pragma acc parallel loop independent gang vector
3590#endif
3591 for (int ip = 0; ip < np; ip++)
3592 if (izs[ip] >= 0) {
3593 int idx = ARRAY_3D
3594 (ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz);
3595#ifdef _OPENACC
3596#pragma acc atomic update
3597#endif
3598 cmean[idx] += atm->q[qnt_idx][ip];
3599#ifdef _OPENACC
3600#pragma acc atomic update
3601#endif
3602 count[idx]++;
3603 }
3604#ifdef _OPENACC
3605#pragma acc parallel loop independent gang vector
3606#else
3607#ifdef __NVCOMPILER
3608#pragma novector
3609#endif
3610#pragma omp parallel for
3611#endif
3612 for (int i = 0; i < ngrid; i++)
3613 if (count[i] > 0)
3614 cmean[i] /= count[i];
3615
3616 /* Calculate interparcel mixing... */
3617#ifdef _OPENACC
3618#pragma acc parallel loop independent gang vector
3619#else
3620#pragma omp parallel for
3621#endif
3622 for (int ip = 0; ip < np; ip++)
3623 if (izs[ip] >= 0) {
3624
3625 /* Set mixing parameter... */
3626 double mixparam = 1.0;
3627 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
3628 double w = tropo_weight(clim, atm, ip);
3629 mixparam = w * ctl->mixing_trop + (1 - w) * ctl->mixing_strat;
3630 }
3631
3632 /* Adjust quantity... */
3633 atm->q[qnt_idx][ip] +=
3634 (cmean
3635 [ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz)]
3636 - atm->q[qnt_idx][ip]) * mixparam;
3637 }
3638
3639 /* Free... */
3640#ifdef _OPENACC
3641#pragma acc exit data delete(cmean,count)
3642#endif
3643 free(cmean);
3644 free(count);
3645}
3646
3647/*****************************************************************************/
3648
3650 const ctl_t *ctl,
3651 const cache_t *cache,
3652 const clim_t *clim,
3653 met_t *met0,
3654 met_t *met1,
3655 atm_t *atm) {
3656
3657 /* Set timer... */
3658 SELECT_TIMER("MODULE_OHCHEM", "PHYSICS", NVTX_GPU);
3659
3660 /* Check quantity flags... */
3661 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3662 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3663
3664 /* Parameter of SO2 correction... */
3665 const double a = 4.71572206e-08;
3666 const double b = -8.28782867e-01;
3667 const double low = pow(1. / a, 1. / b);
3668
3669 /* Loop over particles... */
3670 PARTICLE_LOOP(0, atm->np, 1,
3671 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3672
3673 /* Get temperature... */
3674 double t;
3676 INTPOL_3D(t, 1);
3677
3678 /* Calculate molecular density... */
3679 const double M = MOLEC_DENS(atm->p[ip], t);
3680
3681 /* Use constant reaction rate... */
3682 double k = NAN;
3683 if (ctl->oh_chem_reaction == 1)
3684 k = ctl->oh_chem[0];
3685
3686 /* Calculate bimolecular reaction rate... */
3687 else if (ctl->oh_chem_reaction == 2)
3688 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
3689
3690 /* Calculate termolecular reaction rate... */
3691 if (ctl->oh_chem_reaction == 3) {
3692
3693 /* Calculate rate coefficient for X + OH + M -> XOH + M
3694 (JPL Publication 19-05) ... */
3695 const double k0 =
3696 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
3697 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
3698 const double ki =
3699 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
3700 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
3701 const double c = log10(k0 * M / ki);
3702 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
3703 }
3704
3705 /* Correction factor for high SO2 concentration
3706 (if qnt_Cx is defined, the correction is switched on)... */
3707 double cor = 1;
3708 if (ctl->qnt_Cx >= 0)
3709 cor =
3710 atm->q[ctl->qnt_Cx][ip] >
3711 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3712
3713 /* Calculate exponential decay... */
3714 const double rate_coef =
3715 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
3716 atm->lat[ip], atm->p[ip]) * M * cor;
3717 const double aux = exp(-cache->dt[ip] * rate_coef);
3718 if (ctl->qnt_m >= 0) {
3719 if (ctl->qnt_mloss_oh >= 0)
3720 atm->q[ctl->qnt_mloss_oh][ip]
3721 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3722 atm->q[ctl->qnt_m][ip] *= aux;
3723 if (ctl->qnt_loss_rate >= 0)
3724 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3725 }
3726 if (ctl->qnt_vmr >= 0)
3727 atm->q[ctl->qnt_vmr][ip] *= aux;
3728 }
3729}
3730
3731/*****************************************************************************/
3732
3734 const cache_t *cache,
3735 met_t *met0,
3736 met_t *met1,
3737 atm_t *atm) {
3738
3739 /* Set timer... */
3740 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
3741
3742 /* Loop over particles... */
3743 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
3744
3745 /* Init... */
3746 double ps;
3748
3749 /* Calculate modulo... */
3750 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
3751 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
3752
3753 /* Check latitude... */
3754 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
3755 if (atm->lat[ip] > 90) {
3756 atm->lat[ip] = 180 - atm->lat[ip];
3757 atm->lon[ip] += 180;
3758 }
3759 if (atm->lat[ip] < -90) {
3760 atm->lat[ip] = -180 - atm->lat[ip];
3761 atm->lon[ip] += 180;
3762 }
3763 }
3764
3765 /* Check longitude... */
3766 while (atm->lon[ip] < -180)
3767 atm->lon[ip] += 360;
3768 while (atm->lon[ip] >= 180)
3769 atm->lon[ip] -= 360;
3770
3771 /* Check pressure... */
3772 if (atm->p[ip] < met0->p[met0->np - 1]) {
3773 // TODO: add reflection: atm->p[ip] = 2. * met0->p[met0->np - 1] - atm->p[ip];
3774 atm->p[ip] = met0->p[met0->np - 1];
3775 } else if (atm->p[ip] > 300.) {
3776 INTPOL_2D(ps, 1);
3777 // TODO: add reflection: if (atm->p[ip] > ps)
3778 // atm->p[ip] = 2. * ps - atm->p[ip];
3779 if (atm->p[ip] > ps)
3780 atm->p[ip] = ps;
3781 }
3782 }
3783}
3784
3785/*****************************************************************************/
3786
3788 const int ntask) {
3789
3790 /* Initialize GSL random number generators... */
3791 gsl_rng_env_setup();
3792 if (omp_get_max_threads() > NTHREADS)
3793 ERRMSG("Too many threads!");
3794 for (int i = 0; i < NTHREADS; i++) {
3795 rng[i] = gsl_rng_alloc(gsl_rng_default);
3796 gsl_rng_set(rng[i], gsl_rng_default_seed
3797 + (long unsigned) (ntask * NTHREADS + i));
3798 }
3799
3800 /* Initialize cuRAND random number generators... */
3801#ifdef CURAND
3802 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
3803 CURAND_STATUS_SUCCESS)
3804 ERRMSG("Cannot create random number generator!");
3805 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
3806 CURAND_STATUS_SUCCESS)
3807 ERRMSG("Cannot set seed for random number generator!");
3808 if (curandSetStream
3809 (rng_curand,
3810 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
3811 CURAND_STATUS_SUCCESS)
3812 ERRMSG("Cannot set stream for random number generator!");
3813#endif
3814}
3815
3816/*****************************************************************************/
3817
3819 const ctl_t *ctl,
3820 double *rs,
3821 const size_t n,
3822 const int method) {
3823
3824 /* Use GSL random number generators... */
3825 if (ctl->rng_type == 0) {
3826
3827 /* Uniform distribution... */
3828 if (method == 0) {
3829#pragma omp parallel for default(shared)
3830 for (size_t i = 0; i < n; ++i)
3831 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
3832 }
3833
3834 /* Normal distribution... */
3835 else if (method == 1) {
3836#pragma omp parallel for default(shared)
3837 for (size_t i = 0; i < n; ++i)
3838 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
3839 }
3840
3841 /* Update of random numbers on device... */
3842#ifdef _OPENACC
3843#pragma acc update device(rs[:n])
3844#endif
3845 }
3846
3847 /* Use Squares random number generator (Widynski, 2022)... */
3848 else if (ctl->rng_type == 1) {
3849
3850 /* Set key (don't change this!)... */
3851 const uint64_t key = 0xc8e4fd154ce32f6d;
3852
3853 /* Uniform distribution... */
3854#ifdef _OPENACC
3855#pragma acc data present(rs)
3856#pragma acc parallel loop independent gang vector
3857#else
3858#pragma omp parallel for default(shared)
3859#endif
3860 for (size_t i = 0; i < n + 1; ++i) {
3861 uint64_t r, t, x, y, z;
3862 y = x = (rng_ctr + i) * key;
3863 z = y + key;
3864 x = x * x + y;
3865 x = (x >> 32) | (x << 32);
3866 x = x * x + z;
3867 x = (x >> 32) | (x << 32);
3868 x = x * x + y;
3869 x = (x >> 32) | (x << 32);
3870 t = x = x * x + z;
3871 x = (x >> 32) | (x << 32);
3872 r = t ^ ((x * x + y) >> 32);
3873 rs[i] = (double) r / (double) UINT64_MAX;
3874 }
3875 rng_ctr += n + 1;
3876
3877 /* Normal distribution... */
3878 if (method == 1) {
3879#ifdef _OPENACC
3880#pragma acc parallel loop independent gang vector
3881#else
3882#pragma omp parallel for default(shared)
3883#endif
3884 for (size_t i = 0; i < n; i += 2) {
3885 const double r = sqrt(-2.0 * log(rs[i]));
3886 const double phi = 2.0 * M_PI * rs[i + 1];
3887 rs[i] = r * cosf((float) phi);
3888 rs[i + 1] = r * sinf((float) phi);
3889 }
3890 }
3891 }
3892
3893 /* Use cuRAND random number generators... */
3894 else if (ctl->rng_type == 2) {
3895#ifdef CURAND
3896#pragma acc host_data use_device(rs)
3897 {
3898
3899 /* Uniform distribution... */
3900 if (method == 0) {
3901 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
3902 CURAND_STATUS_SUCCESS)
3903 ERRMSG("Cannot create random numbers!");
3904 }
3905
3906 /* Normal distribution... */
3907 else if (method == 1) {
3908 if (curandGenerateNormalDouble
3909 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
3910 1.0) != CURAND_STATUS_SUCCESS)
3911 ERRMSG("Cannot create random numbers!");
3912 }
3913 }
3914#else
3915 ERRMSG("MPTRAC was compiled without cuRAND!");
3916#endif
3917 }
3918}
3919
3920/*****************************************************************************/
3921
3923 const ctl_t *ctl,
3924 const cache_t *cache,
3925 met_t *met0,
3926 met_t *met1,
3927 atm_t *atm) {
3928
3929 /* Set timer... */
3930 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
3931
3932 /* Loop over particles... */
3933 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3934
3935 /* Get temperature... */
3936 double t;
3938 INTPOL_3D(t, 1);
3939
3940 /* Sedimentation velocity... */
3941 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3942 atm->q[ctl->qnt_rhop][ip]);
3943
3944 /* Calculate pressure change... */
3945 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
3946 }
3947}
3948
3949/*****************************************************************************/
3950
3952 const ctl_t *ctl,
3953 met_t *met0,
3954 atm_t *atm) {
3955
3956 /* Set timer... */
3957 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
3958
3959 /* Allocate... */
3960 const int np = atm->np;
3961 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
3962 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
3963
3964#ifdef _OPENACC
3965#pragma acc enter data create(a[0:np],p[0:np])
3966#pragma acc data present(ctl,met0,atm,a,p)
3967#endif
3968
3969 /* Get box index... */
3970#ifdef _OPENACC
3971#pragma acc parallel loop independent gang vector
3972#else
3973#pragma omp parallel for default(shared)
3974#endif
3975 for (int ip = 0; ip < np; ip++) {
3976 a[ip] =
3977 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
3978 locate_reg(met0->lat, met0->ny, atm->lat[ip]))
3979 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
3980 p[ip] = ip;
3981 }
3982
3983 /* Sorting... */
3984#ifdef _OPENACC
3985#pragma acc host_data use_device(a, p)
3986#endif
3987#ifdef THRUST
3988 thrustSortWrapper(a, np, p);
3989#else
3990 ERRMSG("MPTRAC was compiled without Thrust library!");
3991#endif
3992
3993 /* Sort data... */
3994 module_sort_help(atm->time, p, np);
3995 module_sort_help(atm->p, p, np);
3996 module_sort_help(atm->lon, p, np);
3997 module_sort_help(atm->lat, p, np);
3998 for (int iq = 0; iq < ctl->nq; iq++)
3999 module_sort_help(atm->q[iq], p, np);
4000
4001 /* Free... */
4002#ifdef _OPENACC
4003#pragma acc exit data delete(a,p)
4004#endif
4005 free(a);
4006 free(p);
4007}
4008
4009/*****************************************************************************/
4010
4012 double *a,
4013 const int *p,
4014 const int np) {
4015
4016 /* Allocate... */
4017 double *restrict const help =
4018 (double *) malloc((size_t) np * sizeof(double));
4019
4020 /* Reordering of array... */
4021#ifdef _OPENACC
4022#pragma acc enter data create(help[0:np])
4023#pragma acc data present(a,p,help)
4024#pragma acc parallel loop independent gang vector
4025#else
4026#pragma omp parallel for default(shared)
4027#endif
4028 for (int ip = 0; ip < np; ip++)
4029 help[ip] = a[p[ip]];
4030#ifdef _OPENACC
4031#pragma acc parallel loop independent gang vector
4032#else
4033#pragma omp parallel for default(shared)
4034#endif
4035 for (int ip = 0; ip < np; ip++)
4036 a[ip] = help[ip];
4037
4038 /* Free... */
4039#ifdef _OPENACC
4040#pragma acc exit data delete(help)
4041#endif
4042 free(help);
4043}
4044
4045/*****************************************************************************/
4046
4048 const ctl_t *ctl,
4049 cache_t *cache,
4050 met_t *met0,
4051 atm_t *atm,
4052 const double t) {
4053
4054 /* Set timer... */
4055 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
4056
4057 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
4058 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
4059
4060 const int local =
4061 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
4062
4063 /* Loop over particles... */
4064 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
4065
4066 /* Set time step for each air parcel... */
4067 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
4068 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
4069 && ctl->direction * (atm->time[ip] - t) < 0))
4070 cache->dt[ip] = t - atm->time[ip];
4071 else
4072 cache->dt[ip] = 0.0;
4073
4074 /* Check horizontal boundaries of local meteo data... */
4075 if (local && (atm->lon[ip] <= met0->lon[0]
4076 || atm->lon[ip] >= met0->lon[met0->nx - 1]
4077 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
4078 cache->dt[ip] = 0.0;
4079 }
4080}
4081
4082/*****************************************************************************/
4083
4085 ctl_t *ctl,
4086 const atm_t *atm) {
4087
4088 /* Set timer... */
4089 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
4090
4091 /* Set start time... */
4092 if (ctl->direction == 1) {
4093 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4094 if (ctl->t_stop > 1e99)
4095 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4096 } else {
4097 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
4098 if (ctl->t_stop > 1e99)
4099 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
4100 }
4101
4102 /* Check time interval... */
4103 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
4104 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
4105
4106 /* Round start time... */
4107 if (ctl->direction == 1)
4108 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4109 else
4110 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
4111}
4112
4113/*****************************************************************************/
4114
4116 const ctl_t *ctl,
4117 const cache_t *cache,
4118 const clim_t *clim,
4119 met_t *met0,
4120 met_t *met1,
4121 atm_t *atm) {
4122
4123 /* Set timer... */
4124 SELECT_TIMER("MODULE_TRACERCHEM", "PHYSICS", NVTX_GPU);
4125
4126 /* Loop over particles... */
4127 PARTICLE_LOOP(0, atm->np, 1,
4128 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4129
4130 /* Get temperature... */
4131 double t;
4133 INTPOL_3D(t, 1);
4134
4135 /* Get molecular density... */
4136 const double M = MOLEC_DENS(atm->p[ip], t);
4137
4138 /* Get total column ozone... */
4139 double o3c;
4140 INTPOL_2D(o3c, 1);
4141
4142 /* Get solar zenith angle... */
4143 const double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
4144
4145 /* Get O(1D) volume mixing ratio... */
4146 const double o1d =
4147 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4148
4149 /* Reactions for CFC-10... */
4150 if (ctl->qnt_Cccl4 >= 0) {
4151 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4152 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4153 atm->p[ip], sza, o3c);
4154 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4155 }
4156
4157 /* Reactions for CFC-11... */
4158 if (ctl->qnt_Cccl3f >= 0) {
4159 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4160 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4161 atm->p[ip], sza, o3c);
4162 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4163 }
4164
4165 /* Reactions for CFC-12... */
4166 if (ctl->qnt_Cccl2f2 >= 0) {
4167 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4168 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4169 atm->p[ip], sza, o3c);
4170 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4171 }
4172
4173 /* Reactions for N2O... */
4174 if (ctl->qnt_Cn2o >= 0) {
4175 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4176 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4177 atm->p[ip], sza, o3c);
4178 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4179 }
4180 }
4181}
4182
4183/*****************************************************************************/
4184
4186 const ctl_t *ctl,
4187 const cache_t *cache,
4188 met_t *met0,
4189 met_t *met1,
4190 atm_t *atm) {
4191
4192 /* Set timer... */
4193 SELECT_TIMER("MODULE_WETDEPO", "PHYSICS", NVTX_GPU);
4194
4195 /* Check quantity flags... */
4196 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4197 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4198
4199 /* Loop over particles... */
4200 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4201
4202 /* Check whether particle is below cloud top... */
4203 double pct;
4205 INTPOL_2D(pct, 1);
4206 if (!isfinite(pct) || atm->p[ip] <= pct)
4207 continue;
4208
4209 /* Get cloud bottom pressure... */
4210 double pcb;
4211 INTPOL_2D(pcb, 0);
4212
4213 /* Estimate precipitation rate (Pisso et al., 2019)... */
4214 double cl;
4215 INTPOL_2D(cl, 0);
4216 const double Is =
4217 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4218 if (Is < 0.01)
4219 continue;
4220
4221 /* Check whether particle is inside or below cloud... */
4222 double lwc, rwc, iwc, swc;
4223 INTPOL_3D(lwc, 1);
4224 INTPOL_3D(rwc, 0);
4225 INTPOL_3D(iwc, 0);
4226 INTPOL_3D(swc, 0);
4227 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4228
4229 /* Get temperature... */
4230 double t;
4231 INTPOL_3D(t, 0);
4232
4233 /* Calculate in-cloud scavenging coefficient... */
4234 double lambda = 0;
4235 if (inside) {
4236
4237 /* Calculate retention factor... */
4238 double eta;
4239 if (t > 273.15)
4240 eta = 1;
4241 else if (t <= 238.15)
4242 eta = ctl->wet_depo_ic_ret_ratio;
4243 else
4244 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4245
4246 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4247 if (ctl->wet_depo_ic_a > 0)
4248 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4249
4250 /* Use Henry's law for gases... */
4251 else if (ctl->wet_depo_ic_h[0] > 0) {
4252
4253 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4254 double h = ctl->wet_depo_ic_h[0]
4255 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4256
4257 /* Use effective Henry's constant for SO2
4258 (Berglen, 2004; Simpson, 2012)... */
4259 if (ctl->wet_depo_so2_ph > 0) {
4260 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
4261 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4262 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4263 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
4264 }
4265
4266 /* Estimate depth of cloud layer... */
4267 const double dz = 1e3 * (Z(pct) - Z(pcb));
4268
4269 /* Calculate scavenging coefficient... */
4270 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4271 }
4272 }
4273
4274 /* Calculate below-cloud scavenging coefficient... */
4275 else {
4276
4277 /* Calculate retention factor... */
4278 double eta;
4279 if (t > 270)
4280 eta = 1;
4281 else
4282 eta = ctl->wet_depo_bc_ret_ratio;
4283
4284 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4285 if (ctl->wet_depo_bc_a > 0)
4286 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4287
4288 /* Use Henry's law for gases... */
4289 else if (ctl->wet_depo_bc_h[0] > 0) {
4290
4291 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4292 const double h = ctl->wet_depo_bc_h[0]
4293 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4294
4295 /* Estimate depth of cloud layer... */
4296 const double dz = 1e3 * (Z(pct) - Z(pcb));
4297
4298 /* Calculate scavenging coefficient... */
4299 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4300 }
4301 }
4302
4303 /* Calculate exponential decay of mass... */
4304 const double aux = exp(-cache->dt[ip] * lambda);
4305 if (ctl->qnt_m >= 0) {
4306 if (ctl->qnt_mloss_wet >= 0)
4307 atm->q[ctl->qnt_mloss_wet][ip]
4308 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4309 atm->q[ctl->qnt_m][ip] *= aux;
4310 if (ctl->qnt_loss_rate >= 0)
4311 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4312 }
4313 if (ctl->qnt_vmr >= 0)
4314 atm->q[ctl->qnt_vmr][ip] *= aux;
4315 }
4316}
4317
4318/*****************************************************************************/
4319
4321 ctl_t **ctl,
4322 cache_t **cache,
4323 clim_t **clim,
4324 met_t **met0,
4325 met_t **met1,
4326 atm_t **atm) {
4327
4328 /* Initialize GPUs... */
4329#ifdef _OPENACC
4330 SELECT_TIMER("ACC_INIT", "INIT", NVTX_GPU);
4331 int rank = 0;
4332#ifdef MPI
4333 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
4334#endif
4335 if (acc_get_num_devices(acc_device_nvidia) <= 0)
4336 ERRMSG("Not running on a GPU device!");
4337 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
4338 acc_device_nvidia);
4339 acc_device_t device_type = acc_get_device_type();
4340 acc_init(device_type);
4341#endif
4342
4343 /* Allocate... */
4344 SELECT_TIMER("ALLOC", "MEMORY", NVTX_CPU);
4345 ALLOC(*ctl, ctl_t, 1);
4346 ALLOC(*cache, cache_t, 1);
4347 ALLOC(*clim, clim_t, 1);
4348 ALLOC(*met0, met_t, 1);
4349 ALLOC(*met1, met_t, 1);
4350 ALLOC(*atm, atm_t, 1);
4351
4352 /* Create data region on GPUs... */
4353#ifdef _OPENACC
4354 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY", NVTX_GPU);
4355 ctl_t *ctlup = *ctl;
4356 cache_t *cacheup = *cache;
4357 clim_t *climup = *clim;
4358 met_t *met0up = *met0;
4359 met_t *met1up = *met1;
4360 atm_t *atmup = *atm;
4361#pragma acc enter data create(ctlup[:1], cacheup[:1], climup[:1], met0up[:1], met1up[:1], atmup[:1])
4362#endif
4363}
4364
4365/*****************************************************************************/
4366
4368 ctl_t *ctl,
4369 cache_t *cache,
4370 clim_t *clim,
4371 met_t *met0,
4372 met_t *met1,
4373 atm_t *atm) {
4374
4375 /* Delete data region on GPUs... */
4376#ifdef _OPENACC
4377 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY", NVTX_GPU);
4378#pragma acc exit data delete (ctl, cache, clim, met0, met1, atm)
4379#endif
4380
4381 /* Free... */
4382 SELECT_TIMER("FREE", "MEMORY", NVTX_CPU);
4383 free(atm);
4384 free(ctl);
4385 free(cache);
4386 free(clim);
4387 free(met0);
4388 free(met1);
4389}
4390
4391/*****************************************************************************/
4392
4394 ctl_t *ctl,
4395 cache_t *cache,
4396 clim_t *clim,
4397 met_t **met0,
4398 met_t **met1,
4399 atm_t *atm,
4400 double t) {
4401
4402 /* Set time steps of air parcels... */
4403 module_timesteps(ctl, cache, *met0, atm, t);
4404
4405 /* Get meteo data... */
4406 if (t != ctl->t_start)
4407 get_met(ctl, clim, t, met0, met1);
4408
4409 /* Sort particles... */
4410 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
4411 module_sort(ctl, *met0, atm);
4412
4413 /* Check positions (initial)... */
4414 module_position(cache, *met0, *met1, atm);
4415
4416 /* Advection... */
4417 if (ctl->advect > 0)
4418 module_advect(ctl, cache, *met0, *met1, atm);
4419
4420 /* Turbulent diffusion... */
4421 if (ctl->diffusion == 1
4422 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
4423 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
4424 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
4425 module_diffusion_turb(ctl, cache, clim, *met0, *met1, atm);
4426
4427 /* Mesoscale diffusion... */
4428 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
4429 module_diffusion_meso(ctl, cache, *met0, *met1, atm);
4430
4431 /* Diffusion... */
4432 if (ctl->diffusion == 2)
4433 module_diffusion_pbl(ctl, cache, *met0, *met1, atm);
4434
4435 /* Convection... */
4436 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
4437 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
4438 module_convection(ctl, cache, *met0, *met1, atm);
4439
4440 /* Sedimentation... */
4441 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
4442 module_sedi(ctl, cache, *met0, *met1, atm);
4443
4444 /* Isosurface... */
4445 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
4446 module_isosurf(ctl, cache, *met0, *met1, atm);
4447
4448 /* Check positions (final)... */
4449 module_position(cache, *met0, *met1, atm);
4450
4451 /* Interpolate meteo data... */
4452 if (ctl->met_dt_out > 0
4453 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
4454 module_meteo(ctl, cache, clim, *met0, *met1, atm);
4455
4456 /* Check boundary conditions (initial)... */
4457 if ((ctl->bound_lat0 < ctl->bound_lat1)
4458 && (ctl->bound_p0 > ctl->bound_p1))
4459 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
4460
4461 /* Initialize quantity of total loss rate... */
4462 if (ctl->qnt_loss_rate >= 0) {
4463 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
4464 atm->q[ctl->qnt_loss_rate][ip] = 0;
4465 }
4466 }
4467
4468 /* Decay of particle mass... */
4469 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
4470 module_decay(ctl, cache, clim, atm);
4471
4472 /* Interparcel mixing... */
4473 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
4474 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
4475 module_mixing(ctl, clim, atm, t);
4476
4477 /* Calculate the tracer vmr in the chemistry grid... */
4478 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
4479 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
4480 module_chemgrid(ctl, *met0, *met1, atm, t);
4481
4482 /* OH chemistry... */
4483 if (ctl->oh_chem_reaction != 0)
4484 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
4485
4486 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
4487 if (ctl->h2o2_chem_reaction != 0)
4488 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
4489
4490 /* First-order tracer chemistry... */
4491 if (ctl->tracer_chem)
4492 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
4493
4494 /* KPP chemistry... */
4495 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
4496#ifdef KPP
4497 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
4498#else
4499 ERRMSG("Code was compiled without KPP!");
4500#endif
4501 }
4502
4503 /* Wet deposition... */
4504 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
4505 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
4506 module_wet_deposition(ctl, cache, *met0, *met1, atm);
4507
4508 /* Dry deposition... */
4509 if (ctl->dry_depo_vdep > 0)
4510 module_dry_deposition(ctl, cache, *met0, *met1, atm);
4511
4512 /* Check boundary conditions (final)... */
4513 if ((ctl->bound_lat0 < ctl->bound_lat1)
4514 && (ctl->bound_p0 > ctl->bound_p1))
4515 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
4516}
4517
4518/*****************************************************************************/
4519
4521 const double p,
4522 const double h2o,
4523 const double hno3) {
4524
4525 /* Check water vapor volume mixing ratio... */
4526 const double h2o_help = MAX(h2o, 0.1e-6);
4527
4528 /* Calculate T_NAT... */
4529 const double p_hno3 = hno3 * p / 1.333224;
4530 const double p_h2o = h2o_help * p / 1.333224;
4531 const double a = 0.009179 - 0.00088 * log10(p_h2o);
4532 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
4533 const double c = -11397.0 / a;
4534 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
4535 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
4536 if (x2 > 0)
4537 tnat = x2;
4538
4539 return tnat;
4540}
4541
4542/*****************************************************************************/
4543
4545 const ctl_t *ctl,
4546 const atm_t *atm,
4547 const int ip,
4548 const double pbl,
4549 const double ps) {
4550
4551 /* Get pressure range... */
4552 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
4553 const double p0 = pbl;
4554
4555 /* Get weighting factor... */
4556 if (atm->p[ip] > p0)
4557 return 1;
4558 else if (atm->p[ip] < p1)
4559 return 0;
4560 else
4561 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
4562}
4563
4564/*****************************************************************************/
4565
4567 const char *filename,
4568 const ctl_t *ctl,
4569 atm_t *atm) {
4570
4571 int result;
4572
4573 /* Set timer... */
4574 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
4575
4576 /* Init... */
4577 atm->np = 0;
4578
4579 /* Write info... */
4580 LOG(1, "Read atmospheric data: %s", filename);
4581
4582 /* Read ASCII data... */
4583 if (ctl->atm_type == 0)
4584 result = read_atm_asc(filename, ctl, atm);
4585
4586 /* Read binary data... */
4587 else if (ctl->atm_type == 1)
4588 result = read_atm_bin(filename, ctl, atm);
4589
4590 /* Read netCDF data... */
4591 else if (ctl->atm_type == 2)
4592 result = read_atm_nc(filename, ctl, atm);
4593
4594 /* Read CLaMS data... */
4595 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
4596 result = read_atm_clams(filename, ctl, atm);
4597
4598 /* Error... */
4599 else
4600 ERRMSG("Atmospheric data type not supported!");
4601
4602 /* Check result... */
4603 if (result != 1)
4604 return 0;
4605
4606 /* Check number of air parcels... */
4607 if (atm->np < 1)
4608 ERRMSG("Can not read any data!");
4609
4610 /* Write info... */
4611 double mini, maxi;
4612 LOG(2, "Number of particles: %d", atm->np);
4613 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
4614 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
4615 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
4616 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
4617 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
4618 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
4619 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
4620 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
4621 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
4622 for (int iq = 0; iq < ctl->nq; iq++) {
4623 char msg[5 * LEN];
4624 sprintf(msg, "Quantity %s range: %s ... %s %s",
4625 ctl->qnt_name[iq], ctl->qnt_format[iq],
4626 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
4627 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
4628 LOG(2, msg, mini, maxi);
4629 }
4630
4631 /* Return success... */
4632 return 1;
4633}
4634
4635/*****************************************************************************/
4636
4638 const char *filename,
4639 const ctl_t *ctl,
4640 atm_t *atm) {
4641
4642 /* Open file... */
4643 FILE *in;
4644 if (!(in = fopen(filename, "r"))) {
4645 WARN("Cannot open file!");
4646 return 0;
4647 }
4648
4649 /* Read line... */
4650 char line[LEN];
4651 while (fgets(line, LEN, in)) {
4652
4653 /* Read data... */
4654 char *tok;
4655 TOK(line, tok, "%lg", atm->time[atm->np]);
4656 TOK(NULL, tok, "%lg", atm->p[atm->np]);
4657 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
4658 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
4659 for (int iq = 0; iq < ctl->nq; iq++)
4660 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
4661
4662 /* Convert altitude to pressure... */
4663 atm->p[atm->np] = P(atm->p[atm->np]);
4664
4665 /* Increment data point counter... */
4666 if ((++atm->np) > NP)
4667 ERRMSG("Too many data points!");
4668 }
4669
4670 /* Close file... */
4671 fclose(in);
4672
4673 /* Return success... */
4674 return 1;
4675}
4676
4677/*****************************************************************************/
4678
4680 const char *filename,
4681 const ctl_t *ctl,
4682 atm_t *atm) {
4683
4684 /* Open file... */
4685 FILE *in;
4686 if (!(in = fopen(filename, "r")))
4687 return 0;
4688
4689 /* Check version of binary data... */
4690 int version;
4691 FREAD(&version, int,
4692 1,
4693 in);
4694 if (version != 100)
4695 ERRMSG("Wrong version of binary data!");
4696
4697 /* Read data... */
4698 FREAD(&atm->np, int,
4699 1,
4700 in);
4701 FREAD(atm->time, double,
4702 (size_t) atm->np,
4703 in);
4704 FREAD(atm->p, double,
4705 (size_t) atm->np,
4706 in);
4707 FREAD(atm->lon, double,
4708 (size_t) atm->np,
4709 in);
4710 FREAD(atm->lat, double,
4711 (size_t) atm->np,
4712 in);
4713 for (int iq = 0; iq < ctl->nq; iq++)
4714 FREAD(atm->q[iq], double,
4715 (size_t) atm->np,
4716 in);
4717
4718 /* Read final flag... */
4719 int final;
4720 FREAD(&final, int,
4721 1,
4722 in);
4723 if (final != 999)
4724 ERRMSG("Error while reading binary data!");
4725
4726 /* Close file... */
4727 fclose(in);
4728
4729 /* Return success... */
4730 return 1;
4731}
4732
4733/*****************************************************************************/
4734
4736 const char *filename,
4737 const ctl_t *ctl,
4738 atm_t *atm) {
4739
4740 int ncid, varid;
4741
4742 /* Open file... */
4743 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
4744 return 0;
4745
4746 /* Get dimensions... */
4747 NC_INQ_DIM("NPARTS", &atm->np, 1, NP);
4748
4749 /* Get time... */
4750 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
4751 NC(nc_get_var_double(ncid, varid, atm->time));
4752 } else {
4753 WARN("TIME_INIT not found use time instead!");
4754 double time_init;
4755 NC_GET_DOUBLE("time", &time_init, 1);
4756 for (int ip = 0; ip < atm->np; ip++) {
4757 atm->time[ip] = time_init;
4758 }
4759 }
4760
4761 /* Read zeta coordinate, pressure is optional... */
4762 if (ctl->advect_vert_coord == 1) {
4763 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
4764 NC_GET_DOUBLE("PRESS", atm->p, 0);
4765 }
4766
4767 /* Read pressure, zeta coordinate is optional... */
4768 else {
4769 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
4770 NC(nc_get_var_double(ncid, varid, atm->p));
4771 } else {
4772 WARN("PRESS_INIT not found use PRESS instead!");
4773 nc_inq_varid(ncid, "PRESS", &varid);
4774 NC(nc_get_var_double(ncid, varid, atm->p));
4775 }
4776 }
4777
4778 /* Read longitude and latitude... */
4779 NC_GET_DOUBLE("LON", atm->lon, 1);
4780 NC_GET_DOUBLE("LAT", atm->lat, 1);
4781
4782 /* Close file... */
4783 NC(nc_close(ncid));
4784
4785 /* Return success... */
4786 return 1;
4787}
4788
4789/*****************************************************************************/
4790
4792 const char *filename,
4793 const ctl_t *ctl,
4794 atm_t *atm) {
4795
4796 int ncid, varid;
4797
4798 /* Open file... */
4799 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
4800 return 0;
4801
4802 /* Get dimensions... */
4803 NC_INQ_DIM("obs", &atm->np, 1, NP);
4804
4805 /* Read geolocations... */
4806 NC_GET_DOUBLE("time", atm->time, 1);
4807 NC_GET_DOUBLE("press", atm->p, 1);
4808 NC_GET_DOUBLE("lon", atm->lon, 1);
4809 NC_GET_DOUBLE("lat", atm->lat, 1);
4810
4811 /* Read variables... */
4812 for (int iq = 0; iq < ctl->nq; iq++)
4813 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
4814
4815 /* Close file... */
4816 NC(nc_close(ncid));
4817
4818 /* Return success... */
4819 return 1;
4820}
4821
4822/*****************************************************************************/
4823
4825 const ctl_t *ctl,
4826 clim_t *clim) {
4827
4828 /* Set timer... */
4829 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
4830
4831 /* Init tropopause climatology... */
4832 clim_tropo_init(clim);
4833
4834 /* Read photolysis rates... */
4835 if (ctl->clim_photo[0] != '-')
4836 read_clim_photo(ctl->clim_photo, &clim->photo);
4837
4838 /* Read HNO3 climatology... */
4839 if (ctl->clim_hno3_filename[0] != '-')
4840 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
4841
4842 /* Read OH climatology... */
4843 if (ctl->clim_oh_filename[0] != '-') {
4844 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
4845 if (ctl->oh_chem_beta > 0)
4846 clim_oh_diurnal_correction(ctl, clim);
4847 }
4848
4849 /* Read H2O2 climatology... */
4850 if (ctl->clim_h2o2_filename[0] != '-')
4851 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
4852
4853 /* Read HO2 climatology... */
4854 if (ctl->clim_ho2_filename[0] != '-')
4855 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
4856
4857 /* Read O(1D) climatology... */
4858 if (ctl->clim_o1d_filename[0] != '-')
4859 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
4860
4861 /* Read CFC-10 time series... */
4862 if (ctl->clim_ccl4_timeseries[0] != '-')
4864
4865 /* Read CFC-11 time series... */
4866 if (ctl->clim_ccl3f_timeseries[0] != '-')
4868
4869 /* Read CFC-12 time series... */
4870 if (ctl->clim_ccl2f2_timeseries[0] != '-')
4872
4873 /* Read N2O time series... */
4874 if (ctl->clim_n2o_timeseries[0] != '-')
4875 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
4876
4877 /* Read SF6 time series... */
4878 if (ctl->clim_sf6_timeseries[0] != '-')
4879 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
4880}
4881
4882/*****************************************************************************/
4883
4885 const char *filename,
4886 clim_photo_t *photo) {
4887
4888 int ncid, varid;
4889
4890 /* Write info... */
4891 LOG(1, "Read photolysis rates: %s", filename);
4892
4893 /* Open netCDF file... */
4894 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
4895 WARN("Photolysis rate data are missing!");
4896 return;
4897 }
4898
4899 /* Read pressure data... */
4900 NC_INQ_DIM("press", &photo->np, 2, CP);
4901 NC_GET_DOUBLE("press", photo->p, 1);
4902 if (photo->p[0] < photo->p[1])
4903 ERRMSG("Pressure data are not descending!");
4904
4905 /* Read total column ozone data... */
4906 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3);
4907 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
4908 if (photo->o3c[0] > photo->o3c[1])
4909 ERRMSG("Total column ozone data are not ascending!");
4910
4911 /* Read solar zenith angle data... */
4912 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA);
4913 NC_GET_DOUBLE("sza", photo->sza, 1);
4914 if (photo->sza[0] > photo->sza[1])
4915 ERRMSG("Solar zenith angle data are not ascending!");
4916
4917 /* Read data... */
4918 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
4919 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
4920 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
4921 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
4922 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
4923 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
4924 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
4925 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
4926 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
4927
4928 /* Close netCDF file... */
4929 NC(nc_close(ncid));
4930
4931 /* Write info... */
4932 LOG(2, "Number of pressure levels: %d", photo->np);
4933 LOG(2, "Altitude levels: %g, %g ... %g km",
4934 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
4935 LOG(2, "Pressure levels: %g, %g ... %g hPa",
4936 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
4937 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
4938 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
4939 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
4940 RAD2DEG(photo->sza[photo->nsza - 1]));
4941 LOG(2, "Number of total column ozone values: %d", photo->no3c);
4942 LOG(2, "Total column ozone: %g, %g ... %g DU",
4943 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
4944 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
4945 photo->n2o[0][0][0], photo->n2o[1][0][0],
4946 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4947 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
4948 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
4949 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4950 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
4951 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
4952 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4953 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
4954 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
4955 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4956 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
4957 photo->o2[0][0][0], photo->o2[1][0][0],
4958 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4959 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
4960 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
4961 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4962 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
4963 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
4964 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4965 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
4966 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
4967 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4968 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
4969 photo->h2o[0][0][0], photo->h2o[1][0][0],
4970 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
4971}
4972
4973/*****************************************************************************/
4974
4976 const int ncid,
4977 const char *varname,
4978 const clim_photo_t *photo,
4979 double var[CP][CSZA][CO3]) {
4980
4981 /* Allocate... */
4982 double *help;
4983 ALLOC(help, double,
4984 photo->np * photo->nsza * photo->no3c);
4985
4986 /* Read varible... */
4987 int varid;
4988 NC_GET_DOUBLE(varname, help, 1);
4989
4990 /* Copy data... */
4991 for (int ip = 0; ip < photo->np; ip++)
4992 for (int is = 0; is < photo->nsza; is++)
4993 for (int io = 0; io < photo->no3c; io++)
4994 var[ip][is][io] =
4995 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
4996
4997 /* Free... */
4998 free(help);
4999}
5000
5001/*****************************************************************************/
5002
5004 const char *filename,
5005 clim_ts_t *ts) {
5006
5007 /* Write info... */
5008 LOG(1, "Read climatological time series: %s", filename);
5009
5010 /* Open file... */
5011 FILE *in;
5012 if (!(in = fopen(filename, "r"))) {
5013 WARN("Cannot open file!");
5014 return 0;
5015 }
5016
5017 /* Read data... */
5018 char line[LEN];
5019 int nh = 0;
5020 while (fgets(line, LEN, in))
5021 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
5022
5023 /* Convert years to seconds... */
5024 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
5025
5026 /* Check data... */
5027 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
5028 ERRMSG("Time series must be ascending!");
5029
5030 /* Count time steps... */
5031 if ((++nh) >= CTS)
5032 ERRMSG("Too many data points!");
5033 }
5034
5035 /* Close file... */
5036 fclose(in);
5037
5038 /* Check number of data points... */
5039 ts->ntime = nh;
5040 if (nh < 2)
5041 ERRMSG("Not enough data points!");
5042
5043 /* Write info... */
5044 LOG(2, "Number of time steps: %d", ts->ntime);
5045 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
5046 ts->time[nh - 1]);
5047 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
5048 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
5049 (size_t) nh));
5050
5051 /* Exit success... */
5052 return 1;
5053}
5054
5055/*****************************************************************************/
5056
5058 const char *filename,
5059 const char *varname,
5060 clim_zm_t *zm) {
5061
5062 int ncid, varid, it, iy, iz, iz2, nt;
5063
5064 double *help, varmin = 1e99, varmax = -1e99;
5065
5066 /* Write info... */
5067 LOG(1, "Read %s data: %s", varname, filename);
5068
5069 /* Open netCDF file... */
5070 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
5071 WARN("%s climatology data are missing!", varname);
5072 return;
5073 }
5074
5075 /* Read pressure data... */
5076 NC_INQ_DIM("press", &zm->np, 2, CP);
5077 NC_GET_DOUBLE("press", zm->p, 1);
5078 if (zm->p[0] < zm->p[1])
5079 ERRMSG("Pressure data are not descending!");
5080
5081 /* Read latitudes... */
5082 NC_INQ_DIM("lat", &zm->nlat, 2, CY);
5083 NC_GET_DOUBLE("lat", zm->lat, 1);
5084 if (zm->lat[0] > zm->lat[1])
5085 ERRMSG("Latitude data are not ascending!");
5086
5087 /* Set time data (for monthly means)... */
5088 zm->ntime = 12;
5089 zm->time[0] = 1209600.00;
5090 zm->time[1] = 3888000.00;
5091 zm->time[2] = 6393600.00;
5092 zm->time[3] = 9072000.00;
5093 zm->time[4] = 11664000.00;
5094 zm->time[5] = 14342400.00;
5095 zm->time[6] = 16934400.00;
5096 zm->time[7] = 19612800.00;
5097 zm->time[8] = 22291200.00;
5098 zm->time[9] = 24883200.00;
5099 zm->time[10] = 27561600.00;
5100 zm->time[11] = 30153600.00;
5101
5102 /* Check number of timesteps... */
5103 NC_INQ_DIM("time", &nt, 12, 12);
5104
5105 /* Read data... */
5106 ALLOC(help, double,
5107 zm->nlat * zm->np * zm->ntime);
5108 NC_GET_DOUBLE(varname, help, 1);
5109 for (it = 0; it < zm->ntime; it++)
5110 for (iz = 0; iz < zm->np; iz++)
5111 for (iy = 0; iy < zm->nlat; iy++)
5112 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
5113 free(help);
5114
5115 /* Fix data gaps... */
5116 for (it = 0; it < zm->ntime; it++)
5117 for (iy = 0; iy < zm->nlat; iy++)
5118 for (iz = 0; iz < zm->np; iz++) {
5119 if (zm->vmr[it][iz][iy] < 0) {
5120 for (iz2 = 0; iz2 < zm->np; iz2++)
5121 if (zm->vmr[it][iz2][iy] >= 0) {
5122 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
5123 break;
5124 }
5125 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
5126 if (zm->vmr[it][iz2][iy] >= 0) {
5127 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
5128 break;
5129 }
5130 }
5131 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
5132 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
5133 }
5134
5135 /* Close netCDF file... */
5136 NC(nc_close(ncid));
5137
5138 /* Write info... */
5139 LOG(2, "Number of time steps: %d", zm->ntime);
5140 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
5141 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
5142 LOG(2, "Number of pressure levels: %d", zm->np);
5143 LOG(2, "Altitude levels: %g, %g ... %g km",
5144 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
5145 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
5146 zm->p[1], zm->p[zm->np - 1]);
5147 LOG(2, "Number of latitudes: %d", zm->nlat);
5148 LOG(2, "Latitudes: %g, %g ... %g deg",
5149 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
5150 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
5151 varmax);
5152}
5153
5154/*****************************************************************************/
5155
5157 const char *filename,
5158 int argc,
5159 char *argv[],
5160 ctl_t *ctl) {
5161
5162 /* Set timer... */
5163 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
5164
5165 /* Write info... */
5166 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
5167 "(executable: %s | version: %s | compiled: %s, %s)\n",
5168 argv[0], VERSION, __DATE__, __TIME__);
5169
5170 /* Initialize quantity indices... */
5171 ctl->qnt_idx = -1;
5172 ctl->qnt_ens = -1;
5173 ctl->qnt_stat = -1;
5174 ctl->qnt_m = -1;
5175 ctl->qnt_vmr = -1;
5176 ctl->qnt_rp = -1;
5177 ctl->qnt_rhop = -1;
5178 ctl->qnt_ps = -1;
5179 ctl->qnt_ts = -1;
5180 ctl->qnt_zs = -1;
5181 ctl->qnt_us = -1;
5182 ctl->qnt_vs = -1;
5183 ctl->qnt_ess = -1;
5184 ctl->qnt_nss = -1;
5185 ctl->qnt_shf = -1;
5186 ctl->qnt_lsm = -1;
5187 ctl->qnt_sst = -1;
5188 ctl->qnt_pbl = -1;
5189 ctl->qnt_pt = -1;
5190 ctl->qnt_tt = -1;
5191 ctl->qnt_zt = -1;
5192 ctl->qnt_h2ot = -1;
5193 ctl->qnt_zg = -1;
5194 ctl->qnt_p = -1;
5195 ctl->qnt_t = -1;
5196 ctl->qnt_rho = -1;
5197 ctl->qnt_u = -1;
5198 ctl->qnt_v = -1;
5199 ctl->qnt_w = -1;
5200 ctl->qnt_h2o = -1;
5201 ctl->qnt_o3 = -1;
5202 ctl->qnt_lwc = -1;
5203 ctl->qnt_rwc = -1;
5204 ctl->qnt_iwc = -1;
5205 ctl->qnt_swc = -1;
5206 ctl->qnt_cc = -1;
5207 ctl->qnt_pct = -1;
5208 ctl->qnt_pcb = -1;
5209 ctl->qnt_cl = -1;
5210 ctl->qnt_plcl = -1;
5211 ctl->qnt_plfc = -1;
5212 ctl->qnt_pel = -1;
5213 ctl->qnt_cape = -1;
5214 ctl->qnt_cin = -1;
5215 ctl->qnt_o3c = -1;
5216 ctl->qnt_hno3 = -1;
5217 ctl->qnt_oh = -1;
5218 ctl->qnt_h2o2 = -1;
5219 ctl->qnt_ho2 = -1;
5220 ctl->qnt_o1d = -1;
5221 ctl->qnt_mloss_oh = -1;
5222 ctl->qnt_mloss_h2o2 = -1;
5223 ctl->qnt_mloss_kpp = -1;
5224 ctl->qnt_mloss_wet = -1;
5225 ctl->qnt_mloss_dry = -1;
5226 ctl->qnt_mloss_decay = -1;
5227 ctl->qnt_loss_rate = -1;
5228 ctl->qnt_psat = -1;
5229 ctl->qnt_psice = -1;
5230 ctl->qnt_pw = -1;
5231 ctl->qnt_sh = -1;
5232 ctl->qnt_rh = -1;
5233 ctl->qnt_rhice = -1;
5234 ctl->qnt_theta = -1;
5235 ctl->qnt_zeta = -1;
5236 ctl->qnt_zeta_d = -1;
5237 ctl->qnt_tvirt = -1;
5238 ctl->qnt_lapse = -1;
5239 ctl->qnt_vh = -1;
5240 ctl->qnt_vz = -1;
5241 ctl->qnt_pv = -1;
5242 ctl->qnt_tdew = -1;
5243 ctl->qnt_tice = -1;
5244 ctl->qnt_tsts = -1;
5245 ctl->qnt_tnat = -1;
5246 ctl->qnt_Cx = -1;
5247 ctl->qnt_Ch2o = -1;
5248 ctl->qnt_Co3 = -1;
5249 ctl->qnt_Cco = -1;
5250 ctl->qnt_Coh = -1;
5251 ctl->qnt_Ch = -1;
5252 ctl->qnt_Cho2 = -1;
5253 ctl->qnt_Ch2o2 = -1;
5254 ctl->qnt_Co1d = -1;
5255 ctl->qnt_Co3p = -1;
5256 ctl->qnt_Cccl4 = -1;
5257 ctl->qnt_Cccl3f = -1;
5258 ctl->qnt_Cccl2f2 = -1;
5259 ctl->qnt_Cn2o = -1;
5260 ctl->qnt_Csf6 = -1;
5261 ctl->qnt_aoa = -1;
5262
5263 /* Read quantities... */
5264 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
5265 if (ctl->nq > NQ)
5266 ERRMSG("Too many quantities!");
5267 for (int iq = 0; iq < ctl->nq; iq++) {
5268
5269 /* Read quantity name and format... */
5270 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
5271 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
5272 ctl->qnt_longname[iq]);
5273 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
5274 ctl->qnt_format[iq]);
5275 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
5276 sprintf(ctl->qnt_format[iq], "%%.2f");
5277
5278 /* Try to identify quantity... */
5279 SET_QNT(qnt_idx, "idx", "particle index", "-")
5280 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
5281 SET_QNT(qnt_stat, "stat", "station flag", "-")
5282 SET_QNT(qnt_m, "m", "mass", "kg")
5283 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
5284 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
5285 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
5286 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
5287 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
5288 SET_QNT(qnt_zs, "zs", "surface height", "km")
5289 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
5290 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
5291 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
5292 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
5293 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
5294 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
5295 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
5296 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
5297 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
5298 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
5299 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
5300 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
5301 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
5302 SET_QNT(qnt_p, "p", "pressure", "hPa")
5303 SET_QNT(qnt_t, "t", "temperature", "K")
5304 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
5305 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
5306 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
5307 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
5308 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
5309 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
5310 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
5311 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
5312 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
5313 SET_QNT(qnt_swc, "iwc", "cloud snow water content", "kg/kg")
5314 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
5315 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
5316 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
5317 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
5318 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
5319 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
5320 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
5321 SET_QNT(qnt_cape, "cape", "convective available potential energy",
5322 "J/kg")
5323 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
5324 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
5325 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
5326 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
5327 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
5328 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
5329 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
5330 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
5331 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2", "mass loss due to H2O2 chemistry",
5332 "kg")
5333 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
5334 "kg")
5335 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
5336 "kg")
5337 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
5338 "kg")
5339 SET_QNT(qnt_mloss_decay, "mloss_decay",
5340 "mass loss due to exponential decay", "kg")
5341 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
5342 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
5343 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
5344 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
5345 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
5346 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
5347 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
5348 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
5349 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
5350 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
5351 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
5352 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
5353 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
5354 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
5355 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
5356 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
5357 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
5358 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
5359 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
5360 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
5361 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
5362 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
5363 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
5364 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
5365 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
5366 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
5367 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
5368 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
5369 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
5370 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
5371 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
5372 "ppv")
5373 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
5374 "ppv")
5375 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
5376 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
5377 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
5378 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
5379 }
5380
5381 /* Vertical coordinates and velocities... */
5382 ctl->advect_vert_coord =
5383 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
5384 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 2)
5385 ERRMSG("Set advect_vert_coord to 0, 1, or 2!");
5386 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
5387 ERRMSG("Please add zeta to your quantities for diabatic calculations!");
5388 ctl->met_vert_coord =
5389 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
5390 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord != 1)
5391 ERRMSG
5392 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
5393
5394 /* Time steps of simulation... */
5395 ctl->direction =
5396 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
5397 if (ctl->direction != -1 && ctl->direction != 1)
5398 ERRMSG("Set DIRECTION to -1 or 1!");
5399 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
5400 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
5401
5402 /* Meteo data... */
5403 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
5404 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
5405 ctl->met_convention =
5406 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
5407 ctl->met_type =
5408 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
5409 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
5410 ERRMSG
5411 ("Please use meteorological files in netcdf format for diabatic calculations.");
5412 ctl->met_clams =
5413 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
5414 ctl->met_nc_scale =
5415 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
5416 ctl->met_nc_level =
5417 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
5418 ctl->met_nc_quant =
5419 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
5420 ctl->met_zfp_prec =
5421 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", -1, "8", NULL);
5422 ctl->met_zfp_tol_t =
5423 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_T", -1, "5.0", NULL);
5424 ctl->met_zfp_tol_z =
5425 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_Z", -1, "0.5", NULL);
5426 ctl->met_cms_batch =
5427 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
5428 ctl->met_cms_heur =
5429 (int) scan_ctl(filename, argc, argv, "MET_CMS_HEUR", -1, "1", NULL);
5430 ctl->met_cms_eps_z =
5431 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
5432 ctl->met_cms_eps_t =
5433 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
5434 ctl->met_cms_eps_u =
5435 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
5436 ctl->met_cms_eps_v =
5437 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
5438 ctl->met_cms_eps_w =
5439 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
5440 ctl->met_cms_eps_pv =
5441 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
5442 ctl->met_cms_eps_h2o =
5443 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
5444 ctl->met_cms_eps_o3 =
5445 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
5446 ctl->met_cms_eps_lwc =
5447 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
5448 ctl->met_cms_eps_rwc =
5449 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
5450 ctl->met_cms_eps_iwc =
5451 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
5452 ctl->met_cms_eps_swc =
5453 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
5454 ctl->met_cms_eps_cc =
5455 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
5456 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
5457 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
5458 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
5459 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
5460 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
5461 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
5462 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
5463 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
5464 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
5465 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
5466 ctl->met_detrend =
5467 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
5468 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
5469 if (ctl->met_np > EP)
5470 ERRMSG("Too many levels!");
5471 ctl->met_press_level_def =
5472 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
5473 NULL);
5474 if (ctl->met_press_level_def >= 0) {
5475 level_definitions(ctl);
5476 } else {
5477 if (ctl->met_np > 0) {
5478 for (int ip = 0; ip < ctl->met_np; ip++)
5479 ctl->met_p[ip] =
5480 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
5481 }
5482 }
5483 ctl->met_geopot_sx =
5484 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
5485 ctl->met_geopot_sy =
5486 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
5487 ctl->met_relhum =
5488 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
5489 ctl->met_cape =
5490 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
5491 if (ctl->met_cape < 0 || ctl->met_cape > 1)
5492 ERRMSG("Set MET_CAPE to 0 or 1!");
5493 ctl->met_pbl =
5494 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
5495 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
5496 ERRMSG("Set MET_PBL to 0 ... 3!");
5497 ctl->met_pbl_min =
5498 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
5499 ctl->met_pbl_max =
5500 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
5501 ctl->met_tropo =
5502 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
5503 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
5504 ERRMSG("Set MET_TROPO to 0 ... 5!");
5505 ctl->met_tropo_pv =
5506 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
5507 ctl->met_tropo_theta =
5508 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
5509 ctl->met_tropo_spline =
5510 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
5511 ctl->met_dt_out =
5512 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
5513 ctl->met_cache =
5514 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
5515 ctl->met_mpi_share =
5516 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
5517
5518 /* Sorting... */
5519 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
5520
5521 /* Isosurface parameters... */
5522 ctl->isosurf =
5523 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
5524 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
5525
5526 /* Random number generator... */
5527 ctl->rng_type =
5528 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
5529 if (ctl->rng_type < 0 || ctl->rng_type > 2)
5530 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
5531
5532 /* Advection parameters... */
5533 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
5534 if (!(ctl->advect == 0 || ctl->advect == 1
5535 || ctl->advect == 2 || ctl->advect == 4))
5536 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
5537
5538 /* Diffusion parameters... */
5539 ctl->diffusion
5540 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
5541 if (ctl->diffusion < 0 || ctl->diffusion > 2)
5542 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
5543 ctl->turb_dx_pbl =
5544 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
5545 ctl->turb_dx_trop =
5546 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
5547 ctl->turb_dx_strat =
5548 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
5549 ctl->turb_dz_pbl =
5550 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
5551 ctl->turb_dz_trop =
5552 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
5553 ctl->turb_dz_strat =
5554 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
5555 ctl->turb_mesox =
5556 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
5557 ctl->turb_mesoz =
5558 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
5559
5560 /* Convection... */
5561 ctl->conv_mix_pbl
5562 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
5563 ctl->conv_pbl_trans
5564 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
5565 ctl->conv_cape
5566 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
5567 ctl->conv_cin
5568 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
5569 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
5570
5571 /* Boundary conditions... */
5572 ctl->bound_mass =
5573 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
5574 ctl->bound_mass_trend =
5575 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
5576 ctl->bound_vmr =
5577 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
5578 ctl->bound_vmr_trend =
5579 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
5580 ctl->bound_lat0 =
5581 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
5582 ctl->bound_lat1 =
5583 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
5584 ctl->bound_p0 =
5585 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
5586 ctl->bound_p1 =
5587 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
5588 ctl->bound_dps =
5589 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
5590 ctl->bound_dzs =
5591 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
5592 ctl->bound_zetas =
5593 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
5594 ctl->bound_pbl =
5595 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
5596
5597 /* Species parameters... */
5598 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
5599 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
5600 ctl->molmass = 120.907;
5601 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
5602 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5603 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5604 ctl->molmass = 137.359;
5605 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5606 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5607 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5608 ctl->molmass = 16.043;
5609 ctl->oh_chem_reaction = 2;
5610 ctl->oh_chem[0] = 2.45e-12;
5611 ctl->oh_chem[1] = 1775;
5612 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5613 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5614 } else if (strcasecmp(ctl->species, "CO") == 0) {
5615 ctl->molmass = 28.01;
5616 ctl->oh_chem_reaction = 3;
5617 ctl->oh_chem[0] = 6.9e-33;
5618 ctl->oh_chem[1] = 2.1;
5619 ctl->oh_chem[2] = 1.1e-12;
5620 ctl->oh_chem[3] = -1.3;
5621 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5622 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5623 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5624 ctl->molmass = 44.009;
5625 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5626 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5627 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5628 ctl->molmass = 18.01528;
5629 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5630 ctl->molmass = 44.013;
5631 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5632 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5633 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5634 ctl->molmass = 17.031;
5635 ctl->oh_chem_reaction = 2;
5636 ctl->oh_chem[0] = 1.7e-12;
5637 ctl->oh_chem[1] = 710;
5638 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
5639 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
5640 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
5641 ctl->molmass = 63.012;
5642 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
5643 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
5644 } else if (strcasecmp(ctl->species, "NO") == 0) {
5645 ctl->molmass = 30.006;
5646 ctl->oh_chem_reaction = 3;
5647 ctl->oh_chem[0] = 7.1e-31;
5648 ctl->oh_chem[1] = 2.6;
5649 ctl->oh_chem[2] = 3.6e-11;
5650 ctl->oh_chem[3] = 0.1;
5651 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
5652 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5653 } else if (strcasecmp(ctl->species, "NO2") == 0) {
5654 ctl->molmass = 46.005;
5655 ctl->oh_chem_reaction = 3;
5656 ctl->oh_chem[0] = 1.8e-30;
5657 ctl->oh_chem[1] = 3.0;
5658 ctl->oh_chem[2] = 2.8e-11;
5659 ctl->oh_chem[3] = 0.0;
5660 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
5661 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5662 } else if (strcasecmp(ctl->species, "O3") == 0) {
5663 ctl->molmass = 47.997;
5664 ctl->oh_chem_reaction = 2;
5665 ctl->oh_chem[0] = 1.7e-12;
5666 ctl->oh_chem[1] = 940;
5667 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
5668 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
5669 } else if (strcasecmp(ctl->species, "SF6") == 0) {
5670 ctl->molmass = 146.048;
5671 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
5672 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
5673 } else if (strcasecmp(ctl->species, "SO2") == 0) {
5674 ctl->molmass = 64.066;
5675 ctl->oh_chem_reaction = 3;
5676 ctl->oh_chem[0] = 2.9e-31;
5677 ctl->oh_chem[1] = 4.1;
5678 ctl->oh_chem[2] = 1.7e-12;
5679 ctl->oh_chem[3] = -0.2;
5680 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
5681 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
5682 }
5683
5684 /* Molar mass... */
5685 char defstr[LEN];
5686 sprintf(defstr, "%g", ctl->molmass);
5687 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
5688
5689 /* OH chemistry... */
5690 sprintf(defstr, "%d", ctl->oh_chem_reaction);
5691 ctl->oh_chem_reaction =
5692 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
5693 NULL);
5694 for (int ip = 0; ip < 4; ip++) {
5695 sprintf(defstr, "%g", ctl->oh_chem[ip]);
5696 ctl->oh_chem[ip] =
5697 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
5698 }
5699 ctl->oh_chem_beta =
5700 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
5701
5702 /* H2O2 chemistry... */
5703 ctl->h2o2_chem_reaction =
5704 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
5705
5706 /* KPP chemistry... */
5707 ctl->kpp_chem =
5708 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
5709 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
5710
5711 /* First order tracer chemistry... */
5712 ctl->tracer_chem =
5713 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
5714
5715 /* Wet deposition... */
5716 for (int ip = 0; ip < 2; ip++) {
5717 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
5718 ctl->wet_depo_ic_h[ip] =
5719 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
5720 }
5721 for (int ip = 0; ip < 1; ip++) {
5722 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
5723 ctl->wet_depo_bc_h[ip] =
5724 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
5725 }
5726 ctl->wet_depo_so2_ph =
5727 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
5728 ctl->wet_depo_ic_a =
5729 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
5730 ctl->wet_depo_ic_b =
5731 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
5732 ctl->wet_depo_bc_a =
5733 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
5734 ctl->wet_depo_bc_b =
5735 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
5736 ctl->wet_depo_pre[0] =
5737 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
5738 ctl->wet_depo_pre[1] =
5739 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
5741 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
5743 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
5744
5745 /* Dry deposition... */
5746 ctl->dry_depo_vdep =
5747 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
5748 ctl->dry_depo_dp =
5749 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
5750
5751 /* Climatological data... */
5752 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
5753 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
5754 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
5755 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
5756 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
5757 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
5758 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
5759 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
5760 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
5761 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
5762 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
5763 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
5764 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
5765 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
5766 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
5767 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
5768 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
5769 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
5770 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
5771 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
5772 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
5773 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
5774
5775 /* Mixing... */
5776 ctl->mixing_dt =
5777 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
5778 ctl->mixing_trop =
5779 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
5780 ctl->mixing_strat =
5781 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
5782 ctl->mixing_z0 =
5783 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
5784 ctl->mixing_z1 =
5785 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
5786 ctl->mixing_nz =
5787 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
5788 ctl->mixing_lon0 =
5789 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
5790 ctl->mixing_lon1 =
5791 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
5792 ctl->mixing_nx =
5793 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
5794 ctl->mixing_lat0 =
5795 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
5796 ctl->mixing_lat1 =
5797 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
5798 ctl->mixing_ny =
5799 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
5800
5801 /* Chemistry grid... */
5802 ctl->chemgrid_z0 =
5803 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
5804 ctl->chemgrid_z1 =
5805 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
5806 ctl->chemgrid_nz =
5807 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
5808 ctl->chemgrid_lon0 =
5809 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
5810 ctl->chemgrid_lon1 =
5811 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
5812 ctl->chemgrid_nx =
5813 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
5814 ctl->chemgrid_lat0 =
5815 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
5816 ctl->chemgrid_lat1 =
5817 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
5818 ctl->chemgrid_ny =
5819 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
5820
5821 /* Exponential decay... */
5822 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
5823 ctl->tdec_strat
5824 = scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
5825
5826 /* PSC analysis... */
5827 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
5828 ctl->psc_hno3 =
5829 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
5830
5831 /* Output of atmospheric data... */
5832 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
5833 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
5834 ctl->atm_dt_out =
5835 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
5836 ctl->atm_filter =
5837 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
5838 ctl->atm_stride =
5839 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
5840 ctl->atm_type =
5841 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
5842 ctl->atm_type_out =
5843 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
5844 if (ctl->atm_type_out == -1)
5845 ctl->atm_type_out = ctl->atm_type;
5846 ctl->atm_nc_level =
5847 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
5848 for (int iq = 0; iq < ctl->nq; iq++)
5849 ctl->atm_nc_quant[iq] =
5850 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
5851 ctl->obs_type =
5852 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
5853
5854 /* Output of CSI data... */
5855 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
5856 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
5857 ctl->csi_dt_out =
5858 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
5859 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
5860 ctl->csi_obsmin =
5861 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
5862 ctl->csi_modmin =
5863 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
5864 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
5865 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
5866 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
5867 ctl->csi_lon0 =
5868 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
5869 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
5870 ctl->csi_nx =
5871 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
5872 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
5873 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
5874 ctl->csi_ny =
5875 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
5876
5877 /* Output of ensemble data... */
5878 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
5879 ctl->ens_dt_out =
5880 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
5881
5882 /* Output of grid data... */
5883 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
5884 ctl->grid_basename);
5885 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
5886 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
5887 ctl->grid_dt_out =
5888 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
5889 ctl->grid_sparse =
5890 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
5891 ctl->grid_nc_level =
5892 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
5893 for (int iq = 0; iq < ctl->nq; iq++)
5894 ctl->grid_nc_quant[iq] =
5895 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
5896 ctl->grid_stddev =
5897 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
5898 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
5899 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
5900 ctl->grid_nz =
5901 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
5902 ctl->grid_lon0 =
5903 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
5904 ctl->grid_lon1 =
5905 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
5906 ctl->grid_nx =
5907 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
5908 ctl->grid_lat0 =
5909 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
5910 ctl->grid_lat1 =
5911 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
5912 ctl->grid_ny =
5913 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
5914 ctl->grid_type =
5915 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
5916
5917 /* Output of profile data... */
5918 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
5919 ctl->prof_basename);
5920 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
5921 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
5922 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
5923 ctl->prof_nz =
5924 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
5925 ctl->prof_lon0 =
5926 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
5927 ctl->prof_lon1 =
5928 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
5929 ctl->prof_nx =
5930 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
5931 ctl->prof_lat0 =
5932 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
5933 ctl->prof_lat1 =
5934 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
5935 ctl->prof_ny =
5936 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
5937
5938 /* Output of sample data... */
5939 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
5940 ctl->sample_basename);
5941 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
5942 ctl->sample_kernel);
5943 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
5944 ctl->sample_obsfile);
5945 ctl->sample_dx =
5946 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
5947 ctl->sample_dz =
5948 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
5949
5950 /* Output of station data... */
5951 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
5952 ctl->stat_basename);
5953 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
5954 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
5955 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
5956 ctl->stat_t0 =
5957 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
5958 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
5959
5960 /* Output of VTK data... */
5961 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
5962 ctl->vtk_dt_out =
5963 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
5964 ctl->vtk_stride =
5965 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
5966 ctl->vtk_scale =
5967 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
5968 ctl->vtk_offset =
5969 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
5970 ctl->vtk_sphere =
5971 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
5972}
5973
5974/*****************************************************************************/
5975
5977 const char *filename,
5978 double kz[EP],
5979 double kw[EP],
5980 int *nk) {
5981
5982 /* Write info... */
5983 LOG(1, "Read kernel function: %s", filename);
5984
5985 /* Open file... */
5986 FILE *in;
5987 if (!(in = fopen(filename, "r")))
5988 ERRMSG("Cannot open file!");
5989
5990 /* Read data... */
5991 char line[LEN];
5992 int n = 0;
5993 while (fgets(line, LEN, in))
5994 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
5995 if (n > 0 && kz[n] < kz[n - 1])
5996 ERRMSG("Height levels must be ascending!");
5997 if ((++n) >= EP)
5998 ERRMSG("Too many height levels!");
5999 }
6000
6001 /* Close file... */
6002 fclose(in);
6003
6004 /* Check number of data points... */
6005 *nk = n;
6006 if (n < 2)
6007 ERRMSG("Not enough height levels!");
6008
6009 /* Normalize kernel function... */
6010 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
6011 for (int iz = 0; iz < n; iz++)
6012 kw[iz] /= kmax;
6013}
6014
6015/*****************************************************************************/
6016
6018 const char *filename,
6019 const ctl_t *ctl,
6020 const clim_t *clim,
6021 met_t *met) {
6022
6023 /* Write info... */
6024 LOG(1, "Read meteo data: %s", filename);
6025
6026 /* Set rank... */
6027 int rank = 0;
6028#ifdef MPI
6029 if (ctl->met_mpi_share)
6030 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
6031#endif
6032
6033 /* Check rank... */
6034 if (!ctl->met_mpi_share || rank == 0) {
6035
6036 /* Read netCDF data... */
6037 if (ctl->met_type == 0) {
6038 if (read_met_nc(filename, ctl, clim, met) != 1)
6039 return 0;
6040 }
6041
6042 /* Read binary data... */
6043 else if (ctl->met_type >= 1 && ctl->met_type <= 5) {
6044 if (read_met_bin(filename, ctl, met) != 1)
6045 return 0;
6046 }
6047
6048 /* Not implemented... */
6049 else
6050 ERRMSG("MET_TYPE not implemented!");
6051 }
6052
6053 /* Broadcast data via MPI... */
6054#ifdef MPI
6055 if (ctl->met_mpi_share) {
6056
6057 /* Set timer... */
6058 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
6059 LOG(2, "Broadcast data on rank %d...", rank);
6060
6061 /* Broadcast... */
6062 broadcast_large_data(met, sizeof(met_t));
6063 }
6064#endif
6065
6066 /* Return success... */
6067 return 1;
6068}
6069
6070/*****************************************************************************/
6071
6073 const char *filename,
6074 const ctl_t *ctl,
6075 met_t *met) {
6076
6077 FILE *in;
6078
6079 double r;
6080
6081 int year, mon, day, hour, min, sec;
6082
6083 /* Set timer... */
6084 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
6085
6086 /* Open file... */
6087 if (!(in = fopen(filename, "r"))) {
6088 WARN("Cannot open file!");
6089 return 0;
6090 }
6091
6092 /* Check type of binary data... */
6093 int met_type;
6094 FREAD(&met_type, int,
6095 1,
6096 in);
6097 if (met_type != ctl->met_type)
6098 ERRMSG("Wrong MET_TYPE of binary data!");
6099
6100 /* Check version of binary data... */
6101 int version;
6102 FREAD(&version, int,
6103 1,
6104 in);
6105 if (version != 103)
6106 ERRMSG("Wrong version of binary data!");
6107
6108 /* Read time... */
6109 FREAD(&met->time, double,
6110 1,
6111 in);
6112 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
6113 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
6114 met->time, year, mon, day, hour, min);
6115 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
6116 || day < 1 || day > 31 || hour < 0 || hour > 23)
6117 ERRMSG("Error while reading time!");
6118
6119 /* Read dimensions... */
6120 FREAD(&met->nx, int,
6121 1,
6122 in);
6123 LOG(2, "Number of longitudes: %d", met->nx);
6124 if (met->nx < 2 || met->nx > EX)
6125 ERRMSG("Number of longitudes out of range!");
6126
6127 FREAD(&met->ny, int,
6128 1,
6129 in);
6130 LOG(2, "Number of latitudes: %d", met->ny);
6131 if (met->ny < 2 || met->ny > EY)
6132 ERRMSG("Number of latitudes out of range!");
6133
6134 FREAD(&met->np, int,
6135 1,
6136 in);
6137 LOG(2, "Number of levels: %d", met->np);
6138 if (met->np < 2 || met->np > EP)
6139 ERRMSG("Number of levels out of range!");
6140
6141 /* Read grid... */
6142 FREAD(met->lon, double,
6143 (size_t) met->nx,
6144 in);
6145 LOG(2, "Longitudes: %g, %g ... %g deg",
6146 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
6147
6148 FREAD(met->lat, double,
6149 (size_t) met->ny,
6150 in);
6151 LOG(2, "Latitudes: %g, %g ... %g deg",
6152 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
6153
6154 FREAD(met->p, double,
6155 (size_t) met->np,
6156 in);
6157 LOG(2, "Altitude levels: %g, %g ... %g km",
6158 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
6159 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6160 met->p[0], met->p[1], met->p[met->np - 1]);
6161
6162 /* Read surface data... */
6163 read_met_bin_2d(in, met, met->ps, "PS");
6164 read_met_bin_2d(in, met, met->ts, "TS");
6165 read_met_bin_2d(in, met, met->zs, "ZS");
6166 read_met_bin_2d(in, met, met->us, "US");
6167 read_met_bin_2d(in, met, met->vs, "VS");
6168 read_met_bin_2d(in, met, met->ess, "ESS");
6169 read_met_bin_2d(in, met, met->nss, "NSS");
6170 read_met_bin_2d(in, met, met->shf, "SHF");
6171 read_met_bin_2d(in, met, met->lsm, "LSM");
6172 read_met_bin_2d(in, met, met->sst, "SST");
6173 read_met_bin_2d(in, met, met->pbl, "PBL");
6174 read_met_bin_2d(in, met, met->pt, "PT");
6175 read_met_bin_2d(in, met, met->tt, "TT");
6176 read_met_bin_2d(in, met, met->zt, "ZT");
6177 read_met_bin_2d(in, met, met->h2ot, "H2OT");
6178 read_met_bin_2d(in, met, met->pct, "PCT");
6179 read_met_bin_2d(in, met, met->pcb, "PCB");
6180 read_met_bin_2d(in, met, met->cl, "CL");
6181 read_met_bin_2d(in, met, met->plcl, "PLCL");
6182 read_met_bin_2d(in, met, met->plfc, "PLFC");
6183 read_met_bin_2d(in, met, met->pel, "PEL");
6184 read_met_bin_2d(in, met, met->cape, "CAPE");
6185 read_met_bin_2d(in, met, met->cin, "CIN");
6186 read_met_bin_2d(in, met, met->o3c, "O3C");
6187
6188 /* Read level data... */
6189 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
6190 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
6191 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
6192 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
6193 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
6194 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
6195 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
6196 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
6197 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
6198 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
6199 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
6200 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
6201 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
6202
6203 /* Read final flag... */
6204 int final;
6205 FREAD(&final, int,
6206 1,
6207 in);
6208 if (final != 999)
6209 ERRMSG("Error while reading binary data!");
6210
6211 /* Close file... */
6212 fclose(in);
6213
6214 /* Return success... */
6215 return 1;
6216}
6217
6218/*****************************************************************************/
6219
6221 FILE *in,
6222 const met_t *met,
6223 float var[EX][EY],
6224 const char *varname) {
6225
6226 float *help;
6227
6228 /* Allocate... */
6229 ALLOC(help, float,
6230 EX * EY);
6231
6232 /* Read uncompressed... */
6233 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
6234 FREAD(help, float,
6235 (size_t) (met->nx * met->ny),
6236 in);
6237
6238 /* Copy data... */
6239 for (int ix = 0; ix < met->nx; ix++)
6240 for (int iy = 0; iy < met->ny; iy++)
6241 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
6242
6243 /* Free... */
6244 free(help);
6245}
6246
6247/*****************************************************************************/
6248
6250 FILE *in,
6251 const ctl_t *ctl,
6252 const met_t *met,
6253 float var[EX][EY][EP],
6254 const char *varname,
6255 const float bound_min,
6256 const float bound_max) {
6257
6258 float *help;
6259
6260 /* Allocate... */
6261 ALLOC(help, float,
6262 EX * EY * EP);
6263
6264 /* Read uncompressed data... */
6265 if (ctl->met_type == 1) {
6266 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
6267 FREAD(help, float,
6268 (size_t) (met->nx * met->ny * met->np),
6269 in);
6270 }
6271
6272 /* Read packed data... */
6273 else if (ctl->met_type == 2)
6274 compress_pck(varname, help, (size_t) (met->ny * met->nx),
6275 (size_t) met->np, 1, in);
6276
6277 /* Read zfp data... */
6278 else if (ctl->met_type == 3) {
6279#ifdef ZFP
6280 int precision;
6281 FREAD(&precision, int,
6282 1,
6283 in);
6284
6285 double tolerance;
6286 FREAD(&tolerance, double,
6287 1,
6288 in);
6289
6290 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
6291 tolerance, 1, in);
6292#else
6293 ERRMSG("MPTRAC was compiled without zfp compression!");
6294#endif
6295 }
6296
6297 /* Read zstd data... */
6298 else if (ctl->met_type == 4) {
6299#ifdef ZSTD
6300 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
6301 in);
6302#else
6303 ERRMSG("MPTRAC was compiled without zstd compression!");
6304#endif
6305 }
6306
6307 /* Read cmultiscale data... */
6308 else if (ctl->met_type == 5) {
6309#ifdef CMS
6310 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
6311 (size_t) met->np, 1, in);
6312#else
6313 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6314#endif
6315 }
6316
6317 /* Copy data... */
6318#pragma omp parallel for default(shared) collapse(2)
6319 for (int ix = 0; ix < met->nx; ix++)
6320 for (int iy = 0; iy < met->ny; iy++)
6321 for (int ip = 0; ip < met->np; ip++) {
6322 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
6323 if (var[ix][iy][ip] < bound_min)
6324 var[ix][iy][ip] = bound_min;
6325 else if (var[ix][iy][ip] > bound_max)
6326 var[ix][iy][ip] = bound_max;
6327 }
6328
6329 /* Free... */
6330 free(help);
6331}
6332
6333/*****************************************************************************/
6334
6336 const ctl_t *ctl,
6337 const clim_t *clim,
6338 met_t *met) {
6339
6340 /* Check parameters... */
6341 if (ctl->met_cape != 1)
6342 return;
6343
6344 /* Set timer... */
6345 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
6346 LOG(2, "Calculate CAPE...");
6347
6348 /* Vertical spacing (about 100 m)... */
6349 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
6350
6351 /* Loop over columns... */
6352#pragma omp parallel for default(shared) collapse(2)
6353 for (int ix = 0; ix < met->nx; ix++)
6354 for (int iy = 0; iy < met->ny; iy++) {
6355
6356 /* Get potential temperature and water vapor at lowest 50 hPa... */
6357 int n = 0;
6358 double h2o = 0, t, theta = 0;
6359 double pbot = MIN(met->ps[ix][iy], met->p[0]);
6360 double ptop = pbot - 50.;
6361 for (int ip = 0; ip < met->np; ip++) {
6362 if (met->p[ip] <= pbot) {
6363 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
6364 h2o += met->h2o[ix][iy][ip];
6365 n++;
6366 }
6367 if (met->p[ip] < ptop && n > 0)
6368 break;
6369 }
6370 theta /= n;
6371 h2o /= n;
6372
6373 /* Cannot compute anything if water vapor is missing... */
6374 met->plcl[ix][iy] = NAN;
6375 met->plfc[ix][iy] = NAN;
6376 met->pel[ix][iy] = NAN;
6377 met->cape[ix][iy] = NAN;
6378 met->cin[ix][iy] = NAN;
6379 if (h2o <= 0)
6380 continue;
6381
6382 /* Find lifted condensation level (LCL)... */
6383 ptop = P(20.);
6384 pbot = met->ps[ix][iy];
6385 do {
6386 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
6387 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
6388 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
6389 ptop = met->plcl[ix][iy];
6390 else
6391 pbot = met->plcl[ix][iy];
6392 } while (pbot - ptop > 0.1);
6393
6394 /* Calculate CIN up to LCL... */
6396 double dcape, dz, h2o_env, t_env;
6397 double p = met->ps[ix][iy];
6398 met->cape[ix][iy] = met->cin[ix][iy] = 0;
6399 do {
6400 dz = dz0 * TVIRT(t, h2o);
6401 p /= pfac;
6402 t = theta / pow(1000. / p, 0.286);
6403 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6404 &t_env, ci, cw, 1);
6405 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6406 &h2o_env, ci, cw, 0);
6407 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6408 TVIRT(t_env, h2o_env) * dz;
6409 if (dcape < 0)
6410 met->cin[ix][iy] += fabsf((float) dcape);
6411 } while (p > met->plcl[ix][iy]);
6412
6413 /* Calculate level of free convection (LFC), equilibrium level (EL),
6414 and convective available potential energy (CAPE)... */
6415 dcape = 0;
6416 p = met->plcl[ix][iy];
6417 t = theta / pow(1000. / p, 0.286);
6418 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
6419 do {
6420 dz = dz0 * TVIRT(t, h2o);
6421 p /= pfac;
6422 t -= lapse_rate(t, h2o) * dz;
6423 double psat = PSAT(t);
6424 h2o = psat / (p - (1. - EPS) * psat);
6425 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6426 &t_env, ci, cw, 1);
6427 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6428 &h2o_env, ci, cw, 0);
6429 double dcape_old = dcape;
6430 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6431 TVIRT(t_env, h2o_env) * dz;
6432 if (dcape > 0) {
6433 met->cape[ix][iy] += (float) dcape;
6434 if (!isfinite(met->plfc[ix][iy]))
6435 met->plfc[ix][iy] = (float) p;
6436 } else if (dcape_old > 0)
6437 met->pel[ix][iy] = (float) p;
6438 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
6439 met->cin[ix][iy] += fabsf((float) dcape);
6440 } while (p > ptop);
6441
6442 /* Check results... */
6443 if (!isfinite(met->plfc[ix][iy]))
6444 met->cin[ix][iy] = NAN;
6445 }
6446}
6447
6448/*****************************************************************************/
6449
6451 met_t *met) {
6452
6453 /* Set timer... */
6454 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
6455 LOG(2, "Calculate cloud data...");
6456
6457 /* Thresholds for cloud detection... */
6458 const double ccmin = 0.01, cwmin = 1e-6;
6459
6460 /* Loop over columns... */
6461#pragma omp parallel for default(shared) collapse(2)
6462 for (int ix = 0; ix < met->nx; ix++)
6463 for (int iy = 0; iy < met->ny; iy++) {
6464
6465 /* Init... */
6466 met->pct[ix][iy] = NAN;
6467 met->pcb[ix][iy] = NAN;
6468 met->cl[ix][iy] = 0;
6469
6470 /* Loop over pressure levels... */
6471 for (int ip = 0; ip < met->np - 1; ip++) {
6472
6473 /* Check pressure... */
6474 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
6475 continue;
6476
6477 /* Check ice water and liquid water content... */
6478 if (met->cc[ix][iy][ip] > ccmin
6479 && (met->iwc[ix][iy][ip] > cwmin
6480 || met->rwc[ix][iy][ip] > cwmin
6481 || met->lwc[ix][iy][ip] > cwmin
6482 || met->swc[ix][iy][ip] > cwmin)) {
6483
6484 /* Get cloud top pressure ... */
6485 met->pct[ix][iy]
6486 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
6487
6488 /* Get cloud bottom pressure ... */
6489 if (!isfinite(met->pcb[ix][iy]))
6490 met->pcb[ix][iy]
6491 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
6492 }
6493
6494 /* Get cloud water... */
6495 met->cl[ix][iy] += (float)
6496 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
6497 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
6498 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
6499 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
6500 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
6501 }
6502 }
6503}
6504
6505/*****************************************************************************/
6506
6508 const ctl_t *ctl,
6509 met_t *met) {
6510
6511 met_t *help;
6512
6513 /* Check parameters... */
6514 if (ctl->met_detrend <= 0)
6515 return;
6516
6517 /* Set timer... */
6518 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
6519 LOG(2, "Detrend meteo data...");
6520
6521 /* Allocate... */
6522 ALLOC(help, met_t, 1);
6523
6524 /* Calculate standard deviation... */
6525 const double sigma = ctl->met_detrend / 2.355;
6526 const double tssq = 2. * SQR(sigma);
6527
6528 /* Calculate box size in latitude... */
6529 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
6530 sy = MIN(MAX(1, sy), met->ny / 2);
6531
6532 /* Calculate background... */
6533#pragma omp parallel for default(shared) collapse(2)
6534 for (int ix = 0; ix < met->nx; ix++) {
6535 for (int iy = 0; iy < met->ny; iy++) {
6536
6537 /* Calculate Cartesian coordinates... */
6538 double x0[3];
6539 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
6540
6541 /* Calculate box size in longitude... */
6542 int sx =
6543 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
6544 fabs(met->lon[1] - met->lon[0]));
6545 sx = MIN(MAX(1, sx), met->nx / 2);
6546
6547 /* Init... */
6548 float wsum = 0;
6549 for (int ip = 0; ip < met->np; ip++) {
6550 help->t[ix][iy][ip] = 0;
6551 help->u[ix][iy][ip] = 0;
6552 help->v[ix][iy][ip] = 0;
6553 help->w[ix][iy][ip] = 0;
6554 }
6555
6556 /* Loop over neighboring grid points... */
6557 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
6558 int ix3 = ix2;
6559 if (ix3 < 0)
6560 ix3 += met->nx;
6561 else if (ix3 >= met->nx)
6562 ix3 -= met->nx;
6563 for (int iy2 = MAX(iy - sy, 0);
6564 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
6565
6566 /* Calculate Cartesian coordinates... */
6567 double x1[3];
6568 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
6569
6570 /* Calculate weighting factor... */
6571 const float w = (float) exp(-DIST2(x0, x1) / tssq);
6572
6573 /* Add data... */
6574 wsum += w;
6575 for (int ip = 0; ip < met->np; ip++) {
6576 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
6577 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
6578 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
6579 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
6580 }
6581 }
6582 }
6583
6584 /* Normalize... */
6585 for (int ip = 0; ip < met->np; ip++) {
6586 help->t[ix][iy][ip] /= wsum;
6587 help->u[ix][iy][ip] /= wsum;
6588 help->v[ix][iy][ip] /= wsum;
6589 help->w[ix][iy][ip] /= wsum;
6590 }
6591 }
6592 }
6593
6594 /* Subtract background... */
6595#pragma omp parallel for default(shared) collapse(3)
6596 for (int ix = 0; ix < met->nx; ix++)
6597 for (int iy = 0; iy < met->ny; iy++)
6598 for (int ip = 0; ip < met->np; ip++) {
6599 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
6600 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
6601 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
6602 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
6603 }
6604
6605 /* Free... */
6606 free(help);
6607}
6608
6609/*****************************************************************************/
6610
6612 met_t *met) {
6613
6614 /* Set timer... */
6615 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
6616 LOG(2, "Extrapolate meteo data...");
6617
6618 /* Loop over columns... */
6619#pragma omp parallel for default(shared) collapse(2)
6620 for (int ix = 0; ix < met->nx; ix++)
6621 for (int iy = 0; iy < met->ny; iy++) {
6622
6623 /* Find lowest valid data point... */
6624 int ip0;
6625 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
6626 if (!isfinite(met->t[ix][iy][ip0])
6627 || !isfinite(met->u[ix][iy][ip0])
6628 || !isfinite(met->v[ix][iy][ip0])
6629 || !isfinite(met->w[ix][iy][ip0]))
6630 break;
6631
6632 /* Extrapolate... */
6633 for (int ip = ip0; ip >= 0; ip--) {
6634 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
6635 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
6636 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
6637 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
6638 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
6639 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
6640 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
6641 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
6642 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
6643 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
6644 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
6645 }
6646 }
6647}
6648
6649/*****************************************************************************/
6650
6652 const ctl_t *ctl,
6653 met_t *met) {
6654
6655 float *help;
6656
6657 double logp[EP];
6658
6659 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
6660
6661 /* Set timer... */
6662 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
6663 LOG(2, "Calculate geopotential heights...");
6664
6665 /* Allocate... */
6666 ALLOC(help, float,
6667 EX * EY * EP);
6668
6669 /* Calculate log pressure... */
6670#pragma omp parallel for default(shared)
6671 for (int ip = 0; ip < met->np; ip++)
6672 logp[ip] = log(met->p[ip]);
6673
6674 /* Apply hydrostatic equation to calculate geopotential heights... */
6675#pragma omp parallel for default(shared) collapse(2)
6676 for (int ix = 0; ix < met->nx; ix++)
6677 for (int iy = 0; iy < met->ny; iy++) {
6678
6679 /* Get surface height and pressure... */
6680 const double zs = met->zs[ix][iy];
6681 const double lnps = log(met->ps[ix][iy]);
6682
6683 /* Get temperature and water vapor at the surface... */
6684 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
6685 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
6686 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
6687 const double h2os =
6688 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
6689 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
6690
6691 /* Upper part of profile... */
6692 met->z[ix][iy][ip0 + 1]
6693 = (float) (zs +
6694 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
6695 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
6696 for (int ip = ip0 + 2; ip < met->np; ip++)
6697 met->z[ix][iy][ip]
6698 = (float) (met->z[ix][iy][ip - 1] +
6699 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
6700 met->h2o[ix][iy][ip - 1], logp[ip],
6701 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
6702
6703 /* Lower part of profile... */
6704 met->z[ix][iy][ip0]
6705 = (float) (zs +
6706 ZDIFF(lnps, ts, h2os, logp[ip0],
6707 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
6708 for (int ip = ip0 - 1; ip >= 0; ip--)
6709 met->z[ix][iy][ip]
6710 = (float) (met->z[ix][iy][ip + 1] +
6711 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
6712 met->h2o[ix][iy][ip + 1], logp[ip],
6713 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
6714 }
6715
6716 /* Check control parameters... */
6717 if (dx == 0 || dy == 0)
6718 return;
6719
6720 /* Default smoothing parameters... */
6721 if (dx < 0 || dy < 0) {
6722 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
6723 dx = 3;
6724 dy = 2;
6725 } else {
6726 dx = 6;
6727 dy = 4;
6728 }
6729 }
6730
6731 /* Calculate weights for smoothing... */
6732 float ws[dx + 1][dy + 1];
6733#pragma omp parallel for default(shared) collapse(2)
6734 for (int ix = 0; ix <= dx; ix++)
6735 for (int iy = 0; iy < dy; iy++)
6736 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
6737 * (1.0f - (float) iy / (float) dy);
6738
6739 /* Copy data... */
6740#pragma omp parallel for default(shared) collapse(3)
6741 for (int ix = 0; ix < met->nx; ix++)
6742 for (int iy = 0; iy < met->ny; iy++)
6743 for (int ip = 0; ip < met->np; ip++)
6744 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
6745
6746 /* Horizontal smoothing... */
6747#pragma omp parallel for default(shared) collapse(3)
6748 for (int ip = 0; ip < met->np; ip++)
6749 for (int ix = 0; ix < met->nx; ix++)
6750 for (int iy = 0; iy < met->ny; iy++) {
6751 float res = 0, wsum = 0;
6752 int iy0 = MAX(iy - dy + 1, 0);
6753 int iy1 = MIN(iy + dy - 1, met->ny - 1);
6754 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
6755 int ix3 = ix2;
6756 if (ix3 < 0)
6757 ix3 += met->nx;
6758 else if (ix3 >= met->nx)
6759 ix3 -= met->nx;
6760 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
6761 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
6762 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
6763 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
6764 wsum += w;
6765 }
6766 }
6767 if (wsum > 0)
6768 met->z[ix][iy][ip] = res / wsum;
6769 else
6770 met->z[ix][iy][ip] = NAN;
6771 }
6772
6773 /* Free... */
6774 free(help);
6775}
6776
6777/*****************************************************************************/
6778
6780 const char *filename,
6781 const int ncid,
6782 const ctl_t *ctl,
6783 met_t *met) {
6784
6785 char levname[LEN], tstr[10];
6786
6787 double rtime = 0, r, r2;
6788
6789 int varid, year2, mon2, day2, hour2, min2, sec2,
6790 year, mon, day, hour, min, sec;
6791
6792 size_t np;
6793
6794 /* Set timer... */
6795 SELECT_TIMER("READ_MET_GRID", "INPUT", NVTX_READ);
6796 LOG(2, "Read meteo grid information...");
6797
6798 /* MPTRAC meteo files... */
6799 if (ctl->met_clams == 0) {
6800
6801 /* Get time from filename... */
6802 met->time = time_from_filename(filename, 16);
6803
6804 /* Check time information from data file... */
6805 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
6806 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
6807 NC(nc_get_var_double(ncid, varid, &rtime));
6808 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
6809 WARN("Time information in meteo file does not match filename!");
6810 } else
6811 WARN("Time information in meteo file is missing!");
6812 }
6813
6814 /* CLaMS meteo files... */
6815 else {
6816
6817 /* Read time from file... */
6818 NC_GET_DOUBLE("time", &rtime, 0);
6819
6820 /* Get time from filename (considering the century)... */
6821 if (rtime < 0)
6822 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
6823 else
6824 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
6825 year = atoi(tstr);
6826 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
6827 mon = atoi(tstr);
6828 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
6829 day = atoi(tstr);
6830 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
6831 hour = atoi(tstr);
6832 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
6833 }
6834
6835 /* Check time... */
6836 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
6837 || day < 1 || day > 31 || hour < 0 || hour > 23)
6838 ERRMSG("Cannot read time from filename!");
6839 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
6840 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
6841 met->time, year2, mon2, day2, hour2, min2);
6842
6843 /* Get grid dimensions... */
6844 NC_INQ_DIM("lon", &met->nx, 2, EX);
6845 LOG(2, "Number of longitudes: %d", met->nx);
6846
6847 NC_INQ_DIM("lat", &met->ny, 2, EY);
6848 LOG(2, "Number of latitudes: %d", met->ny);
6849
6850 int dimid2;
6851 sprintf(levname, "lev");
6852 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
6853 sprintf(levname, "plev");
6854 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
6855 sprintf(levname, "hybrid");
6856
6857 NC_INQ_DIM(levname, &met->np, 1, EP);
6858 if (met->np == 1) {
6859 sprintf(levname, "lev_2");
6860 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR) {
6861 sprintf(levname, "plev");
6862 NC(nc_inq_dimid(ncid, levname, &dimid2));
6863 }
6864 NC(nc_inq_dimlen(ncid, dimid2, &np));
6865 met->np = (int) np;
6866 }
6867 LOG(2, "Number of levels: %d", met->np);
6868 if (met->np < 2 || met->np > EP)
6869 ERRMSG("Number of levels out of range!");
6870
6871 /* Read longitudes and latitudes... */
6872 NC_GET_DOUBLE("lon", met->lon, 1);
6873 LOG(2, "Longitudes: %g, %g ... %g deg",
6874 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
6875 NC_GET_DOUBLE("lat", met->lat, 1);
6876 LOG(2, "Latitudes: %g, %g ... %g deg",
6877 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
6878
6879 /* Read pressure levels... */
6880 if (ctl->met_np <= 0) {
6881 NC_GET_DOUBLE(levname, met->p, 1);
6882 for (int ip = 0; ip < met->np; ip++)
6883 met->p[ip] /= 100.;
6884 LOG(2, "Altitude levels: %g, %g ... %g km",
6885 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
6886 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6887 met->p[0], met->p[1], met->p[met->np - 1]);
6888 }
6889
6890 /* Read hybrid levels... */
6891 if (strcasecmp(levname, "hybrid") == 0)
6892 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
6893}
6894
6895/*****************************************************************************/
6896
6898 const int ncid,
6899 const ctl_t *ctl,
6900 met_t *met) {
6901
6902 /* Set timer... */
6903 SELECT_TIMER("READ_MET_LEVELS", "INPUT", NVTX_READ);
6904 LOG(2, "Read level data...");
6905
6906 /* Read temperature... */
6907 if (!read_met_nc_3d(ncid, "t", "T", "temp", "TEMP", ctl, met, met->t, 1.0))
6908 ERRMSG("Cannot read temperature!");
6909
6910 /* Read horizontal wind and vertical velocity... */
6911 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, met->u, 1.0))
6912 ERRMSG("Cannot read zonal wind!");
6913 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, met->v, 1.0))
6914 ERRMSG("Cannot read meridional wind!");
6915 if (!read_met_nc_3d
6916 (ncid, "w", "W", "omega", "OMEGA", ctl, met, met->w, 0.01f))
6917 WARN("Cannot read vertical velocity!");
6918
6919 /* Read water vapor... */
6920 if (!ctl->met_relhum) {
6921 if (!read_met_nc_3d
6922 (ncid, "q", "Q", "sh", "SH", ctl, met, met->h2o, (float) (MA / MH2O)))
6923 WARN("Cannot read specific humidity!");
6924 } else {
6925 if (!read_met_nc_3d
6926 (ncid, "rh", "RH", NULL, NULL, ctl, met, met->h2o, 0.01f))
6927 WARN("Cannot read relative humidity!");
6928#pragma omp parallel for default(shared) collapse(2)
6929 for (int ix = 0; ix < met->nx; ix++)
6930 for (int iy = 0; iy < met->ny; iy++)
6931 for (int ip = 0; ip < met->np; ip++) {
6932 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
6933 met->h2o[ix][iy][ip] =
6934 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
6935 }
6936 }
6937
6938 /* Read ozone... */
6939 if (!read_met_nc_3d
6940 (ncid, "o3", "O3", NULL, NULL, ctl, met, met->o3, (float) (MA / MO3)))
6941 WARN("Cannot read ozone data!");
6942
6943 /* Read cloud data... */
6944 if (!read_met_nc_3d
6945 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, met->lwc, 1.0))
6946 WARN("Cannot read cloud liquid water content!");
6947 if (!read_met_nc_3d
6948 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, met->rwc, 1.0))
6949 WARN("Cannot read cloud rain water content!");
6950 if (!read_met_nc_3d
6951 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, met->iwc, 1.0))
6952 WARN("Cannot read cloud ice water content!");
6953 if (!read_met_nc_3d
6954 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, met->swc, 1.0))
6955 WARN("Cannot read cloud snow water content!");
6956 if (!read_met_nc_3d(ncid, "cc", "CC", NULL, NULL, ctl, met, met->cc, 1.0))
6957 WARN("Cannot read cloud cover!");
6958
6959 /* Read zeta and zeta_dot... */
6960 if (!read_met_nc_3d
6961 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, met->zetal, 1.0))
6962 WARN("Cannot read ZETA!");
6963 if (!read_met_nc_3d
6964 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
6965 NULL, ctl, met, met->zeta_dotl, 0.00001157407f))
6966 WARN("Cannot read ZETA_DOT!");
6967
6968 /* Store velocities on model levels for diabatic advection... */
6969 if (ctl->met_vert_coord == 1) {
6970 for (int ix = 0; ix < met->nx; ix++)
6971 for (int iy = 0; iy < met->ny; iy++)
6972 for (int ip = 0; ip < met->np; ip++) {
6973 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
6974 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
6975 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
6976 }
6977
6978 /* Original number of vertical levels... */
6979 met->npl = met->np;
6980 }
6981
6982 /* Read pressure on model levels... */
6983 if (ctl->met_np > 0 || ctl->met_vert_coord == 1) {
6984
6985 /* Read data... */
6986 if (!read_met_nc_3d
6987 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, met->pl, 0.01f))
6988 if (!read_met_nc_3d
6989 (ncid, "press", "PRESS", NULL, NULL, ctl, met, met->pl, 1.0))
6990 ERRMSG("Cannot read pressure on model levels!");
6991
6992 /* Check ordering of pressure levels... */
6993 for (int ix = 0; ix < met->nx; ix++)
6994 for (int iy = 0; iy < met->ny; iy++)
6995 for (int ip = 1; ip < met->np; ip++)
6996 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
6997 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
6998 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
6999 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
7000 ERRMSG("Pressure profiles are not monotonic!");
7001 }
7002
7003 /* Interpolate from model levels to pressure levels... */
7004 if (ctl->met_np > 0) {
7005
7006 /* Interpolate variables... */
7007 read_met_ml2pl(ctl, met, met->t, "T");
7008 read_met_ml2pl(ctl, met, met->u, "U");
7009 read_met_ml2pl(ctl, met, met->v, "V");
7010 read_met_ml2pl(ctl, met, met->w, "W");
7011 read_met_ml2pl(ctl, met, met->h2o, "H2O");
7012 read_met_ml2pl(ctl, met, met->o3, "O3");
7013 read_met_ml2pl(ctl, met, met->lwc, "LWC");
7014 read_met_ml2pl(ctl, met, met->rwc, "RWC");
7015 read_met_ml2pl(ctl, met, met->iwc, "IWC");
7016 read_met_ml2pl(ctl, met, met->swc, "SWC");
7017 read_met_ml2pl(ctl, met, met->cc, "CC");
7018
7019 /* Set new pressure levels... */
7020 met->np = ctl->met_np;
7021 for (int ip = 0; ip < met->np; ip++)
7022 met->p[ip] = ctl->met_p[ip];
7023 }
7024
7025 /* Check ordering of pressure levels... */
7026 for (int ip = 1; ip < met->np; ip++)
7027 if (met->p[ip - 1] < met->p[ip])
7028 ERRMSG("Pressure levels must be descending!");
7029}
7030
7031/*****************************************************************************/
7032
7034 const ctl_t *ctl,
7035 const met_t *met,
7036 float var[EX][EY][EP],
7037 const char *varname) {
7038
7039 double aux[EP], p[EP];
7040
7041 /* Set timer... */
7042 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
7043 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
7044
7045 /* Loop over columns... */
7046#pragma omp parallel for default(shared) private(aux,p) collapse(2)
7047 for (int ix = 0; ix < met->nx; ix++)
7048 for (int iy = 0; iy < met->ny; iy++) {
7049
7050 /* Copy pressure profile... */
7051 for (int ip = 0; ip < met->np; ip++)
7052 p[ip] = met->pl[ix][iy][ip];
7053
7054 /* Interpolate... */
7055 for (int ip = 0; ip < ctl->met_np; ip++) {
7056 double pt = ctl->met_p[ip];
7057 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
7058 pt = p[0];
7059 else if ((pt > p[met->np - 1] && p[1] > p[0])
7060 || (pt < p[met->np - 1] && p[1] < p[0]))
7061 pt = p[met->np - 1];
7062 int ip2 = locate_irr(p, met->np, pt);
7063 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
7064 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
7065 }
7066
7067 /* Copy data... */
7068 for (int ip = 0; ip < ctl->met_np; ip++)
7069 var[ix][iy][ip] = (float) aux[ip];
7070 }
7071}
7072
7073/*****************************************************************************/
7074
7076 met_t *met) {
7077
7078 /* Set timer... */
7079 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
7080 LOG(2, "Make zeta profiles monotone...");
7081
7082 /* Create monotone zeta profiles... */
7083#pragma omp parallel for default(shared) collapse(2)
7084 for (int i = 0; i < met->nx; i++)
7085 for (int j = 0; j < met->ny; j++) {
7086 int k = 1;
7087
7088 while (k < met->npl) { /* Check if there is an inversion at level k... */
7089 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
7090 /* Find the upper level k+l over the inversion... */
7091 int l = 0;
7092 do {
7093 l++;
7094 }
7095 while ((met->zetal[i][j][k - 1] >=
7096 met->zetal[i][j][k + l]) & (k + l < met->npl));
7097
7098 /* Interpolate linear between the top and bottom
7099 of the inversion... */
7100 float s =
7101 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
7102 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
7103
7104 for (int m = k; m < k + l; m++) {
7105 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
7106 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
7107 }
7108
7109 /* Search for more inversions above the last inversion ... */
7110 k = k + l;
7111 } else {
7112 k++;
7113 }
7114 }
7115 }
7116
7117 /* Create monotone pressure profiles... */
7118#pragma omp parallel for default(shared) collapse(2)
7119 for (int i = 0; i < met->nx; i++)
7120 for (int j = 0; j < met->ny; j++) {
7121 int k = 1;
7122
7123 while (k < met->npl) { /* Check if there is an inversion at level k... */
7124 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
7125
7126 /* Find the upper level k+l over the inversion... */
7127 int l = 0;
7128 do {
7129 l++;
7130 }
7131 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
7132 met->npl));
7133
7134 /* Interpolate linear between the top and bottom
7135 of the inversion... */
7136 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
7137 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
7138
7139 for (int m = k; m < k + l; m++) {
7140 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
7141 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
7142 }
7143
7144 /* Search for more inversions above the last inversion ... */
7145 k += l;
7146 } else {
7147 k++;
7148 }
7149 }
7150 }
7151}
7152
7153/*****************************************************************************/
7154
7156 const char *filename,
7157 const ctl_t *ctl,
7158 const clim_t *clim,
7159 met_t *met) {
7160
7161 int ncid;
7162
7163 /* Open netCDF file... */
7164 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7165 WARN("Cannot open file!");
7166 return 0;
7167 }
7168
7169 /* Read coordinates of meteo data... */
7170 read_met_grid(filename, ncid, ctl, met);
7171
7172 /* Read meteo data on vertical levels... */
7173 read_met_levels(ncid, ctl, met);
7174
7175 /* Extrapolate data for lower boundary... */
7177
7178 /* Read surface data... */
7179 read_met_surface(ncid, ctl, met);
7180
7181 /* Fix polar winds... */
7183
7184 /* Create periodic boundary conditions... */
7185 read_met_periodic(met);
7186
7187 /* Downsampling... */
7188 read_met_sample(ctl, met);
7189
7190 /* Calculate geopotential heights... */
7191 read_met_geopot(ctl, met);
7192
7193 /* Calculate potential vorticity... */
7194 read_met_pv(met);
7195
7196 /* Calculate boundary layer data... */
7197 read_met_pbl(ctl, met);
7198
7199 /* Calculate tropopause data... */
7200 read_met_tropo(ctl, clim, met);
7201
7202 /* Calculate cloud properties... */
7203 read_met_cloud(met);
7204
7205 /* Calculate convective available potential energy... */
7206 read_met_cape(ctl, clim, met);
7207
7208 /* Calculate total column ozone... */
7209 read_met_ozone(met);
7210
7211 /* Detrending... */
7212 read_met_detrend(ctl, met);
7213
7214 /* Check meteo data and smooth zeta profiles ... */
7215 if (ctl->advect_vert_coord == 1)
7217
7218 /* Close file... */
7219 NC(nc_close(ncid));
7220
7221 /* Return success... */
7222 return 1;
7223}
7224
7225/*****************************************************************************/
7226
7228 const int ncid,
7229 const char *varname,
7230 const char *varname2,
7231 const char *varname3,
7232 const char *varname4,
7233 const char *varname5,
7234 const char *varname6,
7235 const ctl_t *ctl,
7236 const met_t *met,
7237 float dest[EX][EY],
7238 const float scl,
7239 const int init) {
7240
7241 char varsel[LEN];
7242
7243 float offset, scalfac;
7244
7245 int varid;
7246
7247 /* Check if variable exists... */
7248 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7249 sprintf(varsel, "%s", varname);
7250 else if (varname2 != NULL
7251 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7252 sprintf(varsel, "%s", varname2);
7253 else if (varname3 != NULL
7254 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7255 sprintf(varsel, "%s", varname3);
7256 else if (varname4 != NULL
7257 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7258 sprintf(varsel, "%s", varname4);
7259 else if (varname5 != NULL
7260 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
7261 sprintf(varsel, "%s", varname5);
7262 else if (varname6 != NULL
7263 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
7264 sprintf(varsel, "%s", varname6);
7265 else
7266 return 0;
7267
7268 /* Read packed data... */
7269 if (ctl->met_nc_scale
7270 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
7271 && nc_get_att_float(ncid, varid, "scale_factor",
7272 &scalfac) == NC_NOERR) {
7273
7274 /* Allocate... */
7275 short *help;
7276 ALLOC(help, short,
7277 EX * EY * EP);
7278
7279 /* Read fill value and missing value... */
7280 short fillval, missval;
7281 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7282 fillval = 0;
7283 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
7284 missval = 0;
7285
7286 /* Write info... */
7287 LOG(2, "Read 2-D variable: %s"
7288 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
7289 varsel, fillval, missval, scalfac, offset);
7290
7291 /* Read data... */
7292 NC(nc_get_var_short(ncid, varid, help));
7293
7294 /* Check meteo data layout... */
7295 if (ctl->met_convention != 0)
7296 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
7297
7298 /* Copy and check data... */
7299#pragma omp parallel for default(shared) num_threads(12)
7300 for (int ix = 0; ix < met->nx; ix++)
7301 for (int iy = 0; iy < met->ny; iy++) {
7302 if (init)
7303 dest[ix][iy] = 0;
7304 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
7305 if ((fillval == 0 || aux != fillval)
7306 && (missval == 0 || aux != missval)
7307 && fabsf(aux * scalfac + offset) < 1e14f)
7308 dest[ix][iy] += scl * (aux * scalfac + offset);
7309 else
7310 dest[ix][iy] = NAN;
7311 }
7312
7313 /* Free... */
7314 free(help);
7315 }
7316
7317 /* Unpacked data... */
7318 else {
7319
7320 /* Allocate... */
7321 float *help;
7322 ALLOC(help, float,
7323 EX * EY);
7324
7325 /* Read fill value and missing value... */
7326 float fillval, missval;
7327 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7328 fillval = 0;
7329 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7330 missval = 0;
7331
7332 /* Write info... */
7333 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
7334 varsel, fillval, missval);
7335
7336 /* Read data... */
7337 NC(nc_get_var_float(ncid, varid, help));
7338
7339 /* Check meteo data layout... */
7340 if (ctl->met_convention == 0) {
7341
7342 /* Copy and check data (ordering: lat, lon)... */
7343#pragma omp parallel for default(shared) num_threads(12)
7344 for (int ix = 0; ix < met->nx; ix++)
7345 for (int iy = 0; iy < met->ny; iy++) {
7346 if (init)
7347 dest[ix][iy] = 0;
7348 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
7349 if ((fillval == 0 || aux != fillval)
7350 && (missval == 0 || aux != missval)
7351 && fabsf(aux) < 1e14f)
7352 dest[ix][iy] += scl * aux;
7353 else
7354 dest[ix][iy] = NAN;
7355 }
7356
7357 } else {
7358
7359 /* Copy and check data (ordering: lon, lat)... */
7360#pragma omp parallel for default(shared) num_threads(12)
7361 for (int iy = 0; iy < met->ny; iy++)
7362 for (int ix = 0; ix < met->nx; ix++) {
7363 if (init)
7364 dest[ix][iy] = 0;
7365 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
7366 if ((fillval == 0 || aux != fillval)
7367 && (missval == 0 || aux != missval)
7368 && fabsf(aux) < 1e14f)
7369 dest[ix][iy] += scl * aux;
7370 else
7371 dest[ix][iy] = NAN;
7372 }
7373 }
7374
7375 /* Free... */
7376 free(help);
7377 }
7378
7379 /* Return... */
7380 return 1;
7381}
7382
7383/*****************************************************************************/
7384
7386 const int ncid,
7387 const char *varname,
7388 const char *varname2,
7389 const char *varname3,
7390 const char *varname4,
7391 const ctl_t *ctl,
7392 const met_t *met,
7393 float dest[EX][EY][EP],
7394 const float scl) {
7395
7396 char varsel[LEN];
7397
7398 float offset, scalfac;
7399
7400 int varid;
7401
7402 /* Check if variable exists... */
7403 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7404 sprintf(varsel, "%s", varname);
7405 else if (varname2 != NULL
7406 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7407 sprintf(varsel, "%s", varname2);
7408 else if (varname3 != NULL
7409 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7410 sprintf(varsel, "%s", varname3);
7411 else if (varname4 != NULL
7412 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7413 sprintf(varsel, "%s", varname4);
7414 else
7415 return 0;
7416
7417 /* Read packed data... */
7418 if (ctl->met_nc_scale
7419 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
7420 && nc_get_att_float(ncid, varid, "scale_factor",
7421 &scalfac) == NC_NOERR) {
7422
7423 /* Allocate... */
7424 short *help;
7425 ALLOC(help, short,
7426 EX * EY * EP);
7427
7428 /* Read fill value and missing value... */
7429 short fillval, missval;
7430 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7431 fillval = 0;
7432 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
7433 missval = 0;
7434
7435 /* Write info... */
7436 LOG(2, "Read 3-D variable: %s "
7437 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
7438 varsel, fillval, missval, scalfac, offset);
7439
7440 /* Read data... */
7441 NC(nc_get_var_short(ncid, varid, help));
7442
7443 /* Check meteo data layout... */
7444 if (ctl->met_convention != 0)
7445 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
7446
7447 /* Copy and check data... */
7448#pragma omp parallel for default(shared) num_threads(12)
7449 for (int ix = 0; ix < met->nx; ix++)
7450 for (int iy = 0; iy < met->ny; iy++)
7451 for (int ip = 0; ip < met->np; ip++) {
7452 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7453 if ((fillval == 0 || aux != fillval)
7454 && (missval == 0 || aux != missval)
7455 && fabsf(aux * scalfac + offset) < 1e14f)
7456 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
7457 else
7458 dest[ix][iy][ip] = NAN;
7459 }
7460
7461 /* Free... */
7462 free(help);
7463 }
7464
7465 /* Unpacked data... */
7466 else {
7467
7468 /* Allocate... */
7469 float *help;
7470 ALLOC(help, float,
7471 EX * EY * EP);
7472
7473 /* Read fill value and missing value... */
7474 float fillval, missval;
7475 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7476 fillval = 0;
7477 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7478 missval = 0;
7479
7480 /* Write info... */
7481 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
7482 varsel, fillval, missval);
7483
7484 /* Read data... */
7485 NC(nc_get_var_float(ncid, varid, help));
7486
7487 /* Check meteo data layout... */
7488 if (ctl->met_convention == 0) {
7489
7490 /* Copy and check data (ordering: lev, lat, lon)... */
7491#pragma omp parallel for default(shared) num_threads(12)
7492 for (int ix = 0; ix < met->nx; ix++)
7493 for (int iy = 0; iy < met->ny; iy++)
7494 for (int ip = 0; ip < met->np; ip++) {
7495 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7496 if ((fillval == 0 || aux != fillval)
7497 && (missval == 0 || aux != missval)
7498 && fabsf(aux) < 1e14f)
7499 dest[ix][iy][ip] = scl * aux;
7500 else
7501 dest[ix][iy][ip] = NAN;
7502 }
7503
7504 } else {
7505
7506 /* Copy and check data (ordering: lon, lat, lev)... */
7507#pragma omp parallel for default(shared) num_threads(12)
7508 for (int ip = 0; ip < met->np; ip++)
7509 for (int iy = 0; iy < met->ny; iy++)
7510 for (int ix = 0; ix < met->nx; ix++) {
7511 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7512 if ((fillval == 0 || aux != fillval)
7513 && (missval == 0 || aux != missval)
7514 && fabsf(aux) < 1e14f)
7515 dest[ix][iy][ip] = scl * aux;
7516 else
7517 dest[ix][iy][ip] = NAN;
7518 }
7519 }
7520
7521 /* Free... */
7522 free(help);
7523 }
7524
7525 /* Return... */
7526 return 1;
7527}
7528
7529/*****************************************************************************/
7530
7532 const ctl_t *ctl,
7533 met_t *met) {
7534
7535 /* Set timer... */
7536 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
7537 LOG(2, "Calculate planetary boundary layer...");
7538
7539 /* Convert PBL height from meteo file to pressure... */
7540 if (ctl->met_pbl == 1) {
7541
7542 /* Loop over grid points... */
7543#pragma omp parallel for default(shared) collapse(2)
7544 for (int ix = 0; ix < met->nx; ix++)
7545 for (int iy = 0; iy < met->ny; iy++) {
7546
7547 /* Get pressure at top of PBL... */
7548 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
7549 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
7550 met->pbl[ix][iy] =
7551 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
7552 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
7553 }
7554 }
7555
7556 /* Determine PBL based on Richardson number... */
7557 else if (ctl->met_pbl == 2) {
7558
7559 /* Parameters used to estimate the height of the PBL
7560 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
7561 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
7562
7563 /* Loop over grid points... */
7564#pragma omp parallel for default(shared) collapse(2)
7565 for (int ix = 0; ix < met->nx; ix++)
7566 for (int iy = 0; iy < met->ny; iy++) {
7567
7568 /* Set bottom level of PBL... */
7569 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
7570
7571 /* Find lowest level near the bottom... */
7572 int ip;
7573 for (ip = 1; ip < met->np; ip++)
7574 if (met->p[ip] < pbl_bot)
7575 break;
7576
7577 /* Get near surface data... */
7578 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
7579 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
7580 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
7581
7582 /* Init... */
7583 double rib_old = 0;
7584
7585 /* Loop over levels... */
7586 for (; ip < met->np; ip++) {
7587
7588 /* Get squared horizontal wind speed... */
7589 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
7590 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
7591 vh2 = MAX(vh2, SQR(umin));
7592
7593 /* Calculate bulk Richardson number... */
7594 const double rib =
7595 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
7596 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
7597 met->h2o[ix][iy][ip]) - tvs) / vh2;
7598
7599 /* Check for critical value... */
7600 if (rib >= rib_crit) {
7601 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
7602 rib, met->p[ip], rib_crit));
7603 if (met->pbl[ix][iy] > pbl_bot)
7604 met->pbl[ix][iy] = (float) pbl_bot;
7605 break;
7606 }
7607
7608 /* Save Richardson number... */
7609 rib_old = rib;
7610 }
7611 }
7612 }
7613
7614 /* Determine PBL based on potential temperature... */
7615 if (ctl->met_pbl == 3) {
7616
7617 /* Parameters used to estimate the height of the PBL
7618 (following HYSPLIT model)... */
7619 const double dtheta = 2.0, zmin = 0.1;
7620
7621 /* Loop over grid points... */
7622#pragma omp parallel for default(shared) collapse(2)
7623 for (int ix = 0; ix < met->nx; ix++)
7624 for (int iy = 0; iy < met->ny; iy++) {
7625
7626 /* Potential temperature at the surface... */
7627 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
7628
7629 /* Find topmost level where theta exceeds surface value by 2 K... */
7630 int ip;
7631 for (ip = met->np - 2; ip > 0; ip--)
7632 if (met->p[ip] >= 300.)
7633 if (met->p[ip] > met->ps[ix][iy]
7634 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
7635 break;
7636
7637 /* Interpolate... */
7638 met->pbl[ix][iy]
7639 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
7640 met->p[ip + 1],
7641 THETA(met->p[ip], met->t[ix][iy][ip]),
7642 met->p[ip], theta0 + dtheta));
7643
7644 /* Check minimum value... */
7645 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
7646 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
7647 met->pbl[ix][iy] = (float) pbl_min;
7648 }
7649 }
7650
7651 /* Loop over grid points... */
7652#pragma omp parallel for default(shared) collapse(2)
7653 for (int ix = 0; ix < met->nx; ix++)
7654 for (int iy = 0; iy < met->ny; iy++) {
7655
7656 /* Check minimum value... */
7657 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
7658 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
7659
7660 /* Check maximum value... */
7661 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
7662 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
7663 }
7664}
7665
7666/*****************************************************************************/
7667
7669 met_t *met) {
7670
7671 /* Set timer... */
7672 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
7673 LOG(2, "Apply periodic boundary conditions...");
7674
7675 /* Check longitudes... */
7676 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
7677 + met->lon[1] - met->lon[0] - 360) < 0.01))
7678 return;
7679
7680 /* Increase longitude counter... */
7681 if ((++met->nx) >= EX)
7682 ERRMSG("Cannot create periodic boundary conditions!");
7683
7684 /* Set longitude... */
7685 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
7686
7687 /* Loop over latitudes and pressure levels... */
7688#pragma omp parallel for default(shared)
7689 for (int iy = 0; iy < met->ny; iy++) {
7690 met->ps[met->nx - 1][iy] = met->ps[0][iy];
7691 met->zs[met->nx - 1][iy] = met->zs[0][iy];
7692 met->ts[met->nx - 1][iy] = met->ts[0][iy];
7693 met->us[met->nx - 1][iy] = met->us[0][iy];
7694 met->vs[met->nx - 1][iy] = met->vs[0][iy];
7695 met->ess[met->nx - 1][iy] = met->ess[0][iy];
7696 met->nss[met->nx - 1][iy] = met->nss[0][iy];
7697 met->shf[met->nx - 1][iy] = met->shf[0][iy];
7698 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
7699 met->sst[met->nx - 1][iy] = met->sst[0][iy];
7700 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
7701 met->cape[met->nx - 1][iy] = met->cape[0][iy];
7702 met->cin[met->nx - 1][iy] = met->cin[0][iy];
7703 for (int ip = 0; ip < met->np; ip++) {
7704 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
7705 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
7706 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
7707 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
7708 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
7709 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
7710 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
7711 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
7712 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
7713 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
7714 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
7715 }
7716 for (int ip = 0; ip < met->npl; ip++) {
7717 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
7718 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
7719 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
7720 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
7721 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
7722 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
7723 }
7724 }
7725}
7726
7727/*****************************************************************************/
7728
7730 met_t *met) {
7731
7732 /* Set timer... */
7733 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
7734 LOG(2, "Apply fix for polar winds...");
7735
7736 /* Check latitudes... */
7737 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
7738 return;
7739
7740 /* Loop over hemispheres... */
7741 for (int ihem = 0; ihem < 2; ihem++) {
7742
7743 /* Set latitude indices... */
7744 int i89 = 1, i90 = 0, sign = 1;
7745 if (ihem == 1) {
7746 i89 = met->ny - 2;
7747 i90 = met->ny - 1;
7748 }
7749 if (met->lat[i90] < 0)
7750 sign = -1;
7751
7752 /* Look-up table of cosinus and sinus... */
7753 double clon[EX], slon[EX];
7754#pragma omp parallel for default(shared)
7755 for (int ix = 0; ix < met->nx; ix++) {
7756 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
7757 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
7758 }
7759
7760 /* Loop over levels... */
7761#pragma omp parallel for default(shared)
7762 for (int ip = 0; ip < met->np; ip++) {
7763
7764 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
7765 double vel89x = 0, vel89y = 0;
7766 for (int ix = 0; ix < met->nx; ix++) {
7767 vel89x +=
7768 (met->u[ix][i89][ip] * clon[ix] -
7769 met->v[ix][i89][ip] * slon[ix]) / met->nx;
7770 vel89y +=
7771 (met->u[ix][i89][ip] * slon[ix] +
7772 met->v[ix][i89][ip] * clon[ix]) / met->nx;
7773 }
7774
7775 /* Replace 90 degree winds by 89 degree mean... */
7776 for (int ix = 0; ix < met->nx; ix++) {
7777 met->u[ix][i90][ip]
7778 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
7779 met->v[ix][i90][ip]
7780 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
7781 }
7782 }
7783 }
7784}
7785
7786/*****************************************************************************/
7787
7789 met_t *met) {
7790
7791 double pows[EP];
7792
7793 /* Set timer... */
7794 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
7795 LOG(2, "Calculate potential vorticity...");
7796
7797 /* Set powers... */
7798#pragma omp parallel for default(shared)
7799 for (int ip = 0; ip < met->np; ip++)
7800 pows[ip] = pow(1000. / met->p[ip], 0.286);
7801
7802 /* Loop over grid points... */
7803#pragma omp parallel for default(shared)
7804 for (int ix = 0; ix < met->nx; ix++) {
7805
7806 /* Set indices... */
7807 const int ix0 = MAX(ix - 1, 0);
7808 const int ix1 = MIN(ix + 1, met->nx - 1);
7809
7810 /* Loop over grid points... */
7811 for (int iy = 0; iy < met->ny; iy++) {
7812
7813 /* Set indices... */
7814 const int iy0 = MAX(iy - 1, 0);
7815 const int iy1 = MIN(iy + 1, met->ny - 1);
7816
7817 /* Set auxiliary variables... */
7818 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
7819 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
7820 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
7821 const double c0 = cos(DEG2RAD(met->lat[iy0]));
7822 const double c1 = cos(DEG2RAD(met->lat[iy1]));
7823 const double cr = cos(DEG2RAD(latr));
7824 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
7825
7826 /* Loop over grid points... */
7827 for (int ip = 0; ip < met->np; ip++) {
7828
7829 /* Get gradients in longitude... */
7830 const double dtdx
7831 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
7832 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
7833
7834 /* Get gradients in latitude... */
7835 const double dtdy
7836 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
7837 const double dudy
7838 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
7839
7840 /* Set indices... */
7841 const int ip0 = MAX(ip - 1, 0);
7842 const int ip1 = MIN(ip + 1, met->np - 1);
7843
7844 /* Get gradients in pressure... */
7845 double dtdp, dudp, dvdp;
7846 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
7847 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
7848 if (ip != ip0 && ip != ip1) {
7849 double denom = dp0 * dp1 * (dp0 + dp1);
7850 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
7851 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
7852 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
7853 / denom;
7854 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
7855 - dp1 * dp1 * met->u[ix][iy][ip0]
7856 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
7857 / denom;
7858 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
7859 - dp1 * dp1 * met->v[ix][iy][ip0]
7860 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
7861 / denom;
7862 } else {
7863 const double denom = dp0 + dp1;
7864 dtdp =
7865 (met->t[ix][iy][ip1] * pows[ip1] -
7866 met->t[ix][iy][ip0] * pows[ip0]) / denom;
7867 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
7868 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
7869 }
7870
7871 /* Calculate PV... */
7872 met->pv[ix][iy][ip] = (float)
7873 (1e6 * G0 *
7874 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
7875 }
7876 }
7877 }
7878
7879 /* Fix for polar regions... */
7880#pragma omp parallel for default(shared)
7881 for (int ix = 0; ix < met->nx; ix++)
7882 for (int ip = 0; ip < met->np; ip++) {
7883 met->pv[ix][0][ip]
7884 = met->pv[ix][1][ip]
7885 = met->pv[ix][2][ip];
7886 met->pv[ix][met->ny - 1][ip]
7887 = met->pv[ix][met->ny - 2][ip]
7888 = met->pv[ix][met->ny - 3][ip];
7889 }
7890}
7891
7892/*****************************************************************************/
7893
7895 met_t *met) {
7896
7897 /* Set timer... */
7898 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
7899 LOG(2, "Calculate total column ozone...");
7900
7901 /* Loop over columns... */
7902#pragma omp parallel for default(shared) collapse(2)
7903 for (int ix = 0; ix < met->nx; ix++)
7904 for (int iy = 0; iy < met->ny; iy++) {
7905
7906 /* Integrate... */
7907 double cd = 0;
7908 for (int ip = 1; ip < met->np; ip++)
7909 if (met->p[ip - 1] <= met->ps[ix][iy]) {
7910 const double vmr =
7911 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
7912 const double dp = met->p[ip - 1] - met->p[ip];
7913 cd += vmr * MO3 / MA * dp * 1e2 / G0;
7914 }
7915
7916 /* Convert to Dobson units... */
7917 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
7918 }
7919}
7920
7921/*****************************************************************************/
7922
7924 const ctl_t *ctl,
7925 met_t *met) {
7926
7927 met_t *help;
7928
7929 /* Check parameters... */
7930 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
7931 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
7932 return;
7933
7934 /* Set timer... */
7935 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
7936 LOG(2, "Downsampling of meteo data...");
7937
7938 /* Allocate... */
7939 ALLOC(help, met_t, 1);
7940
7941 /* Copy data... */
7942 help->nx = met->nx;
7943 help->ny = met->ny;
7944 help->np = met->np;
7945 memcpy(help->lon, met->lon, sizeof(met->lon));
7946 memcpy(help->lat, met->lat, sizeof(met->lat));
7947 memcpy(help->p, met->p, sizeof(met->p));
7948
7949 /* Smoothing... */
7950 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
7951 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
7952 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
7953 help->ps[ix][iy] = 0;
7954 help->zs[ix][iy] = 0;
7955 help->ts[ix][iy] = 0;
7956 help->us[ix][iy] = 0;
7957 help->vs[ix][iy] = 0;
7958 help->ess[ix][iy] = 0;
7959 help->nss[ix][iy] = 0;
7960 help->shf[ix][iy] = 0;
7961 help->lsm[ix][iy] = 0;
7962 help->sst[ix][iy] = 0;
7963 help->pbl[ix][iy] = 0;
7964 help->cape[ix][iy] = 0;
7965 help->cin[ix][iy] = 0;
7966 help->t[ix][iy][ip] = 0;
7967 help->u[ix][iy][ip] = 0;
7968 help->v[ix][iy][ip] = 0;
7969 help->w[ix][iy][ip] = 0;
7970 help->h2o[ix][iy][ip] = 0;
7971 help->o3[ix][iy][ip] = 0;
7972 help->lwc[ix][iy][ip] = 0;
7973 help->rwc[ix][iy][ip] = 0;
7974 help->iwc[ix][iy][ip] = 0;
7975 help->swc[ix][iy][ip] = 0;
7976 help->cc[ix][iy][ip] = 0;
7977 float wsum = 0;
7978 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
7979 ix2++) {
7980 int ix3 = ix2;
7981 if (ix3 < 0)
7982 ix3 += met->nx;
7983 else if (ix3 >= met->nx)
7984 ix3 -= met->nx;
7985
7986 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
7987 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
7988 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
7989 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
7990 float w = (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
7991 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
7992 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
7993 help->ps[ix][iy] += w * met->ps[ix3][iy2];
7994 help->zs[ix][iy] += w * met->zs[ix3][iy2];
7995 help->ts[ix][iy] += w * met->ts[ix3][iy2];
7996 help->us[ix][iy] += w * met->us[ix3][iy2];
7997 help->vs[ix][iy] += w * met->vs[ix3][iy2];
7998 help->ess[ix][iy] += w * met->ess[ix3][iy2];
7999 help->nss[ix][iy] += w * met->nss[ix3][iy2];
8000 help->shf[ix][iy] += w * met->shf[ix3][iy2];
8001 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
8002 help->sst[ix][iy] += w * met->sst[ix3][iy2];
8003 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
8004 help->cape[ix][iy] += w * met->cape[ix3][iy2];
8005 help->cin[ix][iy] += w * met->cin[ix3][iy2];
8006 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
8007 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
8008 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
8009 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
8010 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
8011 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
8012 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
8013 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
8014 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
8015 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
8016 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
8017 wsum += w;
8018 }
8019 }
8020 help->ps[ix][iy] /= wsum;
8021 help->zs[ix][iy] /= wsum;
8022 help->ts[ix][iy] /= wsum;
8023 help->us[ix][iy] /= wsum;
8024 help->vs[ix][iy] /= wsum;
8025 help->ess[ix][iy] /= wsum;
8026 help->nss[ix][iy] /= wsum;
8027 help->shf[ix][iy] /= wsum;
8028 help->lsm[ix][iy] /= wsum;
8029 help->sst[ix][iy] /= wsum;
8030 help->pbl[ix][iy] /= wsum;
8031 help->cape[ix][iy] /= wsum;
8032 help->cin[ix][iy] /= wsum;
8033 help->t[ix][iy][ip] /= wsum;
8034 help->u[ix][iy][ip] /= wsum;
8035 help->v[ix][iy][ip] /= wsum;
8036 help->w[ix][iy][ip] /= wsum;
8037 help->h2o[ix][iy][ip] /= wsum;
8038 help->o3[ix][iy][ip] /= wsum;
8039 help->lwc[ix][iy][ip] /= wsum;
8040 help->rwc[ix][iy][ip] /= wsum;
8041 help->iwc[ix][iy][ip] /= wsum;
8042 help->swc[ix][iy][ip] /= wsum;
8043 help->cc[ix][iy][ip] /= wsum;
8044 }
8045 }
8046 }
8047
8048 /* Downsampling... */
8049 met->nx = 0;
8050 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
8051 met->lon[met->nx] = help->lon[ix];
8052 met->ny = 0;
8053 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
8054 met->lat[met->ny] = help->lat[iy];
8055 met->ps[met->nx][met->ny] = help->ps[ix][iy];
8056 met->zs[met->nx][met->ny] = help->zs[ix][iy];
8057 met->ts[met->nx][met->ny] = help->ts[ix][iy];
8058 met->us[met->nx][met->ny] = help->us[ix][iy];
8059 met->vs[met->nx][met->ny] = help->vs[ix][iy];
8060 met->ess[met->nx][met->ny] = help->ess[ix][iy];
8061 met->nss[met->nx][met->ny] = help->nss[ix][iy];
8062 met->shf[met->nx][met->ny] = help->shf[ix][iy];
8063 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
8064 met->sst[met->nx][met->ny] = help->sst[ix][iy];
8065 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
8066 met->cape[met->nx][met->ny] = help->cape[ix][iy];
8067 met->cin[met->nx][met->ny] = help->cin[ix][iy];
8068 met->np = 0;
8069 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
8070 met->p[met->np] = help->p[ip];
8071 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
8072 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
8073 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
8074 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
8075 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
8076 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
8077 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
8078 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
8079 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
8080 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
8081 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
8082 met->np++;
8083 }
8084 met->ny++;
8085 }
8086 met->nx++;
8087 }
8088
8089 /* Free... */
8090 free(help);
8091}
8092
8093/*****************************************************************************/
8094
8096 const int ncid,
8097 const ctl_t *ctl,
8098 met_t *met) {
8099
8100 /* Set timer... */
8101 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
8102 LOG(2, "Read surface data...");
8103
8104 /* Read surface pressure... */
8105 if (read_met_nc_2d
8106 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, met->ps, 1.0f,
8107 1)) {
8108 for (int ix = 0; ix < met->nx; ix++)
8109 for (int iy = 0; iy < met->ny; iy++)
8110 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8111 } else
8112 if (!read_met_nc_2d
8113 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, met->ps, 0.01f,
8114 1)) {
8115 WARN("Cannot not read surface pressure data (use lowest level)!");
8116 for (int ix = 0; ix < met->nx; ix++)
8117 for (int iy = 0; iy < met->ny; iy++)
8118 met->ps[ix][iy] = (float) met->p[0];
8119 }
8120
8121 /* MPTRAC meteo data... */
8122 if (ctl->met_clams == 0) {
8123
8124 /* Read geopotential height at the surface... */
8125 if (!read_met_nc_2d
8126 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, met->zs,
8127 (float) (1. / (1000. * G0)), 1))
8128 if (!read_met_nc_2d
8129 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, met->zs,
8130 (float) (1. / 1000.), 1))
8131 WARN("Cannot read surface geopotential height!");
8132 }
8133
8134 /* CLaMS meteo data... */
8135 else {
8136
8137 /* Read geopotential height at the surface
8138 (use lowermost level of 3-D data field)... */
8139 float *help;
8140 ALLOC(help, float,
8141 EX * EY * EP);
8142 memcpy(help, met->pl, sizeof(met->pl));
8143 if (!read_met_nc_3d
8144 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
8145 (float) (1e-3 / G0)))
8146 ERRMSG("Cannot read geopotential height!");
8147 for (int ix = 0; ix < met->nx; ix++)
8148 for (int iy = 0; iy < met->ny; iy++)
8149 met->zs[ix][iy] = met->pl[ix][iy][0];
8150 memcpy(met->pl, help, sizeof(met->pl));
8151 free(help);
8152 }
8153
8154 /* Read temperature at the surface... */
8155 if (!read_met_nc_2d
8156 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, met->ts, 1.0, 1))
8157 WARN("Cannot read surface temperature!");
8158
8159 /* Read zonal wind at the surface... */
8160 if (!read_met_nc_2d
8161 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, met->us,
8162 1.0, 1))
8163 WARN("Cannot read surface zonal wind!");
8164
8165 /* Read meridional wind at the surface... */
8166 if (!read_met_nc_2d
8167 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, met->vs,
8168 1.0, 1))
8169 WARN("Cannot read surface meridional wind!");
8170
8171 /* Read eastward turbulent surface stress... */
8172 if (!read_met_nc_2d
8173 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, met->ess, 1.0,
8174 1))
8175 WARN("Cannot read eastward turbulent surface stress!");
8176
8177 /* Read northward turbulent surface stress... */
8178 if (!read_met_nc_2d
8179 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, met->nss, 1.0,
8180 1))
8181 WARN("Cannot read nothward turbulent surface stress!");
8182
8183 /* Read surface sensible heat flux... */
8184 if (!read_met_nc_2d
8185 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, met->shf, 1.0,
8186 1))
8187 WARN("Cannot read surface sensible heat flux!");
8188
8189 /* Read land-sea mask... */
8190 if (!read_met_nc_2d
8191 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, met->lsm, 1.0,
8192 1))
8193 WARN("Cannot read land-sea mask!");
8194
8195 /* Read sea surface temperature... */
8196 if (!read_met_nc_2d
8197 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, met->sst,
8198 1.0, 1))
8199 WARN("Cannot read sea surface temperature!");
8200
8201 /* Read PBL... */
8202 if (ctl->met_pbl == 0)
8203 if (!read_met_nc_2d
8204 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
8205 0.01f, 1))
8206 WARN("Cannot read planetary boundary layer pressure!");
8207 if (ctl->met_pbl == 1)
8208 if (!read_met_nc_2d
8209 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
8210 0.001f, 1))
8211 WARN("Cannot read planetary boundary layer height!");
8212
8213 /* Read CAPE... */
8214 if (ctl->met_cape == 0)
8215 if (!read_met_nc_2d
8216 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, met->cape,
8217 1.0, 1))
8218 WARN("Cannot read CAPE!");
8219
8220 /* Read CIN... */
8221 if (ctl->met_cape == 0)
8222 if (!read_met_nc_2d
8223 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, met->cin,
8224 1.0, 1))
8225 WARN("Cannot read convective inhibition!");
8226}
8227
8228/*****************************************************************************/
8229
8231 const ctl_t *ctl,
8232 const clim_t *clim,
8233 met_t *met) {
8234
8235 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
8236 th2[200], z[EP], z2[200];
8237
8238 /* Set timer... */
8239 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
8240 LOG(2, "Calculate tropopause...");
8241
8242 /* Get altitude and pressure profiles... */
8243#pragma omp parallel for default(shared)
8244 for (int iz = 0; iz < met->np; iz++)
8245 z[iz] = Z(met->p[iz]);
8246#pragma omp parallel for default(shared)
8247 for (int iz = 0; iz <= 190; iz++) {
8248 z2[iz] = 4.5 + 0.1 * iz;
8249 p2[iz] = P(z2[iz]);
8250 }
8251
8252 /* Do not calculate tropopause... */
8253 if (ctl->met_tropo == 0)
8254#pragma omp parallel for default(shared) collapse(2)
8255 for (int ix = 0; ix < met->nx; ix++)
8256 for (int iy = 0; iy < met->ny; iy++)
8257 met->pt[ix][iy] = NAN;
8258
8259 /* Use tropopause climatology... */
8260 else if (ctl->met_tropo == 1) {
8261#pragma omp parallel for default(shared) collapse(2)
8262 for (int ix = 0; ix < met->nx; ix++)
8263 for (int iy = 0; iy < met->ny; iy++)
8264 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
8265 }
8266
8267 /* Use cold point... */
8268 else if (ctl->met_tropo == 2) {
8269
8270 /* Loop over grid points... */
8271#pragma omp parallel for default(shared) private(t,t2) collapse(2)
8272 for (int ix = 0; ix < met->nx; ix++)
8273 for (int iy = 0; iy < met->ny; iy++) {
8274
8275 /* Interpolate temperature profile... */
8276 for (int iz = 0; iz < met->np; iz++)
8277 t[iz] = met->t[ix][iy][iz];
8278 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
8279
8280 /* Find minimum... */
8281 int iz = (int) gsl_stats_min_index(t2, 1, 171);
8282 if (iz > 0 && iz < 170)
8283 met->pt[ix][iy] = (float) p2[iz];
8284 else
8285 met->pt[ix][iy] = NAN;
8286 }
8287 }
8288
8289 /* Use WMO definition... */
8290 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
8291
8292 /* Loop over grid points... */
8293#pragma omp parallel for default(shared) private(t,t2) collapse(2)
8294 for (int ix = 0; ix < met->nx; ix++)
8295 for (int iy = 0; iy < met->ny; iy++) {
8296
8297 /* Interpolate temperature profile... */
8298 int iz;
8299 for (iz = 0; iz < met->np; iz++)
8300 t[iz] = met->t[ix][iy][iz];
8301 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
8302
8303 /* Find 1st tropopause... */
8304 met->pt[ix][iy] = NAN;
8305 for (iz = 0; iz <= 170; iz++) {
8306 int found = 1;
8307 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
8308 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
8309 found = 0;
8310 break;
8311 }
8312 if (found) {
8313 if (iz > 0 && iz < 170)
8314 met->pt[ix][iy] = (float) p2[iz];
8315 break;
8316 }
8317 }
8318
8319 /* Find 2nd tropopause... */
8320 if (ctl->met_tropo == 4) {
8321 met->pt[ix][iy] = NAN;
8322 for (; iz <= 170; iz++) {
8323 int found = 1;
8324 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
8325 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
8326 found = 0;
8327 break;
8328 }
8329 if (found)
8330 break;
8331 }
8332 for (; iz <= 170; iz++) {
8333 int found = 1;
8334 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
8335 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
8336 found = 0;
8337 break;
8338 }
8339 if (found) {
8340 if (iz > 0 && iz < 170)
8341 met->pt[ix][iy] = (float) p2[iz];
8342 break;
8343 }
8344 }
8345 }
8346 }
8347 }
8348
8349 /* Use dynamical tropopause... */
8350 else if (ctl->met_tropo == 5) {
8351
8352 /* Loop over grid points... */
8353#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
8354 for (int ix = 0; ix < met->nx; ix++)
8355 for (int iy = 0; iy < met->ny; iy++) {
8356
8357 /* Interpolate potential vorticity profile... */
8358 for (int iz = 0; iz < met->np; iz++)
8359 pv[iz] = met->pv[ix][iy][iz];
8360 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
8361
8362 /* Interpolate potential temperature profile... */
8363 for (int iz = 0; iz < met->np; iz++)
8364 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
8365 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
8366
8367 /* Find dynamical tropopause... */
8368 met->pt[ix][iy] = NAN;
8369 for (int iz = 0; iz <= 170; iz++)
8370 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
8371 || th2[iz] >= ctl->met_tropo_theta) {
8372 if (iz > 0 && iz < 170)
8373 met->pt[ix][iy] = (float) p2[iz];
8374 break;
8375 }
8376 }
8377 }
8378
8379 else
8380 ERRMSG("Cannot calculate tropopause!");
8381
8382 /* Interpolate temperature, geopotential height, and water vapor... */
8383#pragma omp parallel for default(shared) collapse(2)
8384 for (int ix = 0; ix < met->nx; ix++)
8385 for (int iy = 0; iy < met->ny; iy++) {
8386 double h2ot, tt, zt;
8388 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
8389 met->lat[iy], &tt, ci, cw, 1);
8390 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
8391 met->lat[iy], &zt, ci, cw, 0);
8392 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
8393 met->lat[iy], &h2ot, ci, cw, 0);
8394 met->tt[ix][iy] = (float) tt;
8395 met->zt[ix][iy] = (float) zt;
8396 met->h2ot[ix][iy] = (float) h2ot;
8397 }
8398}
8399
8400/*****************************************************************************/
8401
8403 const char *filename,
8404 const ctl_t *ctl,
8405 double *rt,
8406 double *rz,
8407 double *rlon,
8408 double *rlat,
8409 double *robs,
8410 int *nobs) {
8411
8412 /* Write info... */
8413 LOG(1, "Read observation data: %s", filename);
8414
8415 /* Read data... */
8416 if (ctl->obs_type == 0)
8417 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
8418 else if (ctl->obs_type == 1)
8419 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
8420 else
8421 ERRMSG("Set OBS_TYPE to 0 or 1!");
8422
8423 /* Check time... */
8424 for (int i = 1; i < *nobs; i++)
8425 if (rt[i] < rt[i - 1])
8426 ERRMSG("Time must be ascending!");
8427
8428 /* Write info... */
8429 int n = *nobs;
8430 double mini, maxi;
8431 LOG(2, "Number of observations: %d", *nobs);
8432 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
8433 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8434 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
8435 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
8436 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
8437 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
8438 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
8439 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
8440 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
8441 LOG(2, "Observation range: %g ... %g", mini, maxi);
8442}
8443
8444/*****************************************************************************/
8445
8447 const char *filename,
8448 double *rt,
8449 double *rz,
8450 double *rlon,
8451 double *rlat,
8452 double *robs,
8453 int *nobs) {
8454
8455 /* Open observation data file... */
8456 FILE *in;
8457 if (!(in = fopen(filename, "r")))
8458 ERRMSG("Cannot open file!");
8459
8460 /* Read observations... */
8461 char line[LEN];
8462 while (fgets(line, LEN, in))
8463 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
8464 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
8465 if ((++(*nobs)) >= NOBS)
8466 ERRMSG("Too many observations!");
8467
8468 /* Close observation data file... */
8469 fclose(in);
8470}
8471
8472/*****************************************************************************/
8473
8475 const char *filename,
8476 double *rt,
8477 double *rz,
8478 double *rlon,
8479 double *rlat,
8480 double *robs,
8481 int *nobs) {
8482
8483 int ncid, varid;
8484
8485 /* Open netCDF file... */
8486 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8487 ERRMSG("Cannot open file!");
8488
8489 /* Read the observations from the NetCDF file... */
8490 NC_INQ_DIM("nobs", nobs, 1, NOBS);
8491 NC_GET_DOUBLE("time", rt, 1);
8492 NC_GET_DOUBLE("alt", rz, 1);
8493 NC_GET_DOUBLE("lon", rlon, 1);
8494 NC_GET_DOUBLE("lat", rlat, 1);
8495 NC_GET_DOUBLE("obs", robs, 1);
8496
8497 /* Close file... */
8498 NC(nc_close(ncid));
8499}
8500
8501/*****************************************************************************/
8502
8504 const char *filename,
8505 int argc,
8506 char *argv[],
8507 const char *varname,
8508 const int arridx,
8509 const char *defvalue,
8510 char *value) {
8511
8512 FILE *in = NULL;
8513
8514 char fullname1[LEN], fullname2[LEN], rval[LEN];
8515
8516 int contain = 0, i;
8517
8518 /* Open file... */
8519 if (filename[strlen(filename) - 1] != '-')
8520 if (!(in = fopen(filename, "r")))
8521 ERRMSG("Cannot open file!");
8522
8523 /* Set full variable name... */
8524 if (arridx >= 0) {
8525 sprintf(fullname1, "%s[%d]", varname, arridx);
8526 sprintf(fullname2, "%s[*]", varname);
8527 } else {
8528 sprintf(fullname1, "%s", varname);
8529 sprintf(fullname2, "%s", varname);
8530 }
8531
8532 /* Read data... */
8533 if (in != NULL) {
8534 char dummy[LEN], line[LEN], rvarname[LEN];
8535 while (fgets(line, LEN, in)) {
8536 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
8537 if (strcasecmp(rvarname, fullname1) == 0 ||
8538 strcasecmp(rvarname, fullname2) == 0) {
8539 contain = 1;
8540 break;
8541 }
8542 }
8543 }
8544 for (i = 1; i < argc - 1; i++)
8545 if (strcasecmp(argv[i], fullname1) == 0 ||
8546 strcasecmp(argv[i], fullname2) == 0) {
8547 sprintf(rval, "%s", argv[i + 1]);
8548 contain = 1;
8549 break;
8550 }
8551
8552 /* Close file... */
8553 if (in != NULL)
8554 fclose(in);
8555
8556 /* Check for missing variables... */
8557 if (!contain) {
8558 if (strlen(defvalue) > 0)
8559 sprintf(rval, "%s", defvalue);
8560 else
8561 ERRMSG("Missing variable %s!\n", fullname1);
8562 }
8563
8564 /* Write info... */
8565 LOG(1, "%s = %s", fullname1, rval);
8566
8567 /* Return values... */
8568 if (value != NULL)
8569 sprintf(value, "%s", rval);
8570 return atof(rval);
8571}
8572
8573/*****************************************************************************/
8574
8575double sedi(
8576 const double p,
8577 const double T,
8578 const double rp,
8579 const double rhop) {
8580
8581 /* Convert particle radius from microns to m... */
8582 const double rp_help = rp * 1e-6;
8583
8584 /* Density of dry air [kg / m^3]... */
8585 const double rho = RHO(p, T);
8586
8587 /* Dynamic viscosity of air [kg / (m s)]... */
8588 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
8589
8590 /* Thermal velocity of an air molecule [m / s]... */
8591 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
8592
8593 /* Mean free path of an air molecule [m]... */
8594 const double lambda = 2. * eta / (rho * v);
8595
8596 /* Knudsen number for air (dimensionless)... */
8597 const double K = lambda / rp_help;
8598
8599 /* Cunningham slip-flow correction (dimensionless)... */
8600 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
8601
8602 /* Sedimentation velocity [m / s]... */
8603 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
8604}
8605
8606/*****************************************************************************/
8607
8609 const double *x,
8610 const double *y,
8611 const int n,
8612 const double *x2,
8613 double *y2,
8614 const int n2,
8615 const int method) {
8616
8617 /* Cubic spline interpolation... */
8618 if (method == 1) {
8619
8620 /* Allocate... */
8621 gsl_interp_accel *acc = gsl_interp_accel_alloc();
8622 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
8623
8624 /* Interpolate profile... */
8625 gsl_spline_init(s, x, y, (size_t) n);
8626 for (int i = 0; i < n2; i++)
8627 if (x2[i] <= x[0])
8628 y2[i] = y[0];
8629 else if (x2[i] >= x[n - 1])
8630 y2[i] = y[n - 1];
8631 else
8632 y2[i] = gsl_spline_eval(s, x2[i], acc);
8633
8634 /* Free... */
8635 gsl_spline_free(s);
8636 gsl_interp_accel_free(acc);
8637 }
8638
8639 /* Linear interpolation... */
8640 else {
8641 for (int i = 0; i < n2; i++)
8642 if (x2[i] <= x[0])
8643 y2[i] = y[0];
8644 else if (x2[i] >= x[n - 1])
8645 y2[i] = y[n - 1];
8646 else {
8647 int idx = locate_irr(x, n, x2[i]);
8648 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
8649 }
8650 }
8651}
8652
8653/*****************************************************************************/
8654
8656 const float *data,
8657 const int n) {
8658
8659 if (n <= 0)
8660 return 0;
8661
8662 float mean = 0, var = 0;
8663
8664 for (int i = 0; i < n; ++i) {
8665 mean += data[i];
8666 var += SQR(data[i]);
8667 }
8668
8669 var = var / (float) n - SQR(mean / (float) n);
8670
8671 return (var > 0 ? sqrtf(var) : 0);
8672}
8673
8674/*****************************************************************************/
8675
8677 const double sec,
8678 const double lon,
8679 const double lat) {
8680
8681 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
8682 const double D = sec / 86400 - 0.5;
8683
8684 /* Geocentric apparent ecliptic longitude [rad]... */
8685 const double g = DEG2RAD(357.529 + 0.98560028 * D);
8686 const double q = 280.459 + 0.98564736 * D;
8687 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
8688
8689 /* Mean obliquity of the ecliptic [rad]... */
8690 const double e = DEG2RAD(23.439 - 0.00000036 * D);
8691
8692 /* Declination [rad]... */
8693 const double sindec = sin(e) * sin(L);
8694
8695 /* Right ascension [rad]... */
8696 const double ra = atan2(cos(e) * sin(L), cos(L));
8697
8698 /* Greenwich Mean Sidereal Time [h]... */
8699 const double GMST = 18.697374558 + 24.06570982441908 * D;
8700
8701 /* Local Sidereal Time [h]... */
8702 const double LST = GMST + lon / 15;
8703
8704 /* Hour angle [rad]... */
8705 const double h = LST / 12 * M_PI - ra;
8706
8707 /* Convert latitude... */
8708 const double lat_help = DEG2RAD(lat);
8709
8710 /* Return solar zenith angle [rad]... */
8711 return acos(sin(lat_help) * sindec +
8712 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
8713}
8714
8715/*****************************************************************************/
8716
8718 const int year,
8719 const int mon,
8720 const int day,
8721 const int hour,
8722 const int min,
8723 const int sec,
8724 const double remain,
8725 double *jsec) {
8726
8727 struct tm t0, t1;
8728
8729 t0.tm_year = 100;
8730 t0.tm_mon = 0;
8731 t0.tm_mday = 1;
8732 t0.tm_hour = 0;
8733 t0.tm_min = 0;
8734 t0.tm_sec = 0;
8735
8736 t1.tm_year = year - 1900;
8737 t1.tm_mon = mon - 1;
8738 t1.tm_mday = day;
8739 t1.tm_hour = hour;
8740 t1.tm_min = min;
8741 t1.tm_sec = sec;
8742
8743 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
8744}
8745
8746/*****************************************************************************/
8747
8749 const char *name,
8750 const char *group,
8751 const int output) {
8752
8753 static char names[NTIMER][100], groups[NTIMER][100];
8754
8755 static double rt_name[NTIMER], rt_group[NTIMER],
8756 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
8757
8758 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
8759
8760 /* Get time... */
8761 t1 = omp_get_wtime();
8762 dt = t1 - t0;
8763
8764 /* Add elapsed time to current timers... */
8765 if (iname >= 0) {
8766 rt_name[iname] += dt;
8767 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
8768 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
8769 ct_name[iname]++;
8770 }
8771 if (igroup >= 0)
8772 rt_group[igroup] += t1 - t0;
8773
8774 /* Report timers... */
8775 if (output) {
8776 for (int i = 0; i < nname; i++)
8777 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
8778 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
8779 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
8780 for (int i = 0; i < ngroup; i++)
8781 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
8782 double total = 0.0;
8783 for (int i = 0; i < nname; i++)
8784 total += rt_name[i];
8785 LOG(1, "TIMER_TOTAL = %.3f s", total);
8786 }
8787
8788 /* Identify IDs of next timer... */
8789 for (iname = 0; iname < nname; iname++)
8790 if (strcasecmp(name, names[iname]) == 0)
8791 break;
8792 for (igroup = 0; igroup < ngroup; igroup++)
8793 if (strcasecmp(group, groups[igroup]) == 0)
8794 break;
8795
8796 /* Check whether this is a new timer... */
8797 if (iname >= nname) {
8798 sprintf(names[iname], "%s", name);
8799 if ((++nname) >= NTIMER)
8800 ERRMSG("Too many timers!");
8801 }
8802
8803 /* Check whether this is a new group... */
8804 if (igroup >= ngroup) {
8805 sprintf(groups[igroup], "%s", group);
8806 if ((++ngroup) >= NTIMER)
8807 ERRMSG("Too many groups!");
8808 }
8809
8810 /* Save starting time... */
8811 t0 = t1;
8812}
8813
8814/*****************************************************************************/
8815
8817 const char *filename,
8818 const int offset) {
8819
8820 char tstr[10];
8821
8822 double t;
8823
8824 /* Get time from filename... */
8825 int len = (int) strlen(filename);
8826 sprintf(tstr, "%.4s", &filename[len - offset]);
8827 int year = atoi(tstr);
8828 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
8829 int mon = atoi(tstr);
8830 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
8831 int day = atoi(tstr);
8832 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
8833 int hour = atoi(tstr);
8834 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
8835 int min = atoi(tstr);
8836
8837 /* Check time... */
8838 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
8839 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
8840 ERRMSG("Cannot read time from filename!");
8841
8842 /* Convert time to Julian seconds... */
8843 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
8844
8845 /* Return time... */
8846 return t;
8847}
8848
8849/*****************************************************************************/
8850
8852 const clim_t *clim,
8853 const atm_t *atm,
8854 const int ip) {
8855
8856 /* Get tropopause pressure... */
8857 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
8858
8859 /* Get pressure range... */
8860 const double p1 = pt * 0.866877899;
8861 const double p0 = pt / 0.866877899;
8862
8863 /* Get weighting factor... */
8864 if (atm->p[ip] > p0)
8865 return 1;
8866 else if (atm->p[ip] < p1)
8867 return 0;
8868 else
8869 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
8870}
8871
8872/*****************************************************************************/
8873
8875 const char *filename,
8876 const ctl_t *ctl,
8877 const atm_t *atm,
8878 const double t) {
8879
8880 /* Set timer... */
8881 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
8882
8883 /* Write info... */
8884 LOG(1, "Write atmospheric data: %s", filename);
8885
8886 /* Write ASCII data... */
8887 if (ctl->atm_type_out == 0)
8888 write_atm_asc(filename, ctl, atm, t);
8889
8890 /* Write binary data... */
8891 else if (ctl->atm_type_out == 1)
8892 write_atm_bin(filename, ctl, atm);
8893
8894 /* Write netCDF data... */
8895 else if (ctl->atm_type_out == 2)
8896 write_atm_nc(filename, ctl, atm);
8897
8898 /* Write CLaMS trajectory data... */
8899 else if (ctl->atm_type_out == 3)
8900 write_atm_clams_traj(filename, ctl, atm, t);
8901
8902 /* Write CLaMS pos data... */
8903 else if (ctl->atm_type_out == 4)
8904 write_atm_clams(filename, ctl, atm);
8905
8906 /* Error... */
8907 else
8908 ERRMSG("Atmospheric data type not supported!");
8909
8910 /* Write info... */
8911 double mini, maxi;
8912 LOG(2, "Number of particles: %d", atm->np);
8913 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
8914 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8915 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
8916 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
8917 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
8918 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
8919 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
8920 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
8921 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
8922 for (int iq = 0; iq < ctl->nq; iq++) {
8923 char msg[5 * LEN];
8924 sprintf(msg, "Quantity %s range: %s ... %s %s",
8925 ctl->qnt_name[iq], ctl->qnt_format[iq],
8926 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
8927 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
8928 LOG(2, msg, mini, maxi);
8929 }
8930}
8931
8932/*****************************************************************************/
8933
8935 const char *filename,
8936 const ctl_t *ctl,
8937 const atm_t *atm,
8938 const double t) {
8939
8940 FILE *out;
8941
8942 /* Set time interval for output... */
8943 const double t0 = t - 0.5 * ctl->dt_mod;
8944 const double t1 = t + 0.5 * ctl->dt_mod;
8945
8946 /* Check if gnuplot output is requested... */
8947 if (ctl->atm_gpfile[0] != '-') {
8948
8949 /* Create gnuplot pipe... */
8950 if (!(out = popen("gnuplot", "w")))
8951 ERRMSG("Cannot create pipe to gnuplot!");
8952
8953 /* Set plot filename... */
8954 fprintf(out, "set out \"%s.png\"\n", filename);
8955
8956 /* Set time string... */
8957 double r;
8958 int year, mon, day, hour, min, sec;
8959 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
8960 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
8961 year, mon, day, hour, min);
8962
8963 /* Dump gnuplot file to pipe... */
8964 FILE *in;
8965 if (!(in = fopen(ctl->atm_gpfile, "r")))
8966 ERRMSG("Cannot open file!");
8967 char line[LEN];
8968 while (fgets(line, LEN, in))
8969 fprintf(out, "%s", line);
8970 fclose(in);
8971 }
8972
8973 else {
8974
8975 /* Create file... */
8976 if (!(out = fopen(filename, "w")))
8977 ERRMSG("Cannot create file!");
8978 }
8979
8980 /* Write header... */
8981 fprintf(out,
8982 "# $1 = time [s]\n"
8983 "# $2 = altitude [km]\n"
8984 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
8985 for (int iq = 0; iq < ctl->nq; iq++)
8986 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
8987 ctl->qnt_unit[iq]);
8988 fprintf(out, "\n");
8989
8990 /* Write data... */
8991 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
8992
8993 /* Check time... */
8994 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
8995 continue;
8996
8997 /* Write output... */
8998 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
8999 atm->lon[ip], atm->lat[ip]);
9000 for (int iq = 0; iq < ctl->nq; iq++) {
9001 fprintf(out, " ");
9002 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
9003 fprintf(out, ctl->qnt_format[iq], NAN);
9004 else
9005 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
9006 }
9007 fprintf(out, "\n");
9008 }
9009
9010 /* Close file... */
9011 fclose(out);
9012}
9013
9014/*****************************************************************************/
9015
9017 const char *filename,
9018 const ctl_t *ctl,
9019 const atm_t *atm) {
9020
9021 FILE *out;
9022
9023 /* Create file... */
9024 if (!(out = fopen(filename, "w")))
9025 ERRMSG("Cannot create file!");
9026
9027 /* Write version of binary data... */
9028 int version = 100;
9029 FWRITE(&version, int,
9030 1,
9031 out);
9032
9033 /* Write data... */
9034 FWRITE(&atm->np, int,
9035 1,
9036 out);
9037 FWRITE(atm->time, double,
9038 (size_t) atm->np,
9039 out);
9040 FWRITE(atm->p, double,
9041 (size_t) atm->np,
9042 out);
9043 FWRITE(atm->lon, double,
9044 (size_t) atm->np,
9045 out);
9046 FWRITE(atm->lat, double,
9047 (size_t) atm->np,
9048 out);
9049 for (int iq = 0; iq < ctl->nq; iq++)
9050 FWRITE(atm->q[iq], double,
9051 (size_t) atm->np,
9052 out);
9053
9054 /* Write final flag... */
9055 int final = 999;
9056 FWRITE(&final, int,
9057 1,
9058 out);
9059
9060 /* Close file... */
9061 fclose(out);
9062}
9063
9064/*****************************************************************************/
9065
9067 const char *filename,
9068 const ctl_t *ctl,
9069 const atm_t *atm) {
9070
9071 int tid, pid, ncid, varid;
9072 size_t start[2], count[2];
9073
9074 /* Create file... */
9075 nc_create(filename, NC_NETCDF4, &ncid);
9076
9077 /* Define dimensions... */
9078 NC(nc_def_dim(ncid, "time", 1, &tid));
9079 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9080
9081 /* Define variables and their attributes... */
9082 int dim_ids[2] = { tid, pid };
9083 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9084 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9085 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
9086 ctl->atm_nc_level, 0);
9087 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
9088 ctl->atm_nc_level, 0);
9089 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
9090 ctl->atm_nc_level, 0);
9091 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
9092 for (int iq = 0; iq < ctl->nq; iq++)
9093 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9094 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9095 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9096
9097 /* Define global attributes... */
9098 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9099 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9100
9101 /* End definitions... */
9102 NC(nc_enddef(ncid));
9103
9104 /* Write data... */
9105 NC_PUT_DOUBLE("time", atm->time, 0);
9106 NC_PUT_DOUBLE("LAT", atm->lat, 0);
9107 NC_PUT_DOUBLE("LON", atm->lon, 0);
9108 NC_PUT_DOUBLE("PRESS", atm->p, 0);
9109 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
9110 for (int iq = 0; iq < ctl->nq; iq++)
9111 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9112
9113 /* Close file... */
9114 NC(nc_close(ncid));
9115}
9116
9117/*****************************************************************************/
9118
9120 const char *dirname,
9121 const ctl_t *ctl,
9122 const atm_t *atm,
9123 const double t) {
9124
9125 /* Global Counter... */
9126 static size_t out_cnt = 0;
9127
9128 double r, r_start, r_stop;
9129 int year, mon, day, hour, min, sec;
9130 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
9131 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
9132 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
9133
9134 int ncid, varid, tid, pid, cid;
9135 int dim_ids[2];
9136
9137 /* time, nparc */
9138 size_t start[2];
9139 size_t count[2];
9140
9141 /* Determine start and stop times of calculation... */
9142 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9143 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
9144 &min_start, &sec_start, &r_start);
9145 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
9146 &min_stop, &sec_stop, &r_stop);
9147
9148 sprintf(filename_out, "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc",
9149 dirname,
9150 year_start % 100, mon_start, day_start, hour_start,
9151 year_stop % 100, mon_stop, day_stop, hour_stop);
9152 LOG(1, "Write traj file: %s", filename_out);
9153
9154 /* Define hyperslap for the traj_file... */
9155 start[0] = out_cnt;
9156 start[1] = 0;
9157 count[0] = 1;
9158 count[1] = (size_t) atm->np;
9159
9160 /* Create the file at the first timestep... */
9161 if (out_cnt == 0) {
9162
9163 /* Create file... */
9164 nc_create(filename_out, NC_NETCDF4, &ncid);
9165
9166 /* Define dimensions... */
9167 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
9168 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9169 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
9170 dim_ids[0] = tid;
9171 dim_ids[1] = pid;
9172
9173 /* Define variables and their attributes... */
9174 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9175 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9176 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
9177 ctl->atm_nc_level, 0);
9178 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
9179 ctl->atm_nc_level, 0);
9180 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
9181 ctl->atm_nc_level, 0);
9182 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
9183 ctl->atm_nc_level, 0);
9184 for (int iq = 0; iq < ctl->nq; iq++)
9185 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9186 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9187 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9188
9189 /* Define global attributes... */
9190 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9191 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9192
9193 /* End definitions... */
9194 NC(nc_enddef(ncid));
9195 NC(nc_close(ncid));
9196 }
9197
9198 /* Increment global counter to change hyperslap... */
9199 out_cnt++;
9200
9201 /* Open file... */
9202 NC(nc_open(filename_out, NC_WRITE, &ncid));
9203
9204 /* Write data... */
9205 NC_PUT_DOUBLE("time", atm->time, 1);
9206 NC_PUT_DOUBLE("LAT", atm->lat, 1);
9207 NC_PUT_DOUBLE("LON", atm->lon, 1);
9208 NC_PUT_DOUBLE("PRESS", atm->p, 1);
9209 if (ctl->advect_vert_coord == 1) {
9210 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
9211 } else if (ctl->qnt_zeta >= 0) {
9212 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
9213 }
9214 for (int iq = 0; iq < ctl->nq; iq++)
9215 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
9216
9217 /* Close file... */
9218 NC(nc_close(ncid));
9219
9220 /* At the last time step create the init_fix_YYYYMMDDHH file... */
9221 if ((year == year_stop) && (mon == mon_stop)
9222 && (day == day_stop) && (hour == hour_stop)) {
9223
9224 /* Set filename... */
9225 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
9226 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
9227 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
9228 LOG(1, "Write init file: %s", filename_init);
9229
9230 /* Create file... */
9231 nc_create(filename_init, NC_NETCDF4, &ncid);
9232
9233 /* Define dimensions... */
9234 NC(nc_def_dim(ncid, "time", 1, &tid));
9235 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9236 dim_ids[0] = tid;
9237 dim_ids[1] = pid;
9238
9239 /* Define variables and their attributes... */
9240 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9241 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9242 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
9243 ctl->atm_nc_level, 0);
9244 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
9245 ctl->atm_nc_level, 0);
9246 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
9247 ctl->atm_nc_level, 0);
9248 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
9249 for (int iq = 0; iq < ctl->nq; iq++)
9250 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9251 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9252 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9253
9254 /* Define global attributes... */
9255 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9256 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9257
9258 /* End definitions... */
9259 NC(nc_enddef(ncid));
9260
9261 /* Write data... */
9262 NC_PUT_DOUBLE("time", atm->time, 0);
9263 NC_PUT_DOUBLE("LAT", atm->lat, 0);
9264 NC_PUT_DOUBLE("LON", atm->lon, 0);
9265 NC_PUT_DOUBLE("PRESS", atm->p, 0);
9266 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
9267 for (int iq = 0; iq < ctl->nq; iq++)
9268 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9269
9270 /* Close file... */
9271 NC(nc_close(ncid));
9272 }
9273}
9274
9275/*****************************************************************************/
9276
9278 const char *filename,
9279 const ctl_t *ctl,
9280 const atm_t *atm) {
9281
9282 int ncid, obsid, varid;
9283
9284 size_t start[2], count[2];
9285
9286 /* Create file... */
9287 NC(nc_create(filename, NC_NETCDF4, &ncid));
9288
9289 /* Define dimensions... */
9290 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
9291
9292 /* Define variables and their attributes... */
9293 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
9294 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9295 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
9296 ctl->atm_nc_level, 0);
9297 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
9298 ctl->atm_nc_level, 0);
9299 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
9300 ctl->atm_nc_level, 0);
9301 for (int iq = 0; iq < ctl->nq; iq++)
9302 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
9303 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
9304 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9305
9306 /* Define global attributes... */
9307 NC_PUT_ATT_GLOBAL("featureType", "point");
9308
9309 /* End definitions... */
9310 NC(nc_enddef(ncid));
9311
9312 /* Write data... */
9313 NC_PUT_DOUBLE("time", atm->time, 0);
9314 NC_PUT_DOUBLE("press", atm->p, 0);
9315 NC_PUT_DOUBLE("lon", atm->lon, 0);
9316 NC_PUT_DOUBLE("lat", atm->lat, 0);
9317 for (int iq = 0; iq < ctl->nq; iq++)
9318 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9319
9320 /* Close file... */
9321 NC(nc_close(ncid));
9322}
9323
9324/*****************************************************************************/
9325
9327 const char *filename,
9328 const ctl_t *ctl,
9329 const atm_t *atm,
9330 const double t) {
9331
9332 static FILE *out;
9333
9334 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
9335 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
9336
9337 static int *obscount, ct, cx, cy, cz, ip, ix, iy, iz, n, nobs, nk;
9338
9339 /* Set timer... */
9340 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
9341
9342 /* Init... */
9343 if (t == ctl->t_start) {
9344
9345 /* Check quantity index for mass... */
9346 if (ctl->qnt_m < 0)
9347 ERRMSG("Need quantity mass!");
9348
9349 /* Allocate... */
9350 ALLOC(area, double,
9351 ctl->csi_ny);
9352 ALLOC(rt, double,
9353 NOBS);
9354 ALLOC(rz, double,
9355 NOBS);
9356 ALLOC(rlon, double,
9357 NOBS);
9358 ALLOC(rlat, double,
9359 NOBS);
9360 ALLOC(robs, double,
9361 NOBS);
9362
9363 /* Read observation data... */
9364 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
9365
9366 /* Read kernel data... */
9367 if (ctl->csi_kernel[0] != '-')
9368 read_kernel(ctl->csi_kernel, kz, kw, &nk);
9369
9370 /* Create new file... */
9371 LOG(1, "Write CSI data: %s", filename);
9372 if (!(out = fopen(filename, "w")))
9373 ERRMSG("Cannot create file!");
9374
9375 /* Write header... */
9376 fprintf(out,
9377 "# $1 = time [s]\n"
9378 "# $2 = number of hits (cx)\n"
9379 "# $3 = number of misses (cy)\n"
9380 "# $4 = number of false alarms (cz)\n"
9381 "# $5 = number of observations (cx + cy)\n"
9382 "# $6 = number of forecasts (cx + cz)\n"
9383 "# $7 = bias (ratio of forecasts and observations) [%%]\n"
9384 "# $8 = probability of detection (POD) [%%]\n"
9385 "# $9 = false alarm rate (FAR) [%%]\n"
9386 "# $10 = critical success index (CSI) [%%]\n");
9387 fprintf(out,
9388 "# $11 = hits associated with random chance\n"
9389 "# $12 = equitable threat score (ETS) [%%]\n"
9390 "# $13 = Pearson linear correlation coefficient\n"
9391 "# $14 = Spearman rank-order correlation coefficient\n"
9392 "# $15 = column density mean error (F - O) [kg/m^2]\n"
9393 "# $16 = column density root mean square error (RMSE) [kg/m^2]\n"
9394 "# $17 = column density mean absolute error [kg/m^2]\n"
9395 "# $18 = log-likelihood function\n"
9396 "# $19 = number of data points\n\n");
9397
9398 /* Set grid box size... */
9399 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
9400 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
9401 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
9402
9403 /* Set horizontal coordinates... */
9404 for (iy = 0; iy < ctl->csi_ny; iy++) {
9405 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
9406 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat));
9407 }
9408 }
9409
9410 /* Set time interval... */
9411 const double t0 = t - 0.5 * ctl->dt_mod;
9412 const double t1 = t + 0.5 * ctl->dt_mod;
9413
9414 /* Allocate... */
9415 ALLOC(modmean, double,
9416 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9417 ALLOC(obsmean, double,
9418 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9419 ALLOC(obscount, int,
9420 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9421 ALLOC(obsstd, double,
9422 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9423
9424 /* Loop over observations... */
9425 for (int i = 0; i < nobs; i++) {
9426
9427 /* Check time... */
9428 if (rt[i] < t0)
9429 continue;
9430 else if (rt[i] >= t1)
9431 break;
9432
9433 /* Check observation data... */
9434 if (!isfinite(robs[i]))
9435 continue;
9436
9437 /* Calculate indices... */
9438 ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
9439 iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
9440 iz = (int) ((rz[i] - ctl->csi_z0) / dz);
9441
9442 /* Check indices... */
9443 if (ix < 0 || ix >= ctl->csi_nx ||
9444 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9445 continue;
9446
9447 /* Get mean observation index... */
9448 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9449 obsmean[idx] += robs[i];
9450 obsstd[idx] += SQR(robs[i]);
9451 obscount[idx]++;
9452 }
9453
9454 /* Analyze model data... */
9455 for (ip = 0; ip < atm->np; ip++) {
9456
9457 /* Check time... */
9458 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9459 continue;
9460
9461 /* Get indices... */
9462 ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
9463 iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
9464 iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
9465
9466 /* Check indices... */
9467 if (ix < 0 || ix >= ctl->csi_nx ||
9468 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9469 continue;
9470
9471 /* Get total mass in grid cell... */
9472 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9473 modmean[idx] += kernel_weight(kz, kw, nk, atm->p[ip])
9474 * atm->q[ctl->qnt_m][ip];
9475 }
9476
9477 /* Analyze all grid cells... */
9478 for (ix = 0; ix < ctl->csi_nx; ix++)
9479 for (iy = 0; iy < ctl->csi_ny; iy++)
9480 for (iz = 0; iz < ctl->csi_nz; iz++) {
9481
9482 /* Calculate mean observation index... */
9483 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9484 if (obscount[idx] > 0) {
9485 obsmean[idx] /= obscount[idx];
9486 obsstd[idx] -= SQR(obsmean[idx]);
9487 obsstd[idx] = sqrt(obsstd[idx]);
9488 }
9489
9490 /* Calculate column density... */
9491 if (modmean[idx] > 0)
9492 modmean[idx] /= (1e6 * area[iy]);
9493
9494 /* Calculate CSI... */
9495 if (obscount[idx] > 0) {
9496 ct++;
9497 if (obsmean[idx] >= ctl->csi_obsmin &&
9498 modmean[idx] >= ctl->csi_modmin)
9499 cx++;
9500 else if (obsmean[idx] >= ctl->csi_obsmin &&
9501 modmean[idx] < ctl->csi_modmin)
9502 cy++;
9503 else if (obsmean[idx] < ctl->csi_obsmin &&
9504 modmean[idx] >= ctl->csi_modmin)
9505 cz++;
9506 }
9507
9508 /* Save data for other verification statistics... */
9509 if (obscount[idx] > 0
9510 && (obsmean[idx] >= ctl->csi_obsmin
9511 || modmean[idx] >= ctl->csi_modmin)) {
9512 x[n] = modmean[idx];
9513 y[n] = obsmean[idx];
9514 if (modmean[idx] >= ctl->csi_modmin)
9515 obsstdn[n] = obsstd[idx];
9516 if ((++n) >= NCSI)
9517 ERRMSG("Too many data points to calculate statistics!");
9518 }
9519 }
9520
9521 /* Write output... */
9522 if (fmod(t, ctl->csi_dt_out) == 0) {
9523
9524 /* Calculate verification statistics
9525 (https://www.cawcr.gov.au/projects/verification/) ... */
9526 static double work[2 * NCSI], work2[2 * NCSI];;
9527 const int n_obs = cx + cy;
9528 const int n_for = cx + cz;
9529 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
9530 const double pod = (n_obs > 0) ? (100. * cx) / n_obs : NAN;
9531 const double far = (n_for > 0) ? (100. * cz) / n_for : NAN;
9532 const double csi =
9533 (cx + cy + cz > 0) ? (100. * cx) / (cx + cy + cz) : NAN;
9534 const double cx_rd = (ct > 0) ? (1. * n_obs * n_for) / ct : NAN;
9535 const double ets = (cx + cy + cz - cx_rd > 0) ?
9536 (100. * (cx - cx_rd)) / (cx + cy + cz - cx_rd) : NAN;
9537 const double rho_p =
9538 (n > 0) ? gsl_stats_correlation(x, 1, y, 1, (size_t) n) : NAN;
9539 const double rho_s =
9540 (n > 0) ? gsl_stats_spearman(x, 1, y, 1, (size_t) n, work) : NAN;
9541 for (int i = 0; i < n; i++) {
9542 work[i] = x[i] - y[i];
9543 work2[i] = (obsstdn[i] != 0) ? (x[i] - y[i]) / obsstdn[i] : 0;
9544 }
9545 const double mean = (n > 0) ? gsl_stats_mean(work, 1, (size_t) n) : NAN;
9546 const double rmse =
9547 (n > 0) ? gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n,
9548 0.0) : NAN;
9549 const double absdev =
9550 (n > 0) ? gsl_stats_absdev_m(work, 1, (size_t) n, 0.0) : NAN;
9551 const double loglikelihood =
9552 (n > 0) ? gsl_stats_tss(work2, 1, (size_t) n) * (-0.5) : GSL_NAN;
9553
9554 /* Write... */
9555 fprintf(out,
9556 "%.2f %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n", t,
9557 cx, cy, cz, n_obs, n_for, bias, pod, far, csi, cx_rd, ets, rho_p,
9558 rho_s, mean, rmse, absdev, loglikelihood, n);
9559
9560 /* Set counters to zero... */
9561 n = ct = cx = cy = cz = 0;
9562 }
9563
9564 /* Free... */
9565 free(modmean);
9566 free(obsmean);
9567 free(obscount);
9568 free(obsstd);
9569
9570 /* Finalize... */
9571 if (t == ctl->t_stop) {
9572
9573 /* Close output file... */
9574 fclose(out);
9575
9576 /* Free... */
9577 free(area);
9578 free(rt);
9579 free(rz);
9580 free(rlon);
9581 free(rlat);
9582 free(robs);
9583 }
9584}
9585
9586/*****************************************************************************/
9587
9589 const char *filename,
9590 const ctl_t *ctl,
9591 const atm_t *atm,
9592 const double t) {
9593
9594 static FILE *out;
9595
9596 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
9597 x[3], zm[NENS];
9598
9599 static int n[NENS];
9600
9601 /* Set timer... */
9602 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
9603
9604 /* Check quantities... */
9605 if (ctl->qnt_ens < 0)
9606 ERRMSG("Missing ensemble IDs!");
9607
9608 /* Set time interval... */
9609 const double t0 = t - 0.5 * ctl->dt_mod;
9610 const double t1 = t + 0.5 * ctl->dt_mod;
9611
9612 /* Init... */
9613 for (int i = 0; i < NENS; i++) {
9614 for (int iq = 0; iq < ctl->nq; iq++)
9615 qm[iq][i] = qs[iq][i] = 0;
9616 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
9617 n[i] = 0;
9618 }
9619
9620 /* Loop over air parcels... */
9621 for (int ip = 0; ip < atm->np; ip++) {
9622
9623 /* Check time... */
9624 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9625 continue;
9626
9627 /* Check ensemble ID... */
9628 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
9629 ERRMSG("Ensemble ID is out of range!");
9630
9631 /* Get means... */
9632 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
9633 for (int iq = 0; iq < ctl->nq; iq++) {
9634 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
9635 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
9636 }
9637 xm[ctl->qnt_ens][0] += x[0];
9638 xm[ctl->qnt_ens][1] += x[1];
9639 xm[ctl->qnt_ens][2] += x[2];
9640 zm[ctl->qnt_ens] += Z(atm->p[ip]);
9641 n[ctl->qnt_ens]++;
9642 }
9643
9644 /* Create file... */
9645 LOG(1, "Write ensemble data: %s", filename);
9646 if (!(out = fopen(filename, "w")))
9647 ERRMSG("Cannot create file!");
9648
9649 /* Write header... */
9650 fprintf(out,
9651 "# $1 = time [s]\n"
9652 "# $2 = altitude [km]\n"
9653 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
9654 for (int iq = 0; iq < ctl->nq; iq++)
9655 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
9656 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9657 for (int iq = 0; iq < ctl->nq; iq++)
9658 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
9659 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9660 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
9661
9662 /* Write data... */
9663 for (int i = 0; i < NENS; i++)
9664 if (n[i] > 0) {
9665 cart2geo(xm[i], &dummy, &lon, &lat);
9666 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
9667 for (int iq = 0; iq < ctl->nq; iq++) {
9668 fprintf(out, " ");
9669 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
9670 }
9671 for (int iq = 0; iq < ctl->nq; iq++) {
9672 fprintf(out, " ");
9673 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
9674 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
9675 }
9676 fprintf(out, " %d\n", n[i]);
9677 }
9678
9679 /* Close file... */
9680 fclose(out);
9681}
9682
9683/*****************************************************************************/
9684
9686 const char *filename,
9687 const ctl_t *ctl,
9688 met_t *met0,
9689 met_t *met1,
9690 const atm_t *atm,
9691 const double t) {
9692
9693 static double kz[EP], kw[EP];
9694
9695 static int nk;
9696
9697 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
9698
9699 int *ixs, *iys, *izs, *np;
9700
9701 /* Set timer... */
9702 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
9703
9704 /* Write info... */
9705 LOG(1, "Write grid data: %s", filename);
9706
9707 /* Init... */
9708 if (t == ctl->t_start) {
9709
9710 /* Read kernel data... */
9711 if (ctl->grid_kernel[0] != '-')
9712 read_kernel(ctl->grid_kernel, kz, kw, &nk);
9713 }
9714
9715 /* Allocate... */
9716 ALLOC(cd, double,
9717 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9718 for (int iq = 0; iq < ctl->nq; iq++) {
9719 ALLOC(mean[iq], double,
9720 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9721 ALLOC(sigma[iq], double,
9722 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9723 }
9724 ALLOC(vmr_impl, double,
9725 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9726 ALLOC(z, double,
9727 ctl->grid_nz);
9728 ALLOC(lon, double,
9729 ctl->grid_nx);
9730 ALLOC(lat, double,
9731 ctl->grid_ny);
9732 ALLOC(area, double,
9733 ctl->grid_ny);
9734 ALLOC(press, double,
9735 ctl->grid_nz);
9736 ALLOC(np, int,
9737 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
9738 ALLOC(ixs, int,
9739 atm->np);
9740 ALLOC(iys, int,
9741 atm->np);
9742 ALLOC(izs, int,
9743 atm->np);
9744
9745 /* Set grid box size... */
9746 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
9747 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
9748 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
9749
9750 /* Set vertical coordinates... */
9751#pragma omp parallel for default(shared)
9752 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9753 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
9754 press[iz] = P(z[iz]);
9755 }
9756
9757 /* Set horizontal coordinates... */
9758 for (int ix = 0; ix < ctl->grid_nx; ix++)
9759 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
9760#pragma omp parallel for default(shared)
9761 for (int iy = 0; iy < ctl->grid_ny; iy++) {
9762 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
9763 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
9764 }
9765
9766 /* Set time interval for output... */
9767 const double t0 = t - 0.5 * ctl->dt_mod;
9768 const double t1 = t + 0.5 * ctl->dt_mod;
9769
9770 /* Get grid box indices... */
9771#pragma omp parallel for default(shared)
9772 for (int ip = 0; ip < atm->np; ip++) {
9773 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
9774 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
9775 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
9776 if (atm->time[ip] < t0 || atm->time[ip] > t1
9777 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
9778 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
9779 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
9780 izs[ip] = -1;
9781 }
9782
9783 /* Average data... */
9784 for (int ip = 0; ip < atm->np; ip++)
9785 if (izs[ip] >= 0) {
9786 int idx =
9787 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
9788 double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
9789 np[idx]++;
9790 for (int iq = 0; iq < ctl->nq; iq++) {
9791 mean[iq][idx] += kernel * atm->q[iq][ip];
9792 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
9793 }
9794 }
9795
9796 /* Calculate column density and volume mixing ratio... */
9797#pragma omp parallel for default(shared)
9798 for (int ix = 0; ix < ctl->grid_nx; ix++)
9799 for (int iy = 0; iy < ctl->grid_ny; iy++)
9800 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9801
9802 /* Get grid index... */
9803 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
9804
9805 /* Calculate column density... */
9806 cd[idx] = NAN;
9807 if (ctl->qnt_m >= 0)
9808 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
9809
9810 /* Calculate volume mixing ratio (implicit)... */
9811 vmr_impl[idx] = NAN;
9812 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
9813 && met1 != NULL) {
9814 vmr_impl[idx] = 0;
9815 if (mean[ctl->qnt_m][idx] > 0) {
9816
9817 /* Get temperature... */
9818 double temp;
9820 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
9821 lon[ix], lat[iy], &temp, ci, cw, 1);
9822
9823 /* Calculate volume mixing ratio... */
9824 vmr_impl[idx] =
9825 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
9826 }
9827 }
9828
9829 /* Calculate mean... */
9830 if (np[idx] > 0)
9831 for (int iq = 0; iq < ctl->nq; iq++) {
9832 mean[iq][idx] /= np[idx];
9833 double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
9834 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
9835 } else
9836 for (int iq = 0; iq < ctl->nq; iq++) {
9837 mean[iq][idx] = NAN;
9838 sigma[iq][idx] = NAN;
9839 }
9840 }
9841
9842 /* Write ASCII data... */
9843 if (ctl->grid_type == 0)
9844 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
9845 t, z, lon, lat, area, dz, np);
9846
9847 /* Write netCDF data... */
9848 else if (ctl->grid_type == 1)
9849 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
9850 t, z, lon, lat, area, dz, np);
9851
9852 /* Error message... */
9853 else
9854 ERRMSG("Grid data format GRID_TYPE unknown!");
9855
9856 /* Free... */
9857 free(cd);
9858 for (int iq = 0; iq < ctl->nq; iq++) {
9859 free(mean[iq]);
9860 free(sigma[iq]);
9861 }
9862 free(vmr_impl);
9863 free(z);
9864 free(lon);
9865 free(lat);
9866 free(area);
9867 free(press);
9868 free(np);
9869 free(ixs);
9870 free(iys);
9871 free(izs);
9872}
9873
9874/*****************************************************************************/
9875
9877 const char *filename,
9878 const ctl_t *ctl,
9879 const double *cd,
9880 double *mean[NQ],
9881 double *sigma[NQ],
9882 const double *vmr_impl,
9883 const double t,
9884 const double *z,
9885 const double *lon,
9886 const double *lat,
9887 const double *area,
9888 const double dz,
9889 const int *np) {
9890
9891 FILE *out;
9892
9893 /* Check if gnuplot output is requested... */
9894 if (ctl->grid_gpfile[0] != '-') {
9895
9896 /* Create gnuplot pipe... */
9897 if (!(out = popen("gnuplot", "w")))
9898 ERRMSG("Cannot create pipe to gnuplot!");
9899
9900 /* Set plot filename... */
9901 fprintf(out, "set out \"%s.png\"\n", filename);
9902
9903 /* Set time string... */
9904 double r;
9905 int year, mon, day, hour, min, sec;
9906 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9907 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
9908 year, mon, day, hour, min);
9909
9910 /* Dump gnuplot file to pipe... */
9911 FILE *in;
9912 char line[LEN];
9913 if (!(in = fopen(ctl->grid_gpfile, "r")))
9914 ERRMSG("Cannot open file!");
9915 while (fgets(line, LEN, in))
9916 fprintf(out, "%s", line);
9917 fclose(in);
9918 }
9919
9920 else {
9921
9922 /* Create file... */
9923 if (!(out = fopen(filename, "w")))
9924 ERRMSG("Cannot create file!");
9925 }
9926
9927 /* Write header... */
9928 fprintf(out,
9929 "# $1 = time [s]\n"
9930 "# $2 = altitude [km]\n"
9931 "# $3 = longitude [deg]\n"
9932 "# $4 = latitude [deg]\n"
9933 "# $5 = surface area [km^2]\n"
9934 "# $6 = layer depth [km]\n"
9935 "# $7 = column density (implicit) [kg/m^2]\n"
9936 "# $8 = volume mixing ratio (implicit) [ppv]\n"
9937 "# $9 = number of particles [1]\n");
9938 for (int iq = 0; iq < ctl->nq; iq++)
9939 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
9940 ctl->qnt_unit[iq]);
9941 if (ctl->grid_stddev)
9942 for (int iq = 0; iq < ctl->nq; iq++)
9943 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
9944 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
9945 fprintf(out, "\n");
9946
9947 /* Write data... */
9948 for (int ix = 0; ix < ctl->grid_nx; ix++) {
9949 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
9950 fprintf(out, "\n");
9951 for (int iy = 0; iy < ctl->grid_ny; iy++) {
9952 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
9953 fprintf(out, "\n");
9954 for (int iz = 0; iz < ctl->grid_nz; iz++) {
9955 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
9956 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
9957 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
9958 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
9959 for (int iq = 0; iq < ctl->nq; iq++) {
9960 fprintf(out, " ");
9961 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
9962 }
9963 if (ctl->grid_stddev)
9964 for (int iq = 0; iq < ctl->nq; iq++) {
9965 fprintf(out, " ");
9966 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
9967 }
9968 fprintf(out, "\n");
9969 }
9970 }
9971 }
9972 }
9973
9974 /* Close file... */
9975 fclose(out);
9976}
9977
9978/*****************************************************************************/
9979
9981 const char *filename,
9982 const ctl_t *ctl,
9983 const double *cd,
9984 double *mean[NQ],
9985 double *sigma[NQ],
9986 const double *vmr_impl,
9987 const double t,
9988 const double *z,
9989 const double *lon,
9990 const double *lat,
9991 const double *area,
9992 const double dz,
9993 const int *np) {
9994
9995 char longname[2 * LEN], varname[2 * LEN];
9996
9997 double *help;
9998
9999 int *help2, ncid, dimid[10], varid;
10000
10001 size_t start[2], count[2];
10002
10003 /* Allocate... */
10004 ALLOC(help, double,
10005 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10006 ALLOC(help2, int,
10007 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10008
10009 /* Create file... */
10010 NC(nc_create(filename, NC_NETCDF4, &ncid));
10011
10012 /* Define dimensions... */
10013 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
10014 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
10015 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
10016 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
10017 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
10018
10019 /* Define variables and their attributes... */
10020 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
10021 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
10022 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
10023 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
10024 0);
10025 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
10026 0);
10027 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
10028 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
10029
10030 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
10031 ctl->grid_nc_level, 0);
10032 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid, "volume mixing ratio (implicit)",
10033 "ppv", ctl->grid_nc_level, 0);
10034 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
10035 for (int iq = 0; iq < ctl->nq; iq++) {
10036 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
10037 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
10038 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
10039 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
10040 if (ctl->grid_stddev) {
10041 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
10042 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
10043 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
10044 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
10045 }
10046 }
10047 /* End definitions... */
10048 NC(nc_enddef(ncid));
10049
10050 /* Write data... */
10051 NC_PUT_DOUBLE("time", &t, 0);
10052 NC_PUT_DOUBLE("lon", lon, 0);
10053 NC_PUT_DOUBLE("lat", lat, 0);
10054 NC_PUT_DOUBLE("z", z, 0);
10055 NC_PUT_DOUBLE("area", area, 0);
10056 NC_PUT_DOUBLE("dz", &dz, 0);
10057
10058 for (int ix = 0; ix < ctl->grid_nx; ix++)
10059 for (int iy = 0; iy < ctl->grid_ny; iy++)
10060 for (int iz = 0; iz < ctl->grid_nz; iz++)
10061 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10062 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10063 NC_PUT_DOUBLE("cd", help, 0);
10064
10065 for (int ix = 0; ix < ctl->grid_nx; ix++)
10066 for (int iy = 0; iy < ctl->grid_ny; iy++)
10067 for (int iz = 0; iz < ctl->grid_nz; iz++)
10068 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10069 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10070 NC_PUT_DOUBLE("vmr_impl", help, 0);
10071
10072 for (int ix = 0; ix < ctl->grid_nx; ix++)
10073 for (int iy = 0; iy < ctl->grid_ny; iy++)
10074 for (int iz = 0; iz < ctl->grid_nz; iz++)
10075 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10076 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10077 NC_PUT_INT("np", help2, 0);
10078
10079 for (int iq = 0; iq < ctl->nq; iq++) {
10080 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
10081 for (int ix = 0; ix < ctl->grid_nx; ix++)
10082 for (int iy = 0; iy < ctl->grid_ny; iy++)
10083 for (int iz = 0; iz < ctl->grid_nz; iz++)
10084 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10085 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10086 NC_PUT_DOUBLE(varname, help, 0);
10087 }
10088
10089 if (ctl->grid_stddev)
10090 for (int iq = 0; iq < ctl->nq; iq++) {
10091 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
10092 for (int ix = 0; ix < ctl->grid_nx; ix++)
10093 for (int iy = 0; iy < ctl->grid_ny; iy++)
10094 for (int iz = 0; iz < ctl->grid_nz; iz++)
10095 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10096 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10097 NC_PUT_DOUBLE(varname, help, 0);
10098 }
10099
10100 /* Close file... */
10101 NC(nc_close(ncid));
10102
10103 /* Free... */
10104 free(help);
10105 free(help2);
10106}
10107
10108/*****************************************************************************/
10109
10111 const char *filename,
10112 const ctl_t *ctl,
10113 met_t *met) {
10114
10115 /* Set timer... */
10116 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
10117
10118 /* Write info... */
10119 LOG(1, "Write meteo data: %s", filename);
10120
10121 /* Check compression flags... */
10122#ifndef ZFP
10123 if (ctl->met_type == 3)
10124 ERRMSG("MPTRAC was compiled without zfp compression!");
10125#endif
10126#ifndef ZSTD
10127 if (ctl->met_type == 4)
10128 ERRMSG("MPTRAC was compiled without zstd compression!");
10129#endif
10130#ifndef CMS
10131 if (ctl->met_type == 5)
10132 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
10133#endif
10134
10135 /* Write netCDF data... */
10136 if (ctl->met_type == 0)
10137 write_met_nc(filename, ctl, met);
10138
10139 /* Write binary data... */
10140 else if (ctl->met_type >= 1 && ctl->met_type <= 5)
10141 write_met_bin(filename, ctl, met);
10142
10143 /* Not implemented... */
10144 else
10145 ERRMSG("MET_TYPE not implemented!");
10146}
10147
10148/*****************************************************************************/
10149
10151 const char *filename,
10152 const ctl_t *ctl,
10153 met_t *met) {
10154
10155 /* Create file... */
10156 FILE *out;
10157 if (!(out = fopen(filename, "w")))
10158 ERRMSG("Cannot create file!");
10159
10160 /* Write type of binary data... */
10161 FWRITE(&ctl->met_type, int,
10162 1,
10163 out);
10164
10165 /* Write version of binary data... */
10166 int version = 103;
10167 FWRITE(&version, int,
10168 1,
10169 out);
10170
10171 /* Write grid data... */
10172 FWRITE(&met->time, double,
10173 1,
10174 out);
10175 FWRITE(&met->nx, int,
10176 1,
10177 out);
10178 FWRITE(&met->ny, int,
10179 1,
10180 out);
10181 FWRITE(&met->np, int,
10182 1,
10183 out);
10184 FWRITE(met->lon, double,
10185 (size_t) met->nx,
10186 out);
10187 FWRITE(met->lat, double,
10188 (size_t) met->ny,
10189 out);
10190 FWRITE(met->p, double,
10191 (size_t) met->np,
10192 out);
10193
10194 /* Write surface data... */
10195 write_met_bin_2d(out, met, met->ps, "PS");
10196 write_met_bin_2d(out, met, met->ts, "TS");
10197 write_met_bin_2d(out, met, met->zs, "ZS");
10198 write_met_bin_2d(out, met, met->us, "US");
10199 write_met_bin_2d(out, met, met->vs, "VS");
10200 write_met_bin_2d(out, met, met->ess, "ESS");
10201 write_met_bin_2d(out, met, met->nss, "NSS");
10202 write_met_bin_2d(out, met, met->shf, "SHF");
10203 write_met_bin_2d(out, met, met->lsm, "LSM");
10204 write_met_bin_2d(out, met, met->sst, "SST");
10205 write_met_bin_2d(out, met, met->pbl, "PBL");
10206 write_met_bin_2d(out, met, met->pt, "PT");
10207 write_met_bin_2d(out, met, met->tt, "TT");
10208 write_met_bin_2d(out, met, met->zt, "ZT");
10209 write_met_bin_2d(out, met, met->h2ot, "H2OT");
10210 write_met_bin_2d(out, met, met->pct, "PCT");
10211 write_met_bin_2d(out, met, met->pcb, "PCB");
10212 write_met_bin_2d(out, met, met->cl, "CL");
10213 write_met_bin_2d(out, met, met->plcl, "PLCL");
10214 write_met_bin_2d(out, met, met->plfc, "PLFC");
10215 write_met_bin_2d(out, met, met->pel, "PEL");
10216 write_met_bin_2d(out, met, met->cape, "CAPE");
10217 write_met_bin_2d(out, met, met->cin, "CIN");
10218 write_met_bin_2d(out, met, met->o3c, "O3C");
10219
10220 /* Write level data... */
10221 write_met_bin_3d(out, ctl, met, met->z, "Z",
10222 (ctl->met_zfp_tol_z <= 0 ? ctl->met_zfp_prec : 0),
10223 ctl->met_zfp_tol_z);
10224 write_met_bin_3d(out, ctl, met, met->t, "T",
10225 (ctl->met_zfp_tol_t <= 0 ? ctl->met_zfp_prec : 0),
10226 ctl->met_zfp_tol_t);
10227 write_met_bin_3d(out, ctl, met, met->u, "U", ctl->met_zfp_prec, 0);
10228 write_met_bin_3d(out, ctl, met, met->v, "V", ctl->met_zfp_prec, 0);
10229 write_met_bin_3d(out, ctl, met, met->w, "W", ctl->met_zfp_prec, 0);
10230 write_met_bin_3d(out, ctl, met, met->pv, "PV", ctl->met_zfp_prec, 0);
10231 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", ctl->met_zfp_prec, 0);
10232 write_met_bin_3d(out, ctl, met, met->o3, "O3", ctl->met_zfp_prec, 0);
10233 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", ctl->met_zfp_prec, 0);
10234 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", ctl->met_zfp_prec, 0);
10235 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", ctl->met_zfp_prec, 0);
10236 write_met_bin_3d(out, ctl, met, met->swc, "SWC", ctl->met_zfp_prec, 0);
10237 write_met_bin_3d(out, ctl, met, met->cc, "CC", ctl->met_zfp_prec, 0);
10238
10239 /* Write final flag... */
10240 int final = 999;
10241 FWRITE(&final, int,
10242 1,
10243 out);
10244
10245 /* Close file... */
10246 fclose(out);
10247}
10248
10249/*****************************************************************************/
10250
10252 FILE *out,
10253 met_t *met,
10254 float var[EX][EY],
10255 const char *varname) {
10256
10257 float *help;
10258
10259 /* Allocate... */
10260 ALLOC(help, float,
10261 EX * EY);
10262
10263 /* Copy data... */
10264 for (int ix = 0; ix < met->nx; ix++)
10265 for (int iy = 0; iy < met->ny; iy++)
10266 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
10267
10268 /* Write uncompressed data... */
10269 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
10270 FWRITE(help, float,
10271 (size_t) (met->nx * met->ny),
10272 out);
10273
10274 /* Free... */
10275 free(help);
10276}
10277
10278/*****************************************************************************/
10279
10281 FILE *out,
10282 const ctl_t *ctl,
10283 met_t *met,
10284 float var[EX][EY][EP],
10285 const char *varname,
10286 const int precision,
10287 const double tolerance) {
10288
10289 float *help;
10290
10291 /* Allocate... */
10292 ALLOC(help, float,
10293 EX * EY * EP);
10294
10295 /* Copy data... */
10296#pragma omp parallel for default(shared) collapse(2)
10297 for (int ix = 0; ix < met->nx; ix++)
10298 for (int iy = 0; iy < met->ny; iy++)
10299 for (int ip = 0; ip < met->np; ip++)
10300 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
10301
10302 /* Write uncompressed data... */
10303 if (ctl->met_type == 1) {
10304 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
10305 FWRITE(help, float,
10306 (size_t) (met->nx * met->ny * met->np),
10307 out);
10308 }
10309
10310 /* Write packed data... */
10311 else if (ctl->met_type == 2)
10312 compress_pck(varname, help, (size_t) (met->ny * met->nx),
10313 (size_t) met->np, 0, out);
10314
10315 /* Write zfp data... */
10316#ifdef ZFP
10317 else if (ctl->met_type == 3) {
10318 FWRITE(&precision, int,
10319 1,
10320 out);
10321 FWRITE(&tolerance, double,
10322 1,
10323 out);
10324 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
10325 tolerance, 0, out);
10326 }
10327#endif
10328
10329 /* Write zstd data... */
10330#ifdef ZSTD
10331 else if (ctl->met_type == 4)
10332 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
10333 out);
10334#endif
10335
10336 /* Write cmultiscale data... */
10337#ifdef CMS
10338 else if (ctl->met_type == 5) {
10339 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
10340 (size_t) met->np, 0, out);
10341 }
10342#endif
10343
10344 /* Unknown method... */
10345 else {
10346 ERRMSG("MET_TYPE not supported!");
10347 LOG(3, "%d %g", precision, tolerance);
10348 }
10349
10350 /* Free... */
10351 free(help);
10352}
10353
10354/*****************************************************************************/
10355
10357 const char *filename,
10358 const ctl_t *ctl,
10359 met_t *met) {
10360
10361 /* Create file... */
10362 int ncid, varid;
10363 size_t start[4], count[4];
10364 nc_create(filename, NC_NETCDF4, &ncid);
10365
10366 /* Define dimensions... */
10367 int tid, lonid, latid, levid;
10368 NC(nc_def_dim(ncid, "time", 1, &tid));
10369 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
10370 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
10371 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
10372
10373 /* Define grid... */
10374 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
10375 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
10376 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
10377 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
10378 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
10379
10380 /* Define surface variables... */
10381 int dimid2[2] = { latid, lonid };
10382 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
10383 ctl->met_nc_level, 0);
10384 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
10385 ctl->met_nc_level, 0);
10386 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
10387 ctl->met_nc_level, 0);
10388 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
10389 "m s**-1", ctl->met_nc_level, 0);
10390 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
10391 "m s**-1", ctl->met_nc_level, 0);
10392 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
10393 "Instantaneous eastward turbulent surface stress", "N m**-2",
10394 ctl->met_nc_level, 0);
10395 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
10396 "Instantaneous northward turbulent surface stress", "N m**-2",
10397 ctl->met_nc_level, 0);
10398 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
10399 "Instantaneous surface sensible heat flux", "W m**-1",
10400 ctl->met_nc_level, 0);
10401 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
10402 ctl->met_nc_level, 0);
10403 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
10404 ctl->met_nc_level, 0);
10405 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
10406 ctl->met_nc_level, 0);
10407 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
10408 ctl->met_nc_level, 0);
10409 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
10410 ctl->met_nc_level, 0);
10411 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
10412 ctl->met_nc_level, 0);
10413 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
10414 ctl->met_nc_level, 0);
10415 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
10416 ctl->met_nc_level, 0);
10417 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
10418 ctl->met_nc_level, 0);
10419 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water", "kg m**2",
10420 ctl->met_nc_level, 0);
10421 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
10422 "Pressure at lifted condensation level (LCL)", "Pa",
10423 ctl->met_nc_level, 0);
10424 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
10425 "Pressure at level of free convection (LFC)", "Pa",
10426 ctl->met_nc_level, 0);
10427 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2, "Pressure at equilibrium level (EL)",
10428 "Pa", ctl->met_nc_level, 0);
10429 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
10430 "Convective available potential energy", "J kg**-1",
10431 ctl->met_nc_level, 0);
10432 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition", "J kg**-1",
10433 ctl->met_nc_level, 0);
10434 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
10435 ctl->met_nc_level, 0);
10436
10437 /* Define level data... */
10438 int dimid3[3] = { levid, latid, lonid };
10439 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
10440 ctl->met_nc_level, ctl->met_nc_quant);
10441 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
10442 ctl->met_nc_level, ctl->met_nc_quant);
10443 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
10444 ctl->met_nc_level, ctl->met_nc_quant);
10445 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
10446 ctl->met_nc_level, ctl->met_nc_quant);
10447 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
10448 ctl->met_nc_level, ctl->met_nc_quant);
10449 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
10450 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10451 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
10452 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10453 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
10454 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10455 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
10456 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10457 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
10458 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10459 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
10460 ctl->met_nc_level, ctl->met_nc_quant);
10461
10462 /* End definitions... */
10463 NC(nc_enddef(ncid));
10464
10465 /* Write grid data... */
10466 NC_PUT_DOUBLE("time", &met->time, 0);
10467 NC_PUT_DOUBLE("lon", met->lon, 0);
10468 NC_PUT_DOUBLE("lat", met->lat, 0);
10469 double phelp[EP];
10470 for (int ip = 0; ip < met->np; ip++)
10471 phelp[ip] = 100. * met->p[ip];
10472 NC_PUT_DOUBLE("lev", phelp, 0);
10473
10474 /* Write surface data... */
10475 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
10476 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
10477 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
10478 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
10479 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
10480 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
10481 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
10482 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
10483 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
10484 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
10485 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
10486 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
10487 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
10488 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
10489 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
10490 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
10491 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
10492 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
10493 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
10494 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
10495 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
10496 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
10497 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
10498 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
10499
10500 /* Write level data... */
10501 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
10502 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
10503 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
10504 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
10505 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
10506 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
10507 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
10508 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
10509 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
10510 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
10511 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
10512
10513 /* Close file... */
10514 NC(nc_close(ncid));
10515}
10516
10517/*****************************************************************************/
10518
10520 const int ncid,
10521 const char *varname,
10522 met_t *met,
10523 float var[EX][EY],
10524 const float scl) {
10525
10526 int varid;
10527 size_t start[4], count[4];
10528
10529 /* Allocate... */
10530 float *help;
10531 ALLOC(help, float,
10532 EX * EY);
10533
10534 /* Copy data... */
10535 for (int ix = 0; ix < met->nx; ix++)
10536 for (int iy = 0; iy < met->ny; iy++)
10537 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
10538
10539 /* Write data... */
10540 NC_PUT_FLOAT(varname, help, 0);
10541
10542 /* Free... */
10543 free(help);
10544}
10545
10546/*****************************************************************************/
10547
10549 const int ncid,
10550 const char *varname,
10551 met_t *met,
10552 float var[EX][EY][EP],
10553 const float scl) {
10554
10555 int varid;
10556 size_t start[4], count[4];
10557
10558 /* Allocate... */
10559 float *help;
10560 ALLOC(help, float,
10561 EX * EY * EP);
10562
10563 /* Copy data... */
10564 for (int ix = 0; ix < met->nx; ix++)
10565 for (int iy = 0; iy < met->ny; iy++)
10566 for (int ip = 0; ip < met->np; ip++)
10567 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
10568
10569 /* Write data... */
10570 NC_PUT_FLOAT(varname, help, 0);
10571
10572 /* Free... */
10573 free(help);
10574}
10575
10576/*****************************************************************************/
10577
10579 const char *dirname,
10580 const ctl_t *ctl,
10581 met_t *met0,
10582 met_t *met1,
10583 atm_t *atm,
10584 const double t) {
10585
10586 char ext[10], filename[2 * LEN];
10587
10588 double r;
10589
10590 int year, mon, day, hour, min, sec;
10591
10592 /* Get time... */
10593 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
10594
10595 /* Update host... */
10596#ifdef _OPENACC
10597 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
10598 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
10599 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
10600 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
10601 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
10602 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0)) {
10603 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_D2H);
10604#pragma acc update host(atm[:1])
10605 }
10606#endif
10607
10608 /* Write atmospheric data... */
10609 if (ctl->atm_basename[0] != '-' &&
10610 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
10611 if (ctl->atm_type_out == 0)
10612 sprintf(ext, "tab");
10613 else if (ctl->atm_type_out == 1)
10614 sprintf(ext, "bin");
10615 else if (ctl->atm_type_out == 2)
10616 sprintf(ext, "nc");
10617 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
10618 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
10619 write_atm(filename, ctl, atm, t);
10620 }
10621
10622 /* Write gridded data... */
10623 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
10624 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
10625 dirname, ctl->grid_basename, year, mon, day, hour, min,
10626 ctl->grid_type == 0 ? "tab" : "nc");
10627 write_grid(filename, ctl, met0, met1, atm, t);
10628 }
10629
10630 /* Write CSI data... */
10631 if (ctl->csi_basename[0] != '-') {
10632 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
10633 write_csi(filename, ctl, atm, t);
10634 }
10635
10636 /* Write ensemble data... */
10637 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
10638 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
10639 dirname, ctl->ens_basename, year, mon, day, hour, min);
10640 write_ens(filename, ctl, atm, t);
10641 }
10642
10643 /* Write profile data... */
10644 if (ctl->prof_basename[0] != '-') {
10645 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
10646 write_prof(filename, ctl, met0, met1, atm, t);
10647 }
10648
10649 /* Write sample data... */
10650 if (ctl->sample_basename[0] != '-') {
10651 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
10652 write_sample(filename, ctl, met0, met1, atm, t);
10653 }
10654
10655 /* Write station data... */
10656 if (ctl->stat_basename[0] != '-') {
10657 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
10658 write_station(filename, ctl, atm, t);
10659 }
10660
10661 /* Write VTK data... */
10662 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
10663 static int nvtk;
10664 if (t == ctl->t_start)
10665 nvtk = 0;
10666 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
10667 write_vtk(filename, ctl, atm, t);
10668 }
10669}
10670
10671/*****************************************************************************/
10672
10674 const char *filename,
10675 const ctl_t *ctl,
10676 met_t *met0,
10677 met_t *met1,
10678 const atm_t *atm,
10679 const double t) {
10680
10681 static FILE *out;
10682
10683 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
10684 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
10685
10686 static int nobs, *obscount, ip, okay;
10687
10688 /* Set timer... */
10689 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
10690
10691 /* Init... */
10692 if (t == ctl->t_start) {
10693
10694 /* Check quantity index for mass... */
10695 if (ctl->qnt_m < 0)
10696 ERRMSG("Need quantity mass!");
10697
10698 /* Check molar mass... */
10699 if (ctl->molmass <= 0)
10700 ERRMSG("Specify molar mass!");
10701
10702 /* Allocate... */
10703 ALLOC(lon, double,
10704 ctl->prof_nx);
10705 ALLOC(lat, double,
10706 ctl->prof_ny);
10707 ALLOC(area, double,
10708 ctl->prof_ny);
10709 ALLOC(z, double,
10710 ctl->prof_nz);
10711 ALLOC(press, double,
10712 ctl->prof_nz);
10713 ALLOC(rt, double,
10714 NOBS);
10715 ALLOC(rz, double,
10716 NOBS);
10717 ALLOC(rlon, double,
10718 NOBS);
10719 ALLOC(rlat, double,
10720 NOBS);
10721 ALLOC(robs, double,
10722 NOBS);
10723
10724 /* Read observation data... */
10725 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
10726
10727 /* Create new output file... */
10728 LOG(1, "Write profile data: %s", filename);
10729 if (!(out = fopen(filename, "w")))
10730 ERRMSG("Cannot create file!");
10731
10732 /* Write header... */
10733 fprintf(out,
10734 "# $1 = time [s]\n"
10735 "# $2 = altitude [km]\n"
10736 "# $3 = longitude [deg]\n"
10737 "# $4 = latitude [deg]\n"
10738 "# $5 = pressure [hPa]\n"
10739 "# $6 = temperature [K]\n"
10740 "# $7 = volume mixing ratio [ppv]\n"
10741 "# $8 = H2O volume mixing ratio [ppv]\n"
10742 "# $9 = O3 volume mixing ratio [ppv]\n"
10743 "# $10 = observed BT index [K]\n"
10744 "# $11 = number of observations\n");
10745
10746 /* Set grid box size... */
10747 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
10748 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
10749 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
10750
10751 /* Set vertical coordinates... */
10752 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10753 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
10754 press[iz] = P(z[iz]);
10755 }
10756
10757 /* Set horizontal coordinates... */
10758 for (int ix = 0; ix < ctl->prof_nx; ix++)
10759 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
10760 for (int iy = 0; iy < ctl->prof_ny; iy++) {
10761 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
10762 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
10763 }
10764 }
10765
10766 /* Set time interval... */
10767 const double t0 = t - 0.5 * ctl->dt_mod;
10768 const double t1 = t + 0.5 * ctl->dt_mod;
10769
10770 /* Allocate... */
10771 ALLOC(mass, double,
10772 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
10773 ALLOC(obsmean, double,
10774 ctl->prof_nx * ctl->prof_ny);
10775 ALLOC(obscount, int,
10776 ctl->prof_nx * ctl->prof_ny);
10777
10778 /* Loop over observations... */
10779 for (int i = 0; i < nobs; i++) {
10780
10781 /* Check time... */
10782 if (rt[i] < t0)
10783 continue;
10784 else if (rt[i] >= t1)
10785 break;
10786
10787 /* Check observation data... */
10788 if (!isfinite(robs[i]))
10789 continue;
10790
10791 /* Calculate indices... */
10792 int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
10793 int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
10794
10795 /* Check indices... */
10796 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
10797 continue;
10798
10799 /* Get mean observation index... */
10800 int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
10801 obsmean[idx] += robs[i];
10802 obscount[idx]++;
10803 }
10804
10805 /* Analyze model data... */
10806 for (ip = 0; ip < atm->np; ip++) {
10807
10808 /* Check time... */
10809 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10810 continue;
10811
10812 /* Get indices... */
10813 int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
10814 int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
10815 int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
10816
10817 /* Check indices... */
10818 if (ix < 0 || ix >= ctl->prof_nx ||
10819 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
10820 continue;
10821
10822 /* Get total mass in grid cell... */
10823 int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10824 mass[idx] += atm->q[ctl->qnt_m][ip];
10825 }
10826
10827 /* Extract profiles... */
10828 for (int ix = 0; ix < ctl->prof_nx; ix++)
10829 for (int iy = 0; iy < ctl->prof_ny; iy++) {
10830 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
10831 if (obscount[idx2] > 0) {
10832
10833 /* Check profile... */
10834 okay = 0;
10835 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10836 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10837 if (mass[idx3] > 0) {
10838 okay = 1;
10839 break;
10840 }
10841 }
10842 if (!okay)
10843 continue;
10844
10845 /* Write output... */
10846 fprintf(out, "\n");
10847
10848 /* Loop over altitudes... */
10849 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10850
10851 /* Get temperature, water vapor, and ozone... */
10853 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
10854 lon[ix], lat[iy], &temp, ci, cw, 1);
10855 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
10856 lon[ix], lat[iy], &h2o, ci, cw, 0);
10857 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
10858 lon[ix], lat[iy], &o3, ci, cw, 0);
10859
10860 /* Calculate volume mixing ratio... */
10861 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
10862 vmr = MA / ctl->molmass * mass[idx3]
10863 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
10864
10865 /* Write output... */
10866 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
10867 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
10868 obsmean[idx2] / obscount[idx2], obscount[idx2]);
10869 }
10870 }
10871 }
10872
10873 /* Free... */
10874 free(mass);
10875 free(obsmean);
10876 free(obscount);
10877
10878 /* Finalize... */
10879 if (t == ctl->t_stop) {
10880
10881 /* Close output file... */
10882 fclose(out);
10883
10884 /* Free... */
10885 free(lon);
10886 free(lat);
10887 free(area);
10888 free(z);
10889 free(press);
10890 free(rt);
10891 free(rz);
10892 free(rlon);
10893 free(rlat);
10894 free(robs);
10895 }
10896}
10897
10898/*****************************************************************************/
10899
10901 const char *filename,
10902 const ctl_t *ctl,
10903 met_t *met0,
10904 met_t *met1,
10905 const atm_t *atm,
10906 const double t) {
10907
10908 static FILE *out;
10909
10910 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
10911 kw[EP];
10912
10913 static int nobs, nk;
10914
10915 /* Set timer... */
10916 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
10917
10918 /* Init... */
10919 if (t == ctl->t_start) {
10920
10921 /* Allocate... */
10922 ALLOC(rt, double,
10923 NOBS);
10924 ALLOC(rz, double,
10925 NOBS);
10926 ALLOC(rlon, double,
10927 NOBS);
10928 ALLOC(rlat, double,
10929 NOBS);
10930 ALLOC(robs, double,
10931 NOBS);
10932
10933 /* Read observation data... */
10934 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
10935
10936 /* Read kernel data... */
10937 if (ctl->sample_kernel[0] != '-')
10938 read_kernel(ctl->sample_kernel, kz, kw, &nk);
10939
10940 /* Create output file... */
10941 LOG(1, "Write sample data: %s", filename);
10942 if (!(out = fopen(filename, "w")))
10943 ERRMSG("Cannot create file!");
10944
10945 /* Write header... */
10946 fprintf(out,
10947 "# $1 = time [s]\n"
10948 "# $2 = altitude [km]\n"
10949 "# $3 = longitude [deg]\n"
10950 "# $4 = latitude [deg]\n"
10951 "# $5 = surface area [km^2]\n"
10952 "# $6 = layer depth [km]\n"
10953 "# $7 = number of particles [1]\n"
10954 "# $8 = column density [kg/m^2]\n"
10955 "# $9 = volume mixing ratio [ppv]\n"
10956 "# $10 = observed BT index [K]\n\n");
10957
10958 /* Set latitude range, squared radius, and area... */
10959 dlat = DY2DEG(ctl->sample_dx);
10960 rmax2 = SQR(ctl->sample_dx);
10961 area = M_PI * rmax2;
10962 }
10963
10964 /* Set time interval for output... */
10965 const double t0 = t - 0.5 * ctl->dt_mod;
10966 const double t1 = t + 0.5 * ctl->dt_mod;
10967
10968 /* Loop over observations... */
10969 for (int i = 0; i < nobs; i++) {
10970
10971 /* Check time... */
10972 if (rt[i] < t0)
10973 continue;
10974 else if (rt[i] >= t1)
10975 break;
10976
10977 /* Calculate Cartesian coordinates... */
10978 double x0[3];
10979 geo2cart(0, rlon[i], rlat[i], x0);
10980
10981 /* Set pressure range... */
10982 const double rp = P(rz[i]);
10983 const double ptop = P(rz[i] + ctl->sample_dz);
10984 const double pbot = P(rz[i] - ctl->sample_dz);
10985
10986 /* Init... */
10987 double mass = 0;
10988 int np = 0;
10989
10990 /* Loop over air parcels... */
10991 //#pragma omp parallel for default(shared) reduction(+:mass,np)
10992 for (int ip = 0; ip < atm->np; ip++) {
10993
10994 /* Check time... */
10995 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10996 continue;
10997
10998 /* Check latitude... */
10999 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
11000 continue;
11001
11002 /* Check horizontal distance... */
11003 double x1[3];
11004 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
11005 if (DIST2(x0, x1) > rmax2)
11006 continue;
11007
11008 /* Check pressure... */
11009 if (ctl->sample_dz > 0)
11010 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
11011 continue;
11012
11013 /* Add mass... */
11014 if (ctl->qnt_m >= 0)
11015 mass +=
11016 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11017 np++;
11018 }
11019
11020 /* Calculate column density... */
11021 const double cd = mass / (1e6 * area);
11022
11023 /* Calculate volume mixing ratio... */
11024 double vmr = 0;
11025 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
11026 if (mass > 0) {
11027
11028 /* Get temperature... */
11029 double temp;
11031 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
11032 rlon[i], rlat[i], &temp, ci, cw, 1);
11033
11034 /* Calculate volume mixing ratio... */
11035 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
11036 }
11037 } else
11038 vmr = NAN;
11039
11040 /* Write output... */
11041 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
11042 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
11043 }
11044
11045 /* Finalize...... */
11046 if (t == ctl->t_stop) {
11047
11048 /* Close output file... */
11049 fclose(out);
11050
11051 /* Free... */
11052 free(rt);
11053 free(rz);
11054 free(rlon);
11055 free(rlat);
11056 free(robs);
11057 }
11058}
11059
11060/*****************************************************************************/
11061
11063 const char *filename,
11064 const ctl_t *ctl,
11065 atm_t *atm,
11066 const double t) {
11067
11068 static FILE *out;
11069
11070 static double rmax2, x0[3], x1[3];
11071
11072 /* Set timer... */
11073 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
11074
11075 /* Init... */
11076 if (t == ctl->t_start) {
11077
11078 /* Write info... */
11079 LOG(1, "Write station data: %s", filename);
11080
11081 /* Create new file... */
11082 if (!(out = fopen(filename, "w")))
11083 ERRMSG("Cannot create file!");
11084
11085 /* Write header... */
11086 fprintf(out,
11087 "# $1 = time [s]\n"
11088 "# $2 = altitude [km]\n"
11089 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11090 for (int iq = 0; iq < ctl->nq; iq++)
11091 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
11092 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11093 fprintf(out, "\n");
11094
11095 /* Set geolocation and search radius... */
11096 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
11097 rmax2 = SQR(ctl->stat_r);
11098 }
11099
11100 /* Set time interval for output... */
11101 const double t0 = t - 0.5 * ctl->dt_mod;
11102 const double t1 = t + 0.5 * ctl->dt_mod;
11103
11104 /* Loop over air parcels... */
11105 for (int ip = 0; ip < atm->np; ip++) {
11106
11107 /* Check time... */
11108 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11109 continue;
11110
11111 /* Check time range for station output... */
11112 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
11113 continue;
11114
11115 /* Check station flag... */
11116 if (ctl->qnt_stat >= 0)
11117 if ((int) atm->q[ctl->qnt_stat][ip])
11118 continue;
11119
11120 /* Get Cartesian coordinates... */
11121 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
11122
11123 /* Check horizontal distance... */
11124 if (DIST2(x0, x1) > rmax2)
11125 continue;
11126
11127 /* Set station flag... */
11128 if (ctl->qnt_stat >= 0)
11129 atm->q[ctl->qnt_stat][ip] = 1;
11130
11131 /* Write data... */
11132 fprintf(out, "%.2f %g %g %g",
11133 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
11134 for (int iq = 0; iq < ctl->nq; iq++) {
11135 fprintf(out, " ");
11136 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11137 }
11138 fprintf(out, "\n");
11139 }
11140
11141 /* Close file... */
11142 if (t == ctl->t_stop)
11143 fclose(out);
11144}
11145
11146/*****************************************************************************/
11147
11149 const char *filename,
11150 const ctl_t *ctl,
11151 const atm_t *atm,
11152 const double t) {
11153
11154 FILE *out;
11155
11156 /* Set timer... */
11157 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
11158
11159 /* Write info... */
11160 LOG(1, "Write VTK data: %s", filename);
11161
11162 /* Set time interval for output... */
11163 const double t0 = t - 0.5 * ctl->dt_mod;
11164 const double t1 = t + 0.5 * ctl->dt_mod;
11165
11166 /* Create file... */
11167 if (!(out = fopen(filename, "w")))
11168 ERRMSG("Cannot create file!");
11169
11170 /* Count data points... */
11171 int np = 0;
11172 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11173 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11174 continue;
11175 np++;
11176 }
11177
11178 /* Write header... */
11179 fprintf(out,
11180 "# vtk DataFile Version 3.0\n"
11181 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
11182
11183 /* Write point coordinates... */
11184 fprintf(out, "POINTS %d float\n", np);
11185 if (ctl->vtk_sphere) {
11186 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11187 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11188 continue;
11189 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
11190 + ctl->vtk_offset) / RE;
11191 const double coslat = cos(DEG2RAD(atm->lat[ip]));
11192 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
11193 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
11194 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
11195 fprintf(out, "%g %g %g\n", x, y, z);
11196 }
11197 } else
11198 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11199 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11200 continue;
11201 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
11202 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
11203 }
11204
11205 /* Write point data... */
11206 fprintf(out, "POINT_DATA %d\n", np);
11207 for (int iq = 0; iq < ctl->nq; iq++) {
11208 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
11209 ctl->qnt_name[iq]);
11210 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11211 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11212 continue;
11213 fprintf(out, "%g\n", atm->q[iq][ip]);
11214 }
11215 }
11216
11217 /* Close file... */
11218 fclose(out);
11219}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:6651
void day2doy(const int year, const int mon, const int day, int *doy)
Get day of year from date.
Definition: mptrac.c:897
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:6611
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:6897
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:7155
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:9119
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:10519
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:4320
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:7923
void module_wet_deposition(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:4185
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:10280
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:8402
void 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:1003
void module_advect(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Performs the advection of atmospheric particles using meteorological data.
Definition: mptrac.c:2217
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:4047
int 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:6017
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:3361
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:4884
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:6450
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:2753
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:8575
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:1592
void intpol_met_time_3d_ml(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)
Interpolates a meteorological variable in time and 3D space (longitude, latitude, pressure).
Definition: mptrac.c:1681
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:4791
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:7531
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:6507
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:7227
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:8230
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:8446
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:2178
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:1238
void module_chem_init(const ctl_t *ctl, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Initializes the chemistry modules by setting atmospheric composition.
Definition: mptrac.c:2639
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:5003
void module_dry_deposition(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:3046
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:7668
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:4084
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:9588
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:3465
double clim_zm(const clim_zm_t *zm, const double t, const double lat, const double p)
Interpolates monthly mean zonal mean climatological variables.
Definition: mptrac.c:401
void module_chemgrid(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:2492
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:4975
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:7033
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:8474
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:6779
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:6220
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:2114
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:3192
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:1908
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:1281
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:9876
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:8717
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:1652
void 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:8874
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:946
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:657
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:4520
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:8608
void module_diffusion_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:2792
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:5057
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:3922
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:8748
void read_met_monotonize(met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:7075
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:8934
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:1459
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:8095
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:2680
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:5976
void module_advect_init(const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm)
Initializes the advection module by setting up pressure fields.
Definition: mptrac.c:2370
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:2396
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:8503
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:4011
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:8655
void 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:10110
void module_diffusion_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:2994
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:1737
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:7385
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:6249
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:2144
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:8816
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:10673
void module_diffusion_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:2869
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:8851
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:10356
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:3787
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:7894
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:4367
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:3818
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:1149
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:11062
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
void 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:10578
double sza_calc(const double sec, const double lon, const double lat)
Calculates the solar zenith angle.
Definition: mptrac.c:8676
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:3555
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:916
void 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:5156
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:1704
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:3733
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:2197
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:10251
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:7788
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:4679
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:1214
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:3951
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:1831
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:6072
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:4393
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:9066
int read_atm_clams(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a CLaMS netCDF file and populates the given atmospheric structure.
Definition: mptrac.c:4735
int 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:4566
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:11148
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:4115
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:7729
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:3109
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:9980
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:4544
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:10548
void read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:4824
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:3256
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:3649
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:985
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:1864
void intpol_met_space_3d_ml(const met_t *met, float array[EX][EY][EP], const double p, const double lon, const double lat, double *var)
Interpolates a meteorological variable in 3D space (longitude, latitude, pressure).
Definition: mptrac.c:1519
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:4637
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:10900
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:9685
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:10150
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:9016
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:6335
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:1890
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:9326
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:9277
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:1916
#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:1883
#define ZETA(ps, p, t)
Calculate potential vorticity using the Zeta approximation.
Definition: mptrac.h:1803
#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:1960
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:1996
#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:1846
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:3147
double time[NP]
Time [s].
Definition: mptrac.h:3153
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3162
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3159
int np
Number of air parcels.
Definition: mptrac.h:3150
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3165
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3156
Cache data structure.
Definition: mptrac.h:3175
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3196
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3184
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3187
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3181
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3193
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3190
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3178
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3207
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3213
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3222
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3243
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3219
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3237
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3240
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3234
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3228
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3249
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3252
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3231
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3246
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3225
int np
Number of pressure levels.
Definition: mptrac.h:3210
int no3c
Number of total ozone columns.
Definition: mptrac.h:3216
Climatological data.
Definition: mptrac.h:3315
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3357
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3333
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3345
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3336
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3318
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3363
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3351
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3354
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3348
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3327
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3342
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3321
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3339
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3330
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3324
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3360
Climatological data in the form of time series.
Definition: mptrac.h:3263
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3272
double time[CTS]
Time [s].
Definition: mptrac.h:3269
int ntime
Number of timesteps.
Definition: mptrac.h:3266
Climatological data in the form of zonal means.
Definition: mptrac.h:3283
double time[CT]
Time [s].
Definition: mptrac.h:3295
int np
Number of pressure levels.
Definition: mptrac.h:3292
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3301
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3304
int ntime
Number of timesteps.
Definition: mptrac.h:3286
int nlat
Number of latitudes.
Definition: mptrac.h:3289
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3298
Control parameters.
Definition: mptrac.h:2170
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3027
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2282
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:2991
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:2958
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2429
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2879
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2500
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2315
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:2967
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2741
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2261
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2453
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:2919
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2804
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2828
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2189
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2201
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2462
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2210
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2294
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:2961
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2303
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2780
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2729
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:2982
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2270
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3105
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2789
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2641
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2801
double stat_r
Search radius around station [km].
Definition: mptrac.h:3111
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2873
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:2985
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3135
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2825
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2609
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2291
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2843
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2693
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2441
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2540
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2369
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3054
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3030
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2465
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2648
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2447
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2570
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2628
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2333
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2396
char species[LEN]
Species.
Definition: mptrac.h:2738
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:2976
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:2988
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2675
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2606
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2285
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2684
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3015
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3033
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:2932
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2702
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3045
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2216
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2360
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2543
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2312
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3036
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2339
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2625
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3090
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2390
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2484
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2762
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2846
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2597
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3006
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2531
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2669
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2204
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2237
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2381
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2717
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3117
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:2952
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2666
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3051
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:2979
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2243
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2852
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3021
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2366
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2834
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2735
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2351
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2594
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2576
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2213
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2657
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3057
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2645
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2723
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2219
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3060
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:2955
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2603
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:2964
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2573
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2837
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2681
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2555
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2558
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3003
int met_zfp_prec
ZFP compression precision for all variables, except z and T.
Definition: mptrac.h:2509
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2534
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3063
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2276
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2708
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2619
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3069
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2198
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2616
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2207
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2634
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2792
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2399
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2336
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:2973
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3114
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2855
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2765
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2750
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:2891
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2798
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2357
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:2937
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2864
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:2949
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2900
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2234
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2225
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2426
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3123
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2471
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2699
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3093
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2327
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3000
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2497
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2255
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2375
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2561
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2714
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2612
int met_dx
Stride for longitudes.
Definition: mptrac.h:2564
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2813
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2487
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2387
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2759
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2867
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2474
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2660
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2414
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2408
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2258
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3132
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2273
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2354
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2711
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2631
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2330
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2186
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2432
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2591
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2849
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2279
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3078
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2378
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2267
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3099
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2747
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:2946
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3018
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2549
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2222
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2525
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3039
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2456
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2450
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2180
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:2916
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2816
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2246
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2306
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2651
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3066
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2264
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:2925
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2861
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2384
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2690
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:2994
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2870
int met_vert_coord
Vertical coordinate of input meteo data (0=pressure-level, 1=model-level).
Definition: mptrac.h:2490
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:2970
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2393
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3108
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2435
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2888
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3042
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2459
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2420
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2582
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2687
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2481
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2726
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2528
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2822
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2318
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2705
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2795
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2324
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2720
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2807
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2771
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2423
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2411
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3024
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2756
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2231
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:2997
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3087
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:2928
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2600
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2819
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:2922
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2783
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3084
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2518
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2906
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2579
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3072
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2831
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2300
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2348
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2363
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3081
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2321
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2909
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3075
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2552
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2506
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2858
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2444
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2943
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2897
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2840
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2774
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2546
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3012
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3120
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2903
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2249
int met_np
Number of target pressure levels.
Definition: mptrac.h:2585
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2195
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2503
double met_zfp_tol_t
ZFP compression tolerance for temperature.
Definition: mptrac.h:2512
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2786
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2345
double met_zfp_tol_z
ZFP compression tolerance for geopotential height.
Definition: mptrac.h:2515
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3129
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2777
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2537
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2885
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2663
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2696
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2402
int advect_vert_coord
Vertical coordinate of air parcels (0=pressure, 1=zeta, 2=eta).
Definition: mptrac.h:2654
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2342
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2438
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2240
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2810
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2940
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2753
int met_cms_heur
cmultiscale coarsening heuristics (0=default, 1=mean diff, 2=median diff, 3=max diff).
Definition: mptrac.h:2522
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2894
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2372
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2228
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2882
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2876
int met_dy
Stride for latitudes.
Definition: mptrac.h:2567
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2417
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2678
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2732
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2192
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2622
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2288
double t_start
Start time of simulation [s].
Definition: mptrac.h:2468
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2183
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2588
int nq
Number of quantities.
Definition: mptrac.h:2177
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2744
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3096
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3126
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3102
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2672
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3048
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2252
int met_type
Type of meteo data files (0=netCDF, 1=binary, 2=pck, 3=zfp, 4=zstd, 5=cms).
Definition: mptrac.h:2494
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2297
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2309
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3009
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2405
Meteo data structure.
Definition: mptrac.h:3374
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3443
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3431
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3503
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3473
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3530
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3494
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3467
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3488
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3449
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3401
int nx
Number of longitudes.
Definition: mptrac.h:3380
int ny
Number of latitudes.
Definition: mptrac.h:3383
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3425
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3404
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3500
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3413
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3524
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3521
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3410
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3497
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3512
int np
Number of pressure levels.
Definition: mptrac.h:3386
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3479
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3407
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3482
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3419
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3518
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3452
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3464
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3470
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3458
double lon[EX]
Longitude [deg].
Definition: mptrac.h:3392
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3437
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3440
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3434
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3416
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3476
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3485
int npl
Number of model levels.
Definition: mptrac.h:3389
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3428
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3506
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3446
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3491
double time
Time [s].
Definition: mptrac.h:3377
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3455
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3422
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3515
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3461
double lat[EY]
Latitude [deg].
Definition: mptrac.h:3395
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3509
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3527
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3398